JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
all.hpp
Go to the documentation of this file.
1/// \file jsonv/all.hpp
2/// A header which includes all other JSON Voorhees headers.
3///
4/// Copyright (c) 2012-2020 by Travis Gockel. All rights reserved.
5///
6/// This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
7/// as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
8/// version.
9///
10/// \author Travis Gockel (travis@gockelhut.com)
11#pragma once
12
13namespace jsonv
14{
15
16/// \mainpage Overview
17///
18/// JSON Voorhees is a JSON library written for the C++ programmer who wants to be productive in
19/// this modern world. This one targets C++23 for developer-friendliness, a reasonably fast parser,
20/// and no dependencies beyond a compliant compiler and standard library. It is hosted on
21/// <a href="https://github.com/tgockel/json-voorhees">GitHub</a> and sports an Apache License, so
22/// use it anywhere you need.
23///
24/// Features include (but are not necessarily limited to):
25///
26/// - Simple
27/// - A `value` should not feel terribly different from a C++ Standard Library container
28/// - Write valid JSON with `operator<<`
29/// - Simple JSON parsing with `parse`
30/// - Read JSON Lines and other runs of concatenated documents with `documents`
31/// - Reasonable error messages when parsing fails
32/// - Full support for Unicode-filled JSON (encoded in UTF-8 in C++)
33/// - Efficient
34/// - Minimal overhead to store values (a `value` is 16 bytes on a 64-bit platform)
35/// - No-throw move semantics wherever possible
36/// - Serialization/Deserialization
37/// - Deserialize a C++ type straight from JSON text or a stream, or from a `value`, using `deserialize<T>`
38/// - Serialize a C++ type straight to JSON text using `serialize`, or into a `value` using `to_json`
39/// - Safe
40/// - In the best case, illegal code should fail to compile
41/// - An illegal action should throw an exception
42/// - The query API is `[[nodiscard]]`, so dropping the answer to a question you asked is a warning
43/// - Almost all utility functions have a [strong exception guarantee](http://www.gotw.ca/gotw/082.htm)
44/// - Stable
45/// - Worry less about upgrading -- the API and ABI will not change out from under you
46/// - Documented
47/// - Consumable by human beings
48/// - Answers questions you might actually ask
49///
50/// \dotfile doc/conversions.dot
51///
52/// JSON Voorhees is designed with ease-of-use in mind. So let's look at some code!
53///
54/// \section demo_value The jsonv::value
55///
56/// The central class of JSON Voorhees is the \c jsonv::value, which represents a JSON AST. Putting
57/// values of different types is easy.
58///
59/// \code
60/// #include <jsonv/value.hpp>
61/// #include <iostream>
62///
63/// int main()
64/// {
65/// jsonv::value x = jsonv::null;
66/// std::cout << x << std::endl;
67/// x = 5.9;
68/// std::cout << x << std::endl;
69/// x = -100;
70/// std::cout << x << std::endl;
71/// x = "something else";
72/// std::cout << x << std::endl;
73/// x = jsonv::array({ "arrays", "of", "the", 7, "different", "types?", true });
74/// std::cout << x << std::endl;
75/// x = jsonv::object({
76/// { "objects", jsonv::array({
77/// "Are fun, too.",
78/// "Do what you want."
79/// })
80/// },
81/// { "compose like", "standard library maps" },
82/// });
83/// std::cout << x << std::endl;
84/// }
85/// \endcode
86///
87/// Output:
88///
89/// \code
90/// null
91/// 5.9
92/// -100
93/// "something else"
94/// ["arrays","of","the",7,"different","types?",true]
95/// {"compose like":"standard library maps","objects":["Are fun, too.","Do what you want."]}
96/// \endcode
97///
98/// If that isn't convenient enough for you, there is a user-defined literal \c _json in the
99/// \c jsonv namespace you can use:
100///
101/// \code
102/// // You can use this hideous syntax if you do not want to bring in the whole jsonv namespace:
103/// using jsonv::operator""_json;
104///
105/// jsonv::value x = R"({
106/// "objects": [ "Are fun, too.",
107/// "Do what you want."
108/// ],
109/// "compose like": "You are just writing JSON",
110/// "which I guess": ["is", "also", "neat"]
111/// })"_json;
112/// \endcode
113///
114/// JSON is dynamic, which makes value access a bit more of a hassle, but JSON Voorhees aims to make
115/// it not too horrifying for you. A \c jsonv::value has a number of accessor methods named things
116/// like \c as_integer and \c as_string which let you access the value as if it was that type. But
117/// what if it isn't that type? In that case, the function will throw a \c jsonv::kind_error with a
118/// bit more information as to what rule you violated.
119///
120/// \code
121/// #include <jsonv/value.hpp>
122/// #include <iostream>
123///
124/// int main()
125/// {
126/// jsonv::value x = jsonv::null;
127/// try
128/// {
129/// (void) x.as_string();
130/// }
131/// catch (const jsonv::kind_error& err)
132/// {
133/// std::cout << err.what() << std::endl;
134/// }
135///
136/// x = "now make it a string";
137/// std::cout << x.as_string().size() << std::endl;
138/// std::cout << x.as_string() << "\tis not the same as\t" << x << std::endl;
139/// }
140/// \endcode
141///
142/// Output:
143///
144/// \code
145/// Unexpected type: expected string but found null.
146/// 20
147/// now make it a string is not the same as "now make it a string"
148/// \endcode
149///
150/// You can also deal with container types in a similar manner that you would deal with the
151/// equivalent STL container type, with some minor caveats. Because the \c value_type of a JSON
152/// object and JSON array are different, they have different iterator types in JSON Voorhees. They
153/// are named \c object_iterator and \c array_iterator. The access methods for these iterators are
154/// \c begin_object / \c end_object and \c begin_array / \c end_array, respectively. The object
155/// interface behaves like a \c std::flat_map<std::string,jsonv::value>: members are kept sorted by
156/// key, an iterator dereferences to a proxy holding references to the key and the value, and
157/// inserting or erasing invalidates iterators. The array interface behaves just like a
158/// \c std::deque<jsonv::value> would.
159///
160/// \code
161/// #include <jsonv/value.hpp>
162/// #include <iostream>
163///
164/// int main()
165/// {
166/// jsonv::value x = jsonv::object({ { "one", 1 }});
167/// auto iter = x.find("one");
168/// if (iter != x.end_object())
169/// std::cout << iter->first << ": " << iter->second << std::endl;
170/// else
171/// std::cout << "Nothing..." << std::endl;
172///
173/// iter = x.find("two");
174/// if (iter != x.end_object())
175/// std::cout << iter->first << ": " << iter->second << std::endl;
176/// else
177/// std::cout << "Nothing..." << std::endl;
178///
179/// x["two"] = 2;
180/// iter = x.find("two");
181/// if (iter != x.end_object())
182/// std::cout << iter->first << ": " << iter->second << std::endl;
183/// else
184/// std::cout << "Nothing..." << std::endl;
185///
186/// x["two"] = jsonv::array({ "one", "+", x.at("one") });
187/// iter = x.find("two");
188/// if (iter != x.end_object())
189/// std::cout << iter->first << ": " << iter->second << std::endl;
190/// else
191/// std::cout << "Nothing..." << std::endl;
192///
193/// x.erase("one");
194/// iter = x.find("one");
195/// if (iter != x.end_object())
196/// std::cout << iter->first << ": " << iter->second << std::endl;
197/// else
198/// std::cout << "Nothing..." << std::endl;
199/// }
200/// \endcode
201///
202/// Output:
203///
204/// \code
205/// one: 1
206/// Nothing...
207/// two: 2
208/// two: ["one","+",1]
209/// Nothing...
210/// \endcode
211///
212/// The iterator types \e work. This means you are free to use all of the C++ things just like you
213/// would a regular container. To use a ranged-based for, simply call \c as_array or \c as_object.
214/// Everything from \c <algorithm> and \c <iterator> or any other library works great with JSON
215/// Voorhees.
216///
217/// \code
218/// #include <jsonv/value.hpp>
219/// #include <algorithm>
220/// #include <iostream>
221///
222/// int main()
223/// {
224/// jsonv::value arr = jsonv::array({ "taco", "cat", 3, -2, jsonv::null, "beef", 4.8, 5 });
225/// std::cout << "Initial: ";
226/// for (const auto& val : arr.as_array())
227/// std::cout << val << '\t';
228/// std::cout << std::endl;
229///
230/// std::sort(arr.begin_array(), arr.end_array());
231/// std::cout << "Sorted: ";
232/// for (const auto& val : arr.as_array())
233/// std::cout << val << '\t';
234/// std::cout << std::endl;
235/// }
236/// \endcode
237///
238/// Output:
239///
240/// \code
241/// Initial: "taco" "cat" 3 -2 null "beef" 4.8 5
242/// Sorted: null -2 3 4.8 5 "beef" "cat" "taco"
243/// \endcode
244///
245/// \section demo_parsing Encoding and decoding
246///
247/// Usually, the reason people are using JSON is as a data exchange format, either for communicating
248/// with other services or storing things in a file or a database. To do this, you need to \e encode
249/// your \c jsonv::value into an \c std::string and \e parse it back. JSON Voorhees makes this easy
250/// for you.
251///
252/// \code
253/// #include <jsonv/value.hpp>
254/// #include <jsonv/encode.hpp>
255/// #include <jsonv/parse.hpp>
256///
257/// #include <iostream>
258/// #include <fstream>
259/// #include <limits>
260///
261/// int main()
262/// {
263/// jsonv::value obj = jsonv::object();
264/// obj["taco"] = "cat";
265/// obj["array"] = jsonv::array({ 1, 2, 3, 4, 5 });
266/// obj["infinity"] = std::numeric_limits<double>::infinity();
267///
268/// {
269/// std::cout << "Saving \"file.json\"... " << obj << std::endl;
270/// std::ofstream file("file.json");
271/// file << obj;
272/// }
273///
274/// jsonv::value loaded;
275/// {
276/// std::cout << "Loading \"file.json\"...";
277/// std::ifstream file("file.json");
278/// loaded = jsonv::parse(file);
279/// }
280/// std::cout << loaded << std::endl;
281///
282/// return obj == loaded ? 0 : 1;
283/// }
284/// \endcode
285///
286/// Output:
287///
288/// \code
289/// Saving "file.json"... {"array":[1,2,3,4,5],"infinity":null,"taco":"cat"}
290/// Loading "file.json"...{"array":[1,2,3,4,5],"infinity":null,"taco":"cat"}
291/// \endcode
292///
293/// If you are paying close attention, you might have noticed that the value for the \c "infinity"
294/// looks a little bit more \c null than \c infinity. This is because, much like mathematicians
295/// before Anaximander, JSON has no concept of infinity, so it is actually \e illegal to serialize a
296/// token like \c infinity anywhere.
297///
298/// By default, when an encoder encounters an unrepresentable value in the JSON it is trying to
299/// encode, it outputs \c null instead. If you wish to change this behavior, implement your own
300/// \c jsonv::encoder (or derive from \c jsonv::ostream_encoder).
301///
302/// If you ran the example program, you might have noticed that the return code was 1, meaning the
303/// value you put into the file and what you got from it were not equal. This is because all the
304/// type and value information is still kept around in the in-memory \c obj. It is only upon
305/// encoding that information is lost.
306///
307/// Getting tired of all this compact rendering of your JSON strings? Want a little more whitespace
308/// in your life? Then \c jsonv::ostream_pretty_encoder is the class for you! Unlike our standard
309/// \e compact encoder, this guy will put newlines and indentation in your JSON so you can present
310/// it in a way more readable format.
311///
312/// \code
313/// #include <jsonv/encode.hpp>
314/// #include <jsonv/parse.hpp>
315/// #include <jsonv/value.hpp>
316///
317/// #include <iostream>
318///
319/// int main()
320/// {
321/// // Make a pretty encoder and point to std::cout
322/// jsonv::ostream_pretty_encoder prettifier(std::cout);
323/// prettifier.encode(jsonv::parse(std::cin));
324/// }
325/// \endcode
326///
327/// Compile that code and you now have your own little JSON prettification program!
328///
329/// Not everything you want to write starts out as a \c jsonv::value. A \c jsonv::writer writes a
330/// document one token at a time into any encoder, the pretty one included, and \c jsonv::serialize
331/// writes a C++ object as one value wherever the writer is:
332///
333/// \code
334/// #include <jsonv/encode.hpp>
335/// #include <jsonv/serialization.hpp>
336/// #include <jsonv/writer.hpp>
337///
338/// #include <iostream>
339/// #include <string>
340/// #include <vector>
341///
342/// int main()
343/// {
344/// std::vector<std::string> villains = { "Jason", "Freddy", "Michael" };
345///
346/// jsonv::ostream_pretty_encoder prettifier(std::cout);
347/// jsonv::writer to(prettifier);
348/// to.object_begin();
349/// to.key("genre").string("slasher");
350/// to.key("villains").array_begin();
351/// for (const std::string& name : villains)
352/// jsonv::serialize(name, to);
353/// to.array_end();
354/// to.object_end();
355/// }
356/// \endcode
357///
358/// Output:
359///
360/// \code
361/// {
362/// "genre": "slasher",
363/// "villains": [
364/// "Jason",
365/// "Freddy",
366/// "Michael"
367/// ]
368/// }
369/// \endcode
370///
371/// The writer writes the commas and the colons, and refuses a token which does not belong where it
372/// is -- a key outside an object, say -- before the encoder ever sees it. Each call to \c serialize
373/// writes one more element into the array the writer has open, so the same loop could write a
374/// million names without ever holding them all in a \c jsonv::value. \c serialize works for any type
375/// a \c jsonv::formats knows -- here, \c jsonv::formats::global() -- and teaching one about your own
376/// types is what the \ref serialization "next section" is about.
377///
378/// \section serialization Serialization
379///
380/// Most of the time, you do not want to deal with \c jsonv::value instances directly. Instead, most
381/// people prefer to convert JSON into their own strong C++ \c class or \c struct. JSON Voorhees
382/// provides utilities to make this easy for you to use. At the end of the day, you should be able
383/// to create an arbitrary C++ type with <tt>jsonv::deserialize&lt;my_type&gt;(text)</tt> and turn
384/// one back into JSON text with <tt>jsonv::serialize(my_instance)</tt> -- or into a \c jsonv::value
385/// with <tt>jsonv::to_json(my_instance)</tt>.
386///
387/// \subsection serialization_encoding Deserializing with deserialize
388///
389/// Let's start with converting JSON into C++ types with <tt>jsonv::deserialize&lt;T&gt;</tt>.
390///
391/// \code
392/// #include <jsonv/parse.hpp>
393/// #include <jsonv/serialization.hpp>
394/// #include <jsonv/value.hpp>
395///
396/// #include <iostream>
397/// #include <string>
398///
399/// int main()
400/// {
401/// std::cout << "a=" << jsonv::deserialize<int>("1") << std::endl;
402/// std::cout << "b=" << jsonv::deserialize<double>("2.5") << std::endl;
403/// std::cout << "c=" << jsonv::deserialize<std::string>(R"("Hello!")") << std::endl;
404///
405/// jsonv::value val = jsonv::parse(R"({ "d": 4 })");
406/// std::cout << "d=" << jsonv::deserialize<int>(val.at("d")) << std::endl;
407/// }
408/// \endcode
409///
410/// Output:
411///
412/// \code
413/// a=1
414/// b=2.5
415/// c=Hello!
416/// d=4
417/// \endcode
418///
419/// The first three deserialize from JSON text, which is the spelling to reach for when text is what you
420/// have: the C++ value is read straight out of the text, and no \c jsonv::value is built along the
421/// way. That does mean a C++ string handed to \c deserialize is JSON \e text rather than a JSON string,
422/// so <tt>deserialize&lt;std::string&gt;(R"("Hello!")")</tt> is <tt>Hello!</tt> while
423/// <tt>deserialize&lt;std::string&gt;("Hello!")</tt> fails to parse. The last deserializes from a
424/// \c jsonv::value, which is the spelling for JSON you have already parsed or built. Either way,
425/// JSON which does not hold what you asked for -- <tt>deserialize&lt;int&gt;(R"("one")")</tt> -- throws
426/// a \c jsonv::deserialization_error saying what was found instead.
427///
428/// Overall, this is not very complicated. We did not do anything that could not have been done
429/// through a little use of \c parse and the \c as_ accessors like \c as_integer. So what is this
430/// \c deserialize giving us?
431///
432/// The real power comes in when we start talking about \c jsonv::formats. These objects provide a
433/// set of rules to encode and decode arbitrary types. So let's make a C++ \c class for our JSON
434/// object and write a special constructor for it.
435///
436/// \code
437/// #include <jsonv/serialization.hpp>
438/// #include <jsonv/serialization/deserializer_construction.hpp>
439///
440/// #include <iostream>
441/// #include <string>
442/// #include <string_view>
443/// #include <utility>
444///
445/// class my_type
446/// {
447/// public:
448/// my_type(jsonv::reader& from, jsonv::deserialization_context& context)
449/// {
450/// if (!from.expect(jsonv::ast_node_type::object_begin))
451/// throw jsonv::deserialization_error(context.problem_path(from), "Expected an object");
452///
453/// // Step off the { and onto the first key -- or onto the } of an empty object.
454/// (void) from.next_token();
455/// while (from.current_type() != jsonv::ast_node_type::object_end)
456/// {
457/// std::string key = from.current().visit_key([] (const auto& k) { return std::string(k.value()); });
458///
459/// // Step off the key and onto its value.
460/// (void) from.next_token();
461///
462/// if (key == "a")
463/// a = deserialize_member<int>(from, context, "a");
464/// else if (key == "b")
465/// b = deserialize_member<int>(from, context, "b");
466/// else if (key == "c")
467/// c = deserialize_member<std::string>(from, context, "c");
468/// else
469/// (void) from.next_value();
470/// }
471///
472/// // Step off the } too, leaving the reader one past this object.
473/// (void) from.next_token();
474/// }
475///
476/// static const jsonv::deserializer* get_deserializer()
477/// {
478/// static jsonv::deserializer_construction<my_type> instance;
479/// return &instance;
480/// }
481///
482/// friend std::ostream& operator<<(std::ostream& os, const my_type& self)
483/// {
484/// return os << "{ a=" << self.a << ", b=" << self.b << ", c=" << self.c << " }";
485/// }
486///
487/// private:
488/// template <typename T>
489/// static T deserialize_member(jsonv::reader& from, jsonv::deserialization_context& context, std::string_view key)
490/// {
491/// jsonv::deserialization_context::path_scope scope(context, key);
492///
493/// auto mark = context.problems().size();
494/// if (auto result = context.deserialize<T>(from))
495/// return *std::move(result);
496///
497/// throw jsonv::deserialization_error(context.take_problems_since(mark));
498/// }
499///
500/// private:
501/// int a = 0;
502/// int b = 0;
503/// std::string c;
504/// };
505///
506/// int main()
507/// {
508/// jsonv::formats local_formats;
509/// local_formats.register_deserializer(my_type::get_deserializer());
510/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
511///
512/// my_type x = jsonv::deserialize<my_type>(R"({ "a": 1, "b": 2, "c": "Hello!" })", format);
513/// std::cout << x << std::endl;
514/// }
515/// \endcode
516///
517/// Output:
518///
519/// \code
520/// { a=1, b=2, c=Hello! }
521/// \endcode
522///
523/// There is a lot going on in that example, so let's take it one step at a time. First, we are
524/// creating a \c my_type object to store our values, which is nice. Then, we gave it a
525/// funny-looking constructor:
526///
527/// \code
528/// my_type(jsonv::reader& from, jsonv::deserialization_context& context)
529/// \endcode
530///
531/// This is a <i>deserializing constructor</i>. All that means is that it has those two arguments: a
532/// \c jsonv::reader and a \c jsonv::deserialization_context. The reader is a forward cursor over the
533/// JSON, and when the constructor is called it is sitting on the first token of the value to
534/// deserialize from -- for \c my_type, the <tt>{</tt> of an object. From there, the constructor walks
535/// the object one key at a time, in whatever order the document wrote them:
536///
537/// \code
538/// while (from.current_type() != jsonv::ast_node_type::object_end)
539/// {
540/// std::string key = from.current().visit_key([] (const auto& k) { return std::string(k.value()); });
541///
542/// // Step off the key and onto its value.
543/// (void) from.next_token();
544///
545/// if (key == "a")
546/// a = deserialize_member<int>(from, context, "a");
547/// // ...
548/// else
549/// (void) from.next_value();
550/// }
551/// \endcode
552///
553/// Each value it wants is deserialized by \c deserialize_member, which leaves the reader on the next key,
554/// or on the <tt>}</tt>. A key it does not recognize has its value skipped with \c next_value,
555/// which steps over the whole value in one go, however large it is. Once the closing <tt>}</tt> has
556/// been stepped off as well, the reader is left one position past the object. Every deserializer
557/// promises that, because it is where whatever is deserializing around this object carries on from. A
558/// key the document leaves out leaves its member as it was initialized.
559///
560/// \code
561/// template <typename T>
562/// static T deserialize_member(jsonv::reader& from, jsonv::deserialization_context& context, std::string_view key)
563/// {
564/// jsonv::deserialization_context::path_scope scope(context, key);
565///
566/// auto mark = context.problems().size();
567/// if (auto result = context.deserialize<T>(from))
568/// return *std::move(result);
569///
570/// throw jsonv::deserialization_error(context.take_problems_since(mark));
571/// }
572/// \endcode
573///
574/// The \c jsonv::deserialization_context is what does the work. <tt>context.deserialize&lt;T&gt;(from)</tt>
575/// deserializes a \c T from the value under the cursor, using the \c jsonv::formats the deserialization was
576/// started with, and leaves the cursor one past that value. When it cannot, it does not throw: it
577/// records the problem on the context and returns a \c std::unexpected. A constructor can only fail
578/// by throwing, so \c deserialize_member throws a \c jsonv::deserialization_error carrying what the context
579/// recorded -- \e taking it with \c take_problems_since rather than copying it, so the problem is
580/// reported once. The \c path_scope names the member for as long as it is being deserialized, which is
581/// what puts a problem with \c "a" at <tt>.a</tt> -- or at <tt>[3].a</tt> when the \c my_type is
582/// the fourth element of an array.
583///
584/// Giving up at the first problem is what deserialization does by default. With
585/// \c jsonv::deserialize_options::on_error::collect_all, it carries on past a problem so that it can
586/// report as many as it finds, and a deserializer which walks the reader itself has more to do for
587/// that to work -- see \c jsonv::deserialization_context::recover. The
588/// \ref serialization_composition "DSL" described below does all of that for you.
589///
590/// \code
591/// static const jsonv::deserializer* get_deserializer()
592/// {
593/// static jsonv::deserializer_construction<my_type> instance;
594/// return &instance;
595/// }
596/// \endcode
597///
598/// A \c jsonv::deserializer is a type that knows how to read JSON and create some C++ type out of it.
599/// In this case, we are creating a \c jsonv::deserializer_construction, which is a subtype that knows
600/// how to call the constructor of a type. There are all sorts of \c jsonv::deserializer
601/// implementations in \c jsonv/serialization/, so you should be able to find one that fits your
602/// needs.
603///
604/// \code
605/// jsonv::formats local_formats;
606/// local_formats.register_deserializer(my_type::get_deserializer());
607/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
608/// \endcode
609///
610/// Now things are starting to get interesting. The \c jsonv::formats object is a collection of
611/// <tt>jsonv::deserializer</tt>s, so we create one of our own and add the \c jsonv::deserializer* from
612/// the static function of \c my_type. The \c local_formats \e only knows how to deserialize instances
613/// of \c my_type -- it does \e not know even the most basic things like how to deserialize an \c int.
614/// We use \c jsonv::formats::compose to create a new instance of \c jsonv::formats that combines
615/// the qualities of \c local_formats (which knows how to deal with \c my_type) and the
616/// \c jsonv::formats::defaults (which knows how to deal with things like \c int and
617/// \c std::string). The \c formats instance now has the power to do everything we need!
618///
619/// \code
620/// my_type x = jsonv::deserialize<my_type>(R"({ "a": 1, "b": 2, "c": "Hello!" })", format);
621/// \endcode
622///
623/// This is not terribly different from the example before, but now we are explicitly passing a
624/// \c jsonv::formats object to the function. If we had not provided \c format as an argument here,
625/// the function would have thrown a \c jsonv::deserialization_error complaining about how it did not
626/// know how to deserialize a \c my_type.
627///
628/// JSON often lives in a file, and \c deserialize reads a \c std::istream just as it reads text. An
629/// error is more use if it says which file, so build the \c jsonv::deserialization_context yourself,
630/// with the name of the source last, and hand it to \c deserialize in place of the \c format:
631///
632/// \code
633/// std::ifstream file("my_type.json");
634/// jsonv::deserialization_context context(format,
635/// std::nullopt,
636/// jsonv::path(),
637/// nullptr,
638/// jsonv::deserialize_options(),
639/// "my_type.json"
640/// );
641/// my_type y = jsonv::deserialize<my_type>(file, context);
642/// \endcode
643///
644/// If the file holds <tt>{ "a": 1, "b": "two", "c": "Hello!" }</tt>, the \c "b" is not an \c int, so
645/// this throws a \c jsonv::deserialization_error reading
646/// <tt>Deserialization error at my_type.json#.b: Read node of type string when expecting integer</tt>.
647/// Write out every argument before the name: the \c nullptr is the user data, and a string in its
648/// place would be taken for user data rather than for a name. A context is meant for one
649/// document, so make a new one for each file.
650///
651/// If you are coming from JSON Voorhees 1.x, you may be looking for \c extract_sub. A deserializing
652/// constructor used to be handed a whole \c jsonv::value and pull each member out of it by name,
653/// which is what \c extraction_context::extract_sub did. It is gone because that \c value is gone:
654/// deserialization reads the JSON as it goes rather than building a \c value first, and a forward cursor
655/// has no way to look a key up. Walking the keys, as \c my_type does, is what replaces it. When
656/// random access is genuinely wanted -- what one member means depends on another written after it,
657/// say -- read the object into a \c jsonv::value and look things up in that, with \c value::find or
658/// \c value::at_path. A deserializing constructor can still take a <tt>const jsonv::value&</tt> in
659/// place of the reader for exactly this, and is handed the object as a \c value -- read off the
660/// reader with \c jsonv::read_value, if it was not one already. That keeps the \c extract_sub calls
661/// of a 1.x constructor easy to port:
662///
663/// \code
664/// my_type(const jsonv::value& from, jsonv::deserialization_context& context) :
665/// a(deserialize_member<int>(from, context, "a")),
666/// b(deserialize_member<int>(from, context, "b")),
667/// c(deserialize_member<std::string>(from, context, "c"))
668/// { }
669///
670/// template <typename T>
671/// static T deserialize_member(const jsonv::value& from,
672/// jsonv::deserialization_context& context,
673/// const std::string& key
674/// )
675/// {
676/// jsonv::deserialization_context::path_scope scope(context, key);
677///
678/// auto member = from.find(key);
679/// if (member == from.end_object())
680/// throw jsonv::deserialization_error(context.path(), "Missing required member");
681///
682/// return context.deserialize<T>(member->second);
683/// }
684/// \endcode
685///
686/// The \c path_scope is what says where a problem is, since a \c value has no idea where in the
687/// document it came from. That includes a member which is not there at all: looking it up with
688/// \c find rather than \c value::at is what reports a missing \c "b" at <tt>.b</tt>, while the
689/// scope is still alive to say so. The \c std::out_of_range from \c at would only be caught once
690/// the scope had gone, so it would be reported at the object around the member, and it does not
691/// say which member it was. <tt>context.deserialize&lt;T&gt;</tt> throws rather than returning when it
692/// is handed a \c value, so nothing needs handing over. Building that \c value for every object
693/// deserialized is the cost the reader-based constructor avoids.
694///
695/// \subsection serialization_to_json Serializing with serialize and to_json
696///
697/// JSON Voorhees also converts from your C++ structures into JSON, using \c jsonv::serialize for
698/// JSON text and \c jsonv::to_json for a \c jsonv::value. It should feel like a mirror of
699/// \c jsonv::deserialize, with similar argument types and many shared concepts. Just like
700/// deserialization, both use the \c jsonv::formats class, but they look up a \c jsonv::serializer
701/// in it to convert from C++ into JSON. Where a deserializer reads from a \c jsonv::reader, a
702/// serializer writes into a \c jsonv::writer.
703///
704/// \code
705/// #include <jsonv/serialization.hpp>
706/// #include <jsonv/serialization/function_serializer.hpp>
707/// #include <jsonv/value.hpp>
708/// #include <jsonv/writer.hpp>
709///
710/// #include <iostream>
711/// #include <string>
712/// #include <utility>
713///
714/// class my_type
715/// {
716/// public:
717/// my_type(int a, int b, std::string c) :
718/// a(a),
719/// b(b),
720/// c(std::move(c))
721/// { }
722///
723/// static const jsonv::serializer* get_serializer()
724/// {
725/// static auto instance = jsonv::make_serializer<my_type>
726/// (
727/// [] (const jsonv::serialization_context& context,
728/// const my_type& self,
729/// jsonv::writer& to
730/// )
731/// {
732/// to.object_begin();
733/// to.key("a");
734/// context.serialize(self.a, to);
735/// to.key("b");
736/// context.serialize(self.b, to);
737/// to.key("c");
738/// context.serialize(self.c, to);
739/// to.object_end();
740/// }
741/// );
742/// return &instance;
743/// }
744///
745/// private:
746/// int a;
747/// int b;
748/// std::string c;
749/// };
750///
751/// int main()
752/// {
753/// jsonv::formats local_formats;
754/// local_formats.register_serializer(my_type::get_serializer());
755/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
756///
757/// my_type x(5, 6, "Hello");
758/// std::cout << jsonv::serialize(x, format) << std::endl;
759///
760/// jsonv::value tree = jsonv::to_json(x, format);
761/// std::cout << tree.at("c") << std::endl;
762/// }
763/// \endcode
764///
765/// Output:
766///
767/// \code
768/// {"a":5,"b":6,"c":"Hello"}
769/// "Hello"
770/// \endcode
771///
772/// The serializer is handed a \c jsonv::writer positioned where the \c my_type goes -- at the root
773/// here, but just as well as the element of an array or the value of another object's member -- and
774/// writes exactly one value there. It opens an object, and for each member writes the key and then
775/// hands the member to <tt>context.serialize</tt>, which looks up the serializer for the member's
776/// type in the same \c jsonv::formats and has it write the member where the writer now is. The
777/// writer writes the punctuation, and refuses a token which does not belong where it is: a key
778/// outside an object, say, or a value inside one with no key before it.
779///
780/// \c jsonv::serialize writes \c x as compact JSON text with nothing built in between: no
781/// \c jsonv::value is made along the way, and the members come out in the order the serializer
782/// wrote them. \c jsonv::to_json runs the same serializer into a \c jsonv::value_encoder and hands
783/// back the tree it built, for when a \c jsonv::value is what you want -- to look things up in, as
784/// here, or to change before writing it out. A \c jsonv::value keeps an object's members sorted by
785/// key, so the text of one can list them in a different order from \c serialize; for \c my_type,
786/// they happen to agree. To write the text to a stream rather than into a \c std::string, there is
787/// <tt>jsonv::serialize(x, std::cout, format)</tt>; and <tt>jsonv::serialize(x, to, format)</tt>
788/// writes \c x into a \c jsonv::writer of your own, as in \ref demo_parsing "Encoding and decoding".
789///
790/// A serializer written for JSON Voorhees 1.x returned a \c jsonv::value rather than writing one.
791/// That still works: \c jsonv::make_serializer also takes a function of
792/// <tt>(const jsonv::serialization_context&, const T&)</tt>, or of just the <tt>const T&</tt>,
793/// which returns a \c jsonv::value to be written whole. Building that \c value for every object
794/// serialized is the cost the writer avoids.
795///
796/// \subsection serialization_composition Composing Type Adapters
797///
798/// Does all this seem a little bit \e manual to you? Creating a \c deserializer and \c serializer for
799/// every single type can get a little bit tedious. Unfortunately, until C++ has a standard way to
800/// do reflection, we must specify the conversions manually. However, there \e is an easier way!
801/// That way is the \ref serialization_builder_dsl "Serialization Builder DSL".
802///
803/// Let's start with a couple of simple structures:
804///
805/// \code
806/// struct foo
807/// {
808/// int a;
809/// int b;
810/// std::string c;
811/// };
812///
813/// struct bar
814/// {
815/// foo x;
816/// foo y;
817/// std::string z;
818/// std::string w;
819/// };
820/// \endcode
821///
822/// Let's make a \c formats for them using the DSL:
823///
824/// \code
825/// jsonv::formats formats =
826/// jsonv::formats_builder()
827/// .type<foo>()
828/// .member("a", &foo::a)
829/// .member("b", &foo::b)
830/// .default_value(10)
831/// .member("c", &foo::c)
832/// .type<bar>()
833/// .member("x", &bar::x)
834/// .member("y", &bar::y)
835/// .member("z", &bar::z)
836/// .since(jsonv::version(2, 0))
837/// .member("w", &bar::w)
838/// .until(jsonv::version(5, 0))
839/// .compose_checked(jsonv::formats::defaults())
840/// ;
841/// \endcode
842///
843/// What is going on there? The giant chain of function calls is building up a collection of type
844/// adapters into a \c formats for you. The indentation shows the intent -- the
845/// <tt>.member("a", &foo::a)</tt> is attached to the type \c adapter for \c foo (if you tried to
846/// specify \c &bar::y in that same place, it would fail to compile). Each function call returns a
847/// reference back to the builder so you can chain as many of these together as you want to. The
848/// \c jsonv::formats_builder is a proper object, so if you wish to spread out building your type
849/// adapters into multiple functions, you can do that by passing around an instance.
850///
851/// The two most-used functions are \c type and \c member. \c type defines a \c jsonv::adapter for
852/// the C++ class provided at the template parameter. All of the calls before the second \c type
853/// call modify the adapter for \c foo. There, we attach members with the \c member function. This
854/// tells the \c formats how to encode and deserialize each of the specified members to and from a JSON
855/// object using the provided string as the key. The extra function calls like \c default_value,
856/// \c since and \c until are just a couple of the many functions available to modify how the
857/// members of the type get transformed.
858///
859/// The chain ends with \c compose_checked, which checks that every type the members refer to --
860/// \c int and \c std::string here -- can be deserialized and serialized once the adapters the DSL
861/// built are combined with \c jsonv::formats::defaults, and then composes the two, just as we
862/// composed \c local_formats by hand earlier.
863///
864/// The \c formats we built would be perfectly capable of serializing to and deserializing from this
865/// JSON document:
866///
867/// \code
868/// {
869/// "x": { "a": 50, "b": 20, "c": "Blah" },
870/// "y": { "a": 10, "c": "No B?" },
871/// "z": "Only serialized in 2.0+",
872/// "w": "Only serialized before 5.0"
873/// }
874/// \endcode
875///
876/// Deserializing a \c bar reads the document just the way the constructor of \c my_type did: each
877/// object's keys are walked in the order the document wrote them, each is handed to the member
878/// which claims it, and a key no member claims has its value stepped over unread. What the DSL adds
879/// is everything that constructor left out. A member without a \c default_value is required, a key
880/// the document repeats is settled by \c jsonv::deserialize_options::on_duplicate_key, and
881/// \c jsonv::deserialize_options::on_error::collect_all carries on past a problem to report the rest.
882///
883/// For a more in-depth reference, see the \ref serialization_builder_dsl "Serialization Builder DSL page".
884///
885/// \section demo_algorithm Algorithms
886///
887/// JSON Voorhees takes a "batteries included" approach. A few building blocks for powerful
888/// operations can be found in the \c algorithm.hpp header file.
889///
890/// One of the simplest operations you can perform is the \c map operation. This operation takes in
891/// some \c jsonv::value and returns another. Let's try it.
892///
893/// \code
894/// #include <jsonv/algorithm.hpp>
895/// #include <jsonv/value.hpp>
896///
897/// #include <iostream>
898///
899/// int main()
900/// {
901/// jsonv::value x = 5;
902/// std::cout << jsonv::map([] (const jsonv::value& y) { return y.as_integer() * 2; }, x) << std::endl;
903/// }
904/// \endcode
905///
906/// If everything went right, you should see a number:
907///
908/// \code
909/// 10
910/// \endcode
911///
912/// That is not the most interesting example of using \c map, but it is enough to get the general
913/// idea of what is going on. This operation is so common that it is a member function of \c value
914/// as \c jsonv::value::map. Let's make things a bit more interesting and \c map an \c array...
915///
916/// \code
917/// #include <jsonv/value.hpp>
918///
919/// #include <iostream>
920///
921/// int main()
922/// {
923/// std::cout << jsonv::array({ 1, 2, 3, 4, 5 })
924/// .map([] (const jsonv::value& y) { return y.as_integer() * 2; })
925/// << std::endl;
926/// }
927/// \endcode
928///
929/// Now we're starting to get somewhere!
930///
931/// \code
932/// [2,4,6,8,10]
933/// \endcode
934///
935/// The \c map function maps over whatever the contents of the \c jsonv::value happens to be and
936/// returns something for you based on the \c kind. This simple concept is so ubiquitous that
937/// <a href="http://www.disi.unige.it/person/MoggiE/"> Eugenio Moggi</a> named it a
938/// <a href="http://stackoverflow.com/questions/44965/what-is-a-monad">monad</a>. If you're feeling
939/// adventurous, try using \c map with an \c object or chaining multiple \c map operations together.
940///
941/// Another common building block is the function \c jsonv::traverse. This function walks a JSON
942/// structure and calls a some user-provided function.
943///
944/// \code
945/// #include <jsonv/algorithm.hpp>
946/// #include <jsonv/parse.hpp>
947/// #include <jsonv/value.hpp>
948///
949/// #include <iostream>
950///
951/// int main()
952/// {
953/// jsonv::traverse(jsonv::parse(std::cin),
954/// [] (const jsonv::path& path, const jsonv::value& value)
955/// {
956/// std::cout << path << " => " << value << std::endl;
957/// },
958/// true
959/// );
960/// }
961/// \endcode
962///
963/// Now we have a tiny little program to decompose JSON into <a href="https://jqlang.org/">jq</a>
964/// style path expressions and their values. For example, if you pipe
965/// <tt>{ "bar": [1, 2, 3], "foo": "hello" }</tt> into the program:
966///
967/// \code
968/// .bar[0] => 1
969/// .bar[1] => 2
970/// .bar[2] => 3
971/// .foo => "hello"
972/// \endcode
973///
974/// All of the \e really powerful functions can be found in \c algorithm.hpp. My personal favorite
975/// is \c jsonv::merge. The idea is simple: it merges two (or more) JSON values into one.
976///
977/// \code
978/// #include <jsonv/algorithm.hpp>
979/// #include <jsonv/value.hpp>
980///
981/// #include <iostream>
982///
983/// int main()
984/// {
985/// jsonv::value a = jsonv::object({ { "a", "taco" }, { "b", "cat" } });
986/// jsonv::value b = jsonv::object({ { "c", "burrito" }, { "d", "dog" } });
987/// jsonv::value merged = jsonv::merge(std::move(a), std::move(b));
988/// std::cout << merged << std::endl;
989/// }
990/// \endcode
991///
992/// Output:
993///
994/// \code
995/// {"a":"taco","b":"cat","c":"burrito","d":"dog"}
996/// \endcode
997///
998/// You might have noticed the use of \c std::move into the \c merge function. Like most functions
999/// in JSON Voorhees, \c merge takes advantage of move semantics. In this case, the implementation
1000/// will move the contents of the values instead of copying them around. While it may not matter in
1001/// this simple case, if you have large JSON structures, the support for movement will save you a
1002/// ton of memory.
1003///
1004/// \see https://github.com/tgockel/json-voorhees
1005/// \see http://json.org/
1006
1007}
1008
1009#include "algorithm.hpp"
1010#include "ast.hpp"
1011#include "coerce.hpp"
1012#include "config.hpp"
1013#include "demangle.hpp"
1014#include "encode.hpp"
1015#include "forward.hpp"
1016#include "functional.hpp"
1017#include "kind.hpp"
1018#include "optional.hpp"
1019#include "parse.hpp"
1020#include "parse_index.hpp"
1021#include "path.hpp"
1022#include "reader.hpp"
1023#include "serialization.hpp"
1025#include "serialization/all.hpp"
1026#include "value.hpp"
1027#include "version.hpp"
1028#include "writer.hpp"
A collection of algorithms a la &lt;algorithm&gt;.
Utilities for directly dealing with a JSON AST.
A jsonv::value has a number of as_X operators, which strictly performs a transformation to a C++ data...
Copyright (c) 2014-2020 by Travis Gockel.
Copyright (c) 2015 by Travis Gockel.
Classes and functions for encoding JSON values to various representations.
Copyright (c) 2012-2020 by Travis Gockel.
A collection of function objects a la &lt;functional&gt;.
Copyright (c) 2019-2020 by Travis Gockel.
Pulls in an implementation of optional.
Copyright (c) 2012-2020 by Travis Gockel.
Parsed index of a JSON document.
Support for JSONPath.
Read a JSON AST.
Header file for including all serialization utilities.
Conversion between C++ types and JSON values.
DSL for building formats.
Copyright (c) 2012-2020 by Travis Gockel.
Representation of a version used to select serialization behavior.
Write a JSON AST.