xref: /third_party/node/src/json_utils.h (revision 1cb0ef41)
1#ifndef SRC_JSON_UTILS_H_
2#define SRC_JSON_UTILS_H_
3
4#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6#include <iomanip>
7#include <limits>
8#include <ostream>
9#include <string>
10#include <string_view>
11
12namespace node {
13
14constexpr bool NeedsJsonEscape(std::string_view str) {
15  for (const char c : str) {
16    if (c == '\\' || c == '"' || c < 0x20) return true;
17  }
18  return false;
19}
20
21std::string EscapeJsonChars(std::string_view str);
22std::string Reindent(const std::string& str, int indentation);
23
24// JSON compiler definitions.
25class JSONWriter {
26 public:
27  JSONWriter(std::ostream& out, bool compact)
28    : out_(out), compact_(compact) {}
29
30 private:
31  inline void indent() { indent_ += 2; }
32  inline void deindent() { indent_ -= 2; }
33  inline void advance() {
34    if (compact_) return;
35    for (int i = 0; i < indent_; i++) out_ << ' ';
36  }
37  inline void write_one_space() {
38    if (compact_) return;
39    out_ << ' ';
40  }
41  inline void write_new_line() {
42    if (compact_) return;
43    out_ << '\n';
44  }
45
46 public:
47  inline void json_start() {
48    if (state_ == kAfterValue) out_ << ',';
49    write_new_line();
50    advance();
51    out_ << '{';
52    indent();
53    state_ = kObjectStart;
54  }
55
56  inline void json_end() {
57    write_new_line();
58    deindent();
59    advance();
60    out_ << '}';
61    state_ = kAfterValue;
62  }
63  template <typename T>
64  inline void json_objectstart(T key) {
65    if (state_ == kAfterValue) out_ << ',';
66    write_new_line();
67    advance();
68    write_string(key);
69    out_ << ':';
70    write_one_space();
71    out_ << '{';
72    indent();
73    state_ = kObjectStart;
74  }
75
76  template <typename T>
77  inline void json_arraystart(T key) {
78    if (state_ == kAfterValue) out_ << ',';
79    write_new_line();
80    advance();
81    write_string(key);
82    out_ << ':';
83    write_one_space();
84    out_ << '[';
85    indent();
86    state_ = kObjectStart;
87  }
88  inline void json_objectend() {
89    write_new_line();
90    deindent();
91    advance();
92    out_ << '}';
93    if (indent_ == 0) {
94      // Top-level object is complete, so end the line.
95      out_ << '\n';
96    }
97    state_ = kAfterValue;
98  }
99
100  inline void json_arrayend() {
101    write_new_line();
102    deindent();
103    advance();
104    out_ << ']';
105    state_ = kAfterValue;
106  }
107  template <typename T, typename U>
108  inline void json_keyvalue(const T& key, const U& value) {
109    if (state_ == kAfterValue) out_ << ',';
110    write_new_line();
111    advance();
112    write_string(key);
113    out_ << ':';
114    write_one_space();
115    write_value(value);
116    state_ = kAfterValue;
117  }
118
119  template <typename U>
120  inline void json_element(const U& value) {
121    if (state_ == kAfterValue) out_ << ',';
122    write_new_line();
123    advance();
124    write_value(value);
125    state_ = kAfterValue;
126  }
127
128  struct Null {};  // Usable as a JSON value.
129
130  struct ForeignJSON {
131    std::string as_string;
132  };
133
134 private:
135  template <typename T,
136            typename test_for_number = typename std::
137                enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
138  inline void write_value(T number) {
139    if constexpr (std::is_same<T, bool>::value)
140      out_ << (number ? "true" : "false");
141    else
142      out_ << number;
143  }
144
145  inline void write_value(Null null) { out_ << "null"; }
146  inline void write_value(std::string_view str) { write_string(str); }
147
148  inline void write_value(const ForeignJSON& json) {
149    out_ << Reindent(json.as_string, indent_);
150  }
151
152  inline void write_string(std::string_view str) {
153    out_ << '"';
154    if (NeedsJsonEscape(str))  // only create temporary std::string if necessary
155      out_ << EscapeJsonChars(str);
156    else
157      out_ << str;
158    out_ << '"';
159  }
160
161  enum JSONState { kObjectStart, kAfterValue };
162  std::ostream& out_;
163  bool compact_;
164  int indent_ = 0;
165  int state_ = kObjectStart;
166};
167
168}  // namespace node
169
170#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
171
172#endif  // SRC_JSON_UTILS_H_
173