logging: add new RateLimiter helper class
[folly.git] / folly / json.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/json.h>
18
19 #include <algorithm>
20 #include <functional>
21 #include <type_traits>
22
23 #include <boost/algorithm/string.hpp>
24 #include <boost/next_prior.hpp>
25 #include <folly/Bits.h>
26 #include <folly/Portability.h>
27
28 #include <folly/Conv.h>
29 #include <folly/Range.h>
30 #include <folly/String.h>
31 #include <folly/Unicode.h>
32 #include <folly/portability/Constexpr.h>
33
34 namespace folly {
35
36 //////////////////////////////////////////////////////////////////////
37
38 namespace json {
39 namespace {
40
41 struct Printer {
42   explicit Printer(
43       std::string& out,
44       unsigned* indentLevel,
45       serialization_opts const* opts)
46       : out_(out), indentLevel_(indentLevel), opts_(*opts) {}
47
48   void operator()(dynamic const& v) const {
49     switch (v.type()) {
50     case dynamic::DOUBLE:
51       if (!opts_.allow_nan_inf &&
52           (std::isnan(v.asDouble()) || std::isinf(v.asDouble()))) {
53         throw std::runtime_error("folly::toJson: JSON object value was a "
54           "NaN or INF");
55       }
56       toAppend(v.asDouble(), &out_, opts_.double_mode, opts_.double_num_digits);
57       break;
58     case dynamic::INT64: {
59       auto intval = v.asInt();
60       if (opts_.javascript_safe) {
61         // Use folly::to to check that this integer can be represented
62         // as a double without loss of precision.
63         intval = int64_t(to<double>(intval));
64       }
65       toAppend(intval, &out_);
66       break;
67     }
68     case dynamic::BOOL:
69       out_ += v.asBool() ? "true" : "false";
70       break;
71     case dynamic::NULLT:
72       out_ += "null";
73       break;
74     case dynamic::STRING:
75       escapeString(v.asString(), out_, opts_);
76       break;
77     case dynamic::OBJECT:
78       printObject(v);
79       break;
80     case dynamic::ARRAY:
81       printArray(v);
82       break;
83     default:
84       CHECK(0) << "Bad type " << v.type();
85     }
86   }
87
88 private:
89   void printKV(const std::pair<const dynamic, dynamic>& p) const {
90     if (!opts_.allow_non_string_keys && !p.first.isString()) {
91       throw std::runtime_error("folly::toJson: JSON object key was not a "
92         "string");
93     }
94     (*this)(p.first);
95     mapColon();
96     (*this)(p.second);
97   }
98
99   template <typename Iterator>
100   void printKVPairs(Iterator begin, Iterator end) const {
101     printKV(*begin);
102     for (++begin; begin != end; ++begin) {
103       out_ += ',';
104       newline();
105       printKV(*begin);
106     }
107   }
108
109   void printObject(dynamic const& o) const {
110     if (o.empty()) {
111       out_ += "{}";
112       return;
113     }
114
115     out_ += '{';
116     indent();
117     newline();
118     if (opts_.sort_keys || opts_.sort_keys_by) {
119       using ref = std::reference_wrapper<decltype(o.items())::value_type const>;
120       std::vector<ref> refs(o.items().begin(), o.items().end());
121
122       using SortByRef = FunctionRef<bool(dynamic const&, dynamic const&)>;
123       auto const& sort_keys_by = opts_.sort_keys_by
124           ? SortByRef(opts_.sort_keys_by)
125           : SortByRef(std::less<dynamic>());
126       std::sort(refs.begin(), refs.end(), [&](ref a, ref b) {
127         // Only compare keys.  No ordering among identical keys.
128         return sort_keys_by(a.get().first, b.get().first);
129       });
130       printKVPairs(refs.cbegin(), refs.cend());
131     } else {
132       printKVPairs(o.items().begin(), o.items().end());
133     }
134     outdent();
135     newline();
136     out_ += '}';
137   }
138
139   void printArray(dynamic const& a) const {
140     if (a.empty()) {
141       out_ += "[]";
142       return;
143     }
144
145     out_ += '[';
146     indent();
147     newline();
148     (*this)(a[0]);
149     for (auto& val : range(boost::next(a.begin()), a.end())) {
150       out_ += ',';
151       newline();
152       (*this)(val);
153     }
154     outdent();
155     newline();
156     out_ += ']';
157   }
158
159 private:
160   void outdent() const {
161     if (indentLevel_) {
162       --*indentLevel_;
163     }
164   }
165
166   void indent() const {
167     if (indentLevel_) {
168       ++*indentLevel_;
169     }
170   }
171
172   void newline() const {
173     if (indentLevel_) {
174       out_ += to<std::string>('\n', std::string(*indentLevel_ * 2, ' '));
175     }
176   }
177
178   void mapColon() const {
179     out_ += indentLevel_ ? " : " : ":";
180   }
181
182 private:
183  std::string& out_;
184  unsigned* const indentLevel_;
185  serialization_opts const& opts_;
186 };
187
188 //////////////////////////////////////////////////////////////////////
189
190 struct ParseError : std::runtime_error {
191   explicit ParseError(
192       unsigned int line,
193       std::string const& context,
194       std::string const& expected)
195       : std::runtime_error(to<std::string>(
196             "json parse error on line ",
197             line,
198             !context.empty() ? to<std::string>(" near `", context, '\'') : "",
199             ": ",
200             expected)) {}
201 };
202
203 // Wraps our input buffer with some helper functions.
204 struct Input {
205   explicit Input(StringPiece range, json::serialization_opts const* opts)
206       : range_(range)
207       , opts_(*opts)
208       , lineNum_(0)
209   {
210     storeCurrent();
211   }
212
213   Input(Input const&) = delete;
214   Input& operator=(Input const&) = delete;
215
216   char const* begin() const { return range_.begin(); }
217
218   // Parse ahead for as long as the supplied predicate is satisfied,
219   // returning a range of what was skipped.
220   template<class Predicate>
221   StringPiece skipWhile(const Predicate& p) {
222     std::size_t skipped = 0;
223     for (; skipped < range_.size(); ++skipped) {
224       if (!p(range_[skipped])) {
225         break;
226       }
227       if (range_[skipped] == '\n') {
228         ++lineNum_;
229       }
230     }
231     auto ret = range_.subpiece(0, skipped);
232     range_.advance(skipped);
233     storeCurrent();
234     return ret;
235   }
236
237   StringPiece skipDigits() {
238     return skipWhile([] (char c) { return c >= '0' && c <= '9'; });
239   }
240
241   StringPiece skipMinusAndDigits() {
242     bool firstChar = true;
243     return skipWhile([&firstChar] (char c) {
244         bool result = (c >= '0' && c <= '9') || (firstChar && c == '-');
245         firstChar = false;
246         return result;
247       });
248   }
249
250   void skipWhitespace() {
251     range_ = folly::skipWhitespace(range_);
252     storeCurrent();
253   }
254
255   void expect(char c) {
256     if (**this != c) {
257       throw ParseError(lineNum_, context(),
258         to<std::string>("expected '", c, '\''));
259     }
260     ++*this;
261   }
262
263   std::size_t size() const {
264     return range_.size();
265   }
266
267   int operator*() const {
268     return current_;
269   }
270
271   void operator++() {
272     range_.pop_front();
273     storeCurrent();
274   }
275
276   template<class T>
277   T extract() {
278     try {
279       return to<T>(&range_);
280     } catch (std::exception const& e) {
281       error(e.what());
282     }
283   }
284
285   bool consume(StringPiece str) {
286     if (boost::starts_with(range_, str)) {
287       range_.advance(str.size());
288       storeCurrent();
289       return true;
290     }
291     return false;
292   }
293
294   std::string context() const {
295     return range_.subpiece(0, 16 /* arbitrary */).toString();
296   }
297
298   dynamic error(char const* what) const {
299     throw ParseError(lineNum_, context(), what);
300   }
301
302   json::serialization_opts const& getOpts() {
303     return opts_;
304   }
305
306   void incrementRecursionLevel() {
307     if (currentRecursionLevel_ > opts_.recursion_limit) {
308       error("recursion limit exceeded");
309     }
310     currentRecursionLevel_++;
311   }
312
313   void decrementRecursionLevel() {
314     currentRecursionLevel_--;
315   }
316
317  private:
318   void storeCurrent() {
319     current_ = range_.empty() ? EOF : range_.front();
320   }
321
322 private:
323   StringPiece range_;
324   json::serialization_opts const& opts_;
325   unsigned lineNum_;
326   int current_;
327   unsigned int currentRecursionLevel_{0};
328 };
329
330 class RecursionGuard {
331  public:
332   explicit RecursionGuard(Input& in) : in_(in) {
333     in_.incrementRecursionLevel();
334   }
335
336   ~RecursionGuard() {
337     in_.decrementRecursionLevel();
338   }
339
340  private:
341   Input& in_;
342 };
343
344 dynamic parseValue(Input& in);
345 std::string parseString(Input& in);
346 dynamic parseNumber(Input& in);
347
348 dynamic parseObject(Input& in) {
349   DCHECK_EQ(*in, '{');
350   ++in;
351
352   dynamic ret = dynamic::object;
353
354   in.skipWhitespace();
355   if (*in == '}') {
356     ++in;
357     return ret;
358   }
359
360   for (;;) {
361     if (in.getOpts().allow_trailing_comma && *in == '}') {
362       break;
363     }
364     if (*in == '\"') { // string
365       auto key = parseString(in);
366       in.skipWhitespace();
367       in.expect(':');
368       in.skipWhitespace();
369       ret.insert(std::move(key), parseValue(in));
370     } else if (!in.getOpts().allow_non_string_keys) {
371       in.error("expected string for object key name");
372     } else {
373       auto key = parseValue(in);
374       in.skipWhitespace();
375       in.expect(':');
376       in.skipWhitespace();
377       ret.insert(std::move(key), parseValue(in));
378     }
379
380     in.skipWhitespace();
381     if (*in != ',') {
382       break;
383     }
384     ++in;
385     in.skipWhitespace();
386   }
387   in.expect('}');
388
389   return ret;
390 }
391
392 dynamic parseArray(Input& in) {
393   DCHECK_EQ(*in, '[');
394   ++in;
395
396   dynamic ret = dynamic::array;
397
398   in.skipWhitespace();
399   if (*in == ']') {
400     ++in;
401     return ret;
402   }
403
404   for (;;) {
405     if (in.getOpts().allow_trailing_comma && *in == ']') {
406       break;
407     }
408     ret.push_back(parseValue(in));
409     in.skipWhitespace();
410     if (*in != ',') {
411       break;
412     }
413     ++in;
414     in.skipWhitespace();
415   }
416   in.expect(']');
417
418   return ret;
419 }
420
421 dynamic parseNumber(Input& in) {
422   bool const negative = (*in == '-');
423   if (negative && in.consume("-Infinity")) {
424     if (in.getOpts().parse_numbers_as_strings) {
425       return "-Infinity";
426     } else {
427       return -std::numeric_limits<double>::infinity();
428     }
429   }
430
431   auto integral = in.skipMinusAndDigits();
432   if (negative && integral.size() < 2) {
433     in.error("expected digits after `-'");
434   }
435
436   auto const wasE = *in == 'e' || *in == 'E';
437
438   constexpr const char* maxInt = "9223372036854775807";
439   constexpr const char* minInt = "-9223372036854775808";
440   constexpr auto maxIntLen = constexpr_strlen(maxInt);
441   constexpr auto minIntLen = constexpr_strlen(minInt);
442
443   if (*in != '.' && !wasE && in.getOpts().parse_numbers_as_strings) {
444     return integral;
445   }
446
447   if (*in != '.' && !wasE) {
448     if (LIKELY(!in.getOpts().double_fallback || integral.size() < maxIntLen) ||
449         (!negative && integral.size() == maxIntLen && integral <= maxInt) ||
450         (negative && integral.size() == minIntLen && integral <= minInt)) {
451       auto val = to<int64_t>(integral);
452       in.skipWhitespace();
453       return val;
454     } else {
455       auto val = to<double>(integral);
456       in.skipWhitespace();
457       return val;
458     }
459   }
460
461   auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
462   if (*in == 'e' || *in == 'E') {
463     ++in;
464     if (*in == '+' || *in == '-') {
465       ++in;
466     }
467     auto expPart = in.skipDigits();
468     end = expPart.end();
469   }
470   auto fullNum = range(integral.begin(), end);
471   if (in.getOpts().parse_numbers_as_strings) {
472     return fullNum;
473   }
474   auto val = to<double>(fullNum);
475   return val;
476 }
477
478 std::string decodeUnicodeEscape(Input& in) {
479   auto hexVal = [&] (int c) -> uint16_t {
480     return uint16_t(
481            c >= '0' && c <= '9' ? c - '0' :
482            c >= 'a' && c <= 'f' ? c - 'a' + 10 :
483            c >= 'A' && c <= 'F' ? c - 'A' + 10 :
484            (in.error("invalid hex digit"), 0));
485   };
486
487   auto readHex = [&]() -> uint16_t {
488     if (in.size() < 4) {
489       in.error("expected 4 hex digits");
490     }
491
492     uint16_t ret = uint16_t(hexVal(*in) * 4096);
493     ++in;
494     ret += hexVal(*in) * 256;
495     ++in;
496     ret += hexVal(*in) * 16;
497     ++in;
498     ret += hexVal(*in);
499     ++in;
500     return ret;
501   };
502
503   /*
504    * If the value encoded is in the surrogate pair range, we need to
505    * make sure there is another escape that we can use also.
506    */
507   uint32_t codePoint = readHex();
508   if (codePoint >= 0xd800 && codePoint <= 0xdbff) {
509     if (!in.consume("\\u")) {
510       in.error("expected another unicode escape for second half of "
511         "surrogate pair");
512     }
513     uint16_t second = readHex();
514     if (second >= 0xdc00 && second <= 0xdfff) {
515       codePoint = 0x10000 + ((codePoint & 0x3ff) << 10) +
516                   (second & 0x3ff);
517     } else {
518       in.error("second character in surrogate pair is invalid");
519     }
520   } else if (codePoint >= 0xdc00 && codePoint <= 0xdfff) {
521     in.error("invalid unicode code point (in range [0xdc00,0xdfff])");
522   }
523
524   return codePointToUtf8(codePoint);
525 }
526
527 std::string parseString(Input& in) {
528   DCHECK_EQ(*in, '\"');
529   ++in;
530
531   std::string ret;
532   for (;;) {
533     auto range = in.skipWhile(
534       [] (char c) { return c != '\"' && c != '\\'; }
535     );
536     ret.append(range.begin(), range.end());
537
538     if (*in == '\"') {
539       ++in;
540       break;
541     }
542     if (*in == '\\') {
543       ++in;
544       switch (*in) {
545       case '\"':    ret.push_back('\"'); ++in; break;
546       case '\\':    ret.push_back('\\'); ++in; break;
547       case '/':     ret.push_back('/');  ++in; break;
548       case 'b':     ret.push_back('\b'); ++in; break;
549       case 'f':     ret.push_back('\f'); ++in; break;
550       case 'n':     ret.push_back('\n'); ++in; break;
551       case 'r':     ret.push_back('\r'); ++in; break;
552       case 't':     ret.push_back('\t'); ++in; break;
553       case 'u':     ++in; ret += decodeUnicodeEscape(in); break;
554       default:
555         in.error(to<std::string>("unknown escape ", *in, " in string").c_str());
556       }
557       continue;
558     }
559     if (*in == EOF) {
560       in.error("unterminated string");
561     }
562     if (!*in) {
563       /*
564        * Apparently we're actually supposed to ban all control
565        * characters from strings.  This seems unnecessarily
566        * restrictive, so we're only banning zero bytes.  (Since the
567        * string is presumed to be UTF-8 encoded it's fine to just
568        * check this way.)
569        */
570       in.error("null byte in string");
571     }
572
573     ret.push_back(char(*in));
574     ++in;
575   }
576
577   return ret;
578 }
579
580 dynamic parseValue(Input& in) {
581   RecursionGuard guard(in);
582
583   in.skipWhitespace();
584   return *in == '[' ? parseArray(in) :
585          *in == '{' ? parseObject(in) :
586          *in == '\"' ? parseString(in) :
587          (*in == '-' || (*in >= '0' && *in <= '9')) ? parseNumber(in) :
588          in.consume("true") ? true :
589          in.consume("false") ? false :
590          in.consume("null") ? nullptr :
591          in.consume("Infinity") ?
592           (in.getOpts().parse_numbers_as_strings ? (dynamic)"Infinity" :
593             (dynamic)std::numeric_limits<double>::infinity()) :
594          in.consume("NaN") ?
595            (in.getOpts().parse_numbers_as_strings ? (dynamic)"NaN" :
596              (dynamic)std::numeric_limits<double>::quiet_NaN()) :
597          in.error("expected json value");
598 }
599
600 }
601
602 //////////////////////////////////////////////////////////////////////
603
604 std::string serialize(dynamic const& dyn, serialization_opts const& opts) {
605   std::string ret;
606   unsigned indentLevel = 0;
607   Printer p(ret, opts.pretty_formatting ? &indentLevel : nullptr, &opts);
608   p(dyn);
609   return ret;
610 }
611
612 // Fast path to determine the longest prefix that can be left
613 // unescaped in a string of sizeof(T) bytes packed in an integer of
614 // type T.
615 template <class T>
616 size_t firstEscapableInWord(T s) {
617   static_assert(std::is_unsigned<T>::value, "Unsigned integer required");
618   static constexpr T kOnes = ~T() / 255; // 0x...0101
619   static constexpr T kMsbs = kOnes * 0x80; // 0x...8080
620
621   // Sets the MSB of bytes < b. Precondition: b < 128.
622   auto isLess = [](T w, uint8_t b) {
623     // A byte is < b iff subtracting b underflows, so we check that
624     // the MSB wasn't set before and it's set after the subtraction.
625     return (w - kOnes * b) & ~w & kMsbs;
626   };
627
628   auto isChar = [&](uint8_t c) {
629     // A byte is == c iff it is 0 if xored with c.
630     return isLess(s ^ (kOnes * c), 1);
631   };
632
633   // The following masks have the MSB set for each byte of the word
634   // that satisfies the corresponding condition.
635   auto isHigh = s & kMsbs; // >= 128
636   auto isLow = isLess(s, 0x20); // <= 0x1f
637   auto needsEscape = isHigh | isLow | isChar('\\') | isChar('"');
638
639   if (!needsEscape) {
640     return sizeof(T);
641   }
642
643   if (folly::kIsLittleEndian) {
644     return folly::findFirstSet(needsEscape) / 8 - 1;
645   } else {
646     return sizeof(T) - folly::findLastSet(needsEscape) / 8;
647   }
648 }
649
650 // Escape a string so that it is legal to print it in JSON text.
651 void escapeString(
652     StringPiece input,
653     std::string& out,
654     const serialization_opts& opts) {
655   auto hexDigit = [] (uint8_t c) -> char {
656     return c < 10 ? c + '0' : c - 10 + 'a';
657   };
658
659   out.push_back('\"');
660
661   auto* p = reinterpret_cast<const unsigned char*>(input.begin());
662   auto* q = reinterpret_cast<const unsigned char*>(input.begin());
663   auto* e = reinterpret_cast<const unsigned char*>(input.end());
664
665   while (p < e) {
666     // Find the longest prefix that does not need escaping, and copy
667     // it literally into the output string.
668     auto firstEsc = p;
669     while (firstEsc < e) {
670       auto avail = e - firstEsc;
671       uint64_t word = 0;
672       if (avail >= 8) {
673         word = folly::loadUnaligned<uint64_t>(firstEsc);
674       } else {
675         memcpy(static_cast<void*>(&word), firstEsc, avail);
676       }
677       auto prefix = firstEscapableInWord(word);
678       DCHECK_LE(prefix, avail);
679       firstEsc += prefix;
680       if (prefix < 8) {
681         break;
682       }
683     }
684     if (firstEsc > p) {
685       out.append(reinterpret_cast<const char*>(p), firstEsc - p);
686       p = firstEsc;
687       // We can't be in the middle of a multibyte sequence, so we can reset q.
688       q = p;
689       if (p == e) {
690         break;
691       }
692     }
693
694     // Handle the next byte that may need escaping.
695
696     // Since non-ascii encoding inherently does utf8 validation
697     // we explicitly validate utf8 only if non-ascii encoding is disabled.
698     if ((opts.validate_utf8 || opts.skip_invalid_utf8)
699         && !opts.encode_non_ascii) {
700       // To achieve better spatial and temporal coherence
701       // we do utf8 validation progressively along with the
702       // string-escaping instead of two separate passes.
703
704       // As the encoding progresses, q will stay at or ahead of p.
705       CHECK_GE(q, p);
706
707       // As p catches up with q, move q forward.
708       if (q == p) {
709         // calling utf8_decode has the side effect of
710         // checking that utf8 encodings are valid
711         char32_t v = utf8ToCodePoint(q, e, opts.skip_invalid_utf8);
712         if (opts.skip_invalid_utf8 && v == U'\ufffd') {
713           out.append(u8"\ufffd");
714           p = q;
715           continue;
716         }
717       }
718     }
719     if (opts.encode_non_ascii && (*p & 0x80)) {
720       // note that this if condition captures utf8 chars
721       // with value > 127, so size > 1 byte
722       char32_t v = utf8ToCodePoint(p, e, opts.skip_invalid_utf8);
723       char buf[] = "\\u\0\0\0\0";
724       buf[2] = hexDigit(uint8_t(v >> 12));
725       buf[3] = hexDigit((v >> 8) & 0x0f);
726       buf[4] = hexDigit((v >> 4) & 0x0f);
727       buf[5] = hexDigit(v & 0x0f);
728       out.append(buf, 6);
729     } else if (*p == '\\' || *p == '\"') {
730       char buf[] = "\\\0";
731       buf[1] = char(*p++);
732       out.append(buf, 2);
733     } else if (*p <= 0x1f) {
734       switch (*p) {
735         case '\b': out.append("\\b"); p++; break;
736         case '\f': out.append("\\f"); p++; break;
737         case '\n': out.append("\\n"); p++; break;
738         case '\r': out.append("\\r"); p++; break;
739         case '\t': out.append("\\t"); p++; break;
740         default:
741           // Note that this if condition captures non readable chars
742           // with value < 32, so size = 1 byte (e.g control chars).
743           char buf[] = "\\u00\0\0";
744           buf[4] = hexDigit(uint8_t((*p & 0xf0) >> 4));
745           buf[5] = hexDigit(uint8_t(*p & 0xf));
746           out.append(buf, 6);
747           p++;
748       }
749     } else {
750       out.push_back(char(*p++));
751     }
752   }
753
754   out.push_back('\"');
755 }
756
757 std::string stripComments(StringPiece jsonC) {
758   std::string result;
759   enum class State {
760     None,
761     InString,
762     InlineComment,
763     LineComment
764   } state = State::None;
765
766   for (size_t i = 0; i < jsonC.size(); ++i) {
767     auto s = jsonC.subpiece(i);
768     switch (state) {
769       case State::None:
770         if (s.startsWith("/*")) {
771           state = State::InlineComment;
772           ++i;
773           continue;
774         } else if (s.startsWith("//")) {
775           state = State::LineComment;
776           ++i;
777           continue;
778         } else if (s[0] == '\"') {
779           state = State::InString;
780         }
781         result.push_back(s[0]);
782         break;
783       case State::InString:
784         if (s[0] == '\\') {
785           if (UNLIKELY(s.size() == 1)) {
786             throw std::logic_error("Invalid JSONC: string is not terminated");
787           }
788           result.push_back(s[0]);
789           result.push_back(s[1]);
790           ++i;
791           continue;
792         } else if (s[0] == '\"') {
793           state = State::None;
794         }
795         result.push_back(s[0]);
796         break;
797       case State::InlineComment:
798         if (s.startsWith("*/")) {
799           state = State::None;
800           ++i;
801         }
802         break;
803       case State::LineComment:
804         if (s[0] == '\n') {
805           // skip the line break. It doesn't matter.
806           state = State::None;
807         }
808         break;
809       default:
810         throw std::logic_error("Unknown comment state");
811     }
812   }
813   return result;
814 }
815
816 }
817
818 //////////////////////////////////////////////////////////////////////
819
820 dynamic parseJson(StringPiece range) {
821   return parseJson(range, json::serialization_opts());
822 }
823
824 dynamic parseJson(
825     StringPiece range,
826     json::serialization_opts const& opts) {
827
828   json::Input in(range, &opts);
829
830   auto ret = parseValue(in);
831   in.skipWhitespace();
832   if (in.size() && *in != '\0') {
833     in.error("parsing didn't consume all input");
834   }
835   return ret;
836 }
837
838 std::string toJson(dynamic const& dyn) {
839   return json::serialize(dyn, json::serialization_opts());
840 }
841
842 std::string toPrettyJson(dynamic const& dyn) {
843   json::serialization_opts opts;
844   opts.pretty_formatting = true;
845   return json::serialize(dyn, opts);
846 }
847
848 //////////////////////////////////////////////////////////////////////
849 // dynamic::print_as_pseudo_json() is implemented here for header
850 // ordering reasons (most of the dynamic implementation is in
851 // dynamic-inl.h, which we don't want to include json.h).
852
853 void dynamic::print_as_pseudo_json(std::ostream& out) const {
854   json::serialization_opts opts;
855   opts.allow_non_string_keys = true;
856   opts.allow_nan_inf = true;
857   out << json::serialize(*this, opts);
858 }
859
860 void PrintTo(const dynamic& dyn, std::ostream* os) {
861   json::serialization_opts opts;
862   opts.allow_nan_inf = true;
863   opts.allow_non_string_keys = true;
864   opts.pretty_formatting = true;
865   opts.sort_keys = true;
866   *os << json::serialize(dyn, opts);
867 }
868
869 //////////////////////////////////////////////////////////////////////
870
871 }