LCOV - code coverage report
Current view: top level - source/common/json - json_streamer.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 4 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <memory>
       4             : #include <stack>
       5             : #include <string>
       6             : 
       7             : #include "envoy/buffer/buffer.h"
       8             : 
       9             : #include "absl/strings/string_view.h"
      10             : #include "absl/types/variant.h"
      11             : 
      12             : namespace Envoy {
      13             : namespace Json {
      14             : 
      15             : /**
      16             :  * Provides an API for streaming JSON output, as an alternative to populating a
      17             :  * JSON structure with an image of what you want to serialize, or using a
      18             :  * protobuf with reflection. The advantage of this approach is that it does not
      19             :  * require building an intermediate data structure with redundant copies of all
      20             :  * strings, maps, and arrays.
      21             :  */
      22             : class Streamer {
      23             : public:
      24             :   using Value = absl::variant<absl::string_view, double, uint64_t, int64_t>;
      25             : 
      26             :   /**
      27             :    * @param response The buffer in which to stream output. Note: this buffer can
      28             :    *                 be flushed during population; it is not necessary to hold
      29             :    *                 the entire json structure in memory before streaming it to
      30             :    *                 the network.
      31             :    */
      32           0 :   explicit Streamer(Buffer::Instance& response) : response_(response) {}
      33             : 
      34             :   class Array;
      35             :   using ArrayPtr = std::unique_ptr<Array>;
      36             :   class Map;
      37             :   using MapPtr = std::unique_ptr<Map>;
      38             : 
      39             :   /**
      40             :    * Represents the current map or array. We keep track of what character is
      41             :    * needed to close it, and whether or not the first entry has been added.
      42             :    */
      43             :   class Level {
      44             :   public:
      45             :     Level(Streamer& streamer, absl::string_view opener, absl::string_view closer);
      46             :     virtual ~Level();
      47             : 
      48             :     /**
      49             :      * This must be called on the top level map or array. It's a programming
      50             :      * error to call this method on a map that's not the top level.
      51             :      * It's also a programming error to call this on map that isn't expecting
      52             :      * a value. You must call Map::addKey prior to calling this.
      53             :      *
      54             :      * @return a newly created subordinate map, which becomes the new top level until destroyed.
      55             :      */
      56             :     MapPtr addMap();
      57             : 
      58             :     /**
      59             :      * This must be called on the top level map or array. It's a programming
      60             :      * error to call this method on a map or array that's not the top level.
      61             :      * It's also a programming error to call this on map that isn't expecting
      62             :      * a value. You must call Map::addKey prior to calling this.
      63             :      *
      64             :      * @return a newly created subordinate array, which becomes the new top level until destroyed.
      65             :      */
      66             :     ArrayPtr addArray();
      67             : 
      68             :     /**
      69             :      * Adds a numeric value to the current array or map. It's a programming
      70             :      * error to call this method on a map or array that's not the top level.
      71             :      * It's also a programming error to call this on map that isn't expecting
      72             :      * a value. You must call Map::addKey prior to calling this.
      73             :      */
      74             :     void addNumber(double d);
      75             :     void addNumber(uint64_t u);
      76             :     void addNumber(int64_t i);
      77             : 
      78             :     /**
      79             :      * Adds a string constant value to the current array or map. The string
      80             :      * will be sanitized per JSON rules.
      81             :      *
      82             :      * It's a programming error to call this method on a map or array that's not
      83             :      * the top level. It's also a programming error to call this on map that
      84             :      * isn't expecting a value. You must call Map::addKey prior to calling this.
      85             :      */
      86             :     void addString(absl::string_view str);
      87             : 
      88             :   protected:
      89             :     /**
      90             :      * Initiates a new field, serializing a comma separator if this is not the
      91             :      * first one.
      92             :      */
      93             :     virtual void nextField();
      94             : 
      95             :     /**
      96             :      * Renders a string or a number in json format. Doubles that are NaN are
      97             :      * rendered as 'null'. Strings are json-sanitized if needed, and surrounded
      98             :      * by quotes.
      99             :      *
     100             :      * @param Value the value to render.
     101             :      */
     102             :     void addValue(const Value& value);
     103             : 
     104             :   private:
     105             :     friend Streamer;
     106             : 
     107             :     bool is_first_{true}; // Used to control whether a comma-separator is added for a new entry.
     108             :     Streamer& streamer_;
     109             :     absl::string_view closer_;
     110             :   };
     111             :   using LevelPtr = std::unique_ptr<Level>;
     112             : 
     113             :   /**
     114             :    * Represents a JSON map while it is being serialized. No data is buffered
     115             :    * in the structure; just enough state to be able emit delimiters properly.
     116             :    */
     117             :   class Map : public Level {
     118             :   public:
     119             :     using NameValue = std::pair<const absl::string_view, Value>;
     120             :     using Entries = absl::Span<const NameValue>;
     121             : 
     122           0 :     Map(Streamer& streamer) : Level(streamer, "{", "}") {}
     123             : 
     124             :     /**
     125             :      * Initiates a new map key. This must be followed by rendering a value,
     126             :      * sub-array, or sub-map. It is a programming error to delete a map that has
     127             :      * rendered a key without a matching value. It's also a programming error to
     128             :      * call this method on a map that's not the current top level.
     129             :      *
     130             :      * See also addEntries, which directly populates a list of name/value
     131             :      * pairs in a single call.
     132             :      */
     133             :     void addKey(absl::string_view key);
     134             : 
     135             :     /**
     136             :      * Populates a list of name/value pairs in a single call. This function
     137             :      * makes it easy to populate structures with scalar values. It's a
     138             :      * programming error to call this method on a map that's not the current top
     139             :      * level.
     140             :      */
     141             :     void addEntries(const Entries& entries);
     142             : 
     143             :   protected:
     144             :     void nextField() override;
     145             : 
     146             :   private:
     147             :     bool expecting_value_{false};
     148             :   };
     149             : 
     150             :   /**
     151             :    * Represents a JSON array while it is being serialized. No data is buffered
     152             :    * in the structure; just enough state to be able emit delimiters properly.
     153             :    */
     154             :   class Array : public Level {
     155             :   public:
     156           0 :     Array(Streamer& streamer) : Level(streamer, "[", "]") {}
     157             :     using Entries = absl::Span<const Value>;
     158             : 
     159             :     /**
     160             :      * Adds values to an array. The values may be numeric or strings; strings
     161             :      * will be escaped if needed. It's a programming error to call this method
     162             :      * on an array that's not the current top level.
     163             :      *
     164             :      * @param entries the array of numeric or string values.
     165             :      */
     166             :     void addEntries(const Entries& entries);
     167             :   };
     168             : 
     169             :   /**
     170             :    * Makes a root map for the streamer.
     171             :    *
     172             :    * You must create a root map or array before any of the JSON population
     173             :    * functions can be called, as those are only available on Map and Array
     174             :    * objects.
     175             :    */
     176             :   MapPtr makeRootMap();
     177             : 
     178             :   /**
     179             :    * Makes a root array for the streamer.
     180             :    *
     181             :    * You must create a root map or array before any of the JSON population
     182             :    * functions can be called, as those are only available on Map and Array
     183             :    * objects.
     184             :    */
     185             :   ArrayPtr makeRootArray();
     186             : 
     187             : private:
     188             :   friend Level;
     189             :   friend Map;
     190             :   friend Array;
     191             : 
     192             :   /**
     193             :    * Takes a raw string, sanitizes it using JSON syntax, surrounds it
     194             :    * with a prefix and suffix, and streams it out.
     195             :    */
     196             :   void addSanitized(absl::string_view prefix, absl::string_view token, absl::string_view suffix);
     197             : 
     198             :   /**
     199             :    * Serializes a number.
     200             :    */
     201             :   void addNumber(double d);
     202             :   void addNumber(uint64_t u);
     203             :   void addNumber(int64_t i);
     204             : 
     205             :   /**
     206             :    * Flushes out any pending fragments.
     207             :    */
     208             :   void flush();
     209             : 
     210             :   /**
     211             :    * Adds a constant string to the output stream. The string must outlive the
     212             :    * Streamer object, and is intended for literal strings such as punctuation.
     213             :    */
     214           0 :   void addConstantString(absl::string_view str) { response_.addFragments({str}); }
     215             : 
     216             : #ifndef NDEBUG
     217             :   /**
     218             :    * @return the top Level*. This is used for asserts.
     219             :    */
     220             :   Level* topLevel() const { return levels_.top(); }
     221             : 
     222             :   /**
     223             :    * Pushes a new level onto the stack.
     224             :    */
     225             :   void push(Level* level);
     226             : 
     227             :   /**
     228             :    * Pops a level off of a stack, asserting that it matches.
     229             :    */
     230             :   void pop(Level* level);
     231             : #endif
     232             : 
     233             :   Buffer::Instance& response_;
     234             :   std::string sanitize_buffer_;
     235             : 
     236             : #ifndef NDEBUG
     237             :   // Keeps a stack of Maps or Arrays (subclasses of Level) to facilitate
     238             :   // assertions that only the top-level map/array can be written.
     239             :   std::stack<Level*> levels_;
     240             : #endif
     241             : };
     242             : 
     243             : } // namespace Json
     244             : } // namespace Envoy

Generated by: LCOV version 1.15