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