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/// - Convert a `value` into a C++ type 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 \c jsonv::value instances into their own strong C++ \c class or
330/// \c struct. JSON Voorhees provides utilities to make this easy for you to use. At the end of the
331/// day, you should be able to create an arbitrary C++ type with
332/// <tt>jsonv::extract&lt;my_type&gt;(value)</tt> and create a \c jsonv::value from your arbitrary
333/// C++ type with <tt>jsonv::to_json(my_instance)</tt>.
334///
335/// \subsection serialization_encoding Extracting with extract
336///
337/// Let's start with converting a \c jsonv::value into a custom C++ type with
338/// <tt>jsonv::extract&lt;T&gt;</tt>.
339///
340/// \code
341/// #include <jsonv/parse.hpp>
342/// #include <jsonv/serialization.hpp>
343/// #include <jsonv/value.hpp>
344///
345/// #include <iostream>
346///
347/// int main()
348/// {
349/// jsonv::value val = jsonv::parse(R"({ "a": 1, "b": 2, "c": "Hello!" })");
350/// std::cout << "a=" << jsonv::extract<int>(val.at("a")) << std::endl;
351/// std::cout << "b=" << jsonv::extract<int>(val.at("b")) << std::endl;
352/// std::cout << "c=" << jsonv::extract<std::string>(val.at("c")) << std::endl;
353/// }
354/// \endcode
355///
356/// Output:
357///
358/// \code
359/// a=1
360/// b=2
361/// c=Hello!
362/// \endcode
363///
364/// Overall, this is not very complicated. We did not do anything that could not have been done
365/// through a little use of \c as_integer and \c as_string. So what is this \c extract giving us?
366///
367/// The real power comes in when we start talking about \c jsonv::formats. These objects provide a
368/// set of rules to encode and decode arbitrary types. So let's make a C++ \c class for our JSON
369/// object and write a special constructor for it.
370///
371/// \code
372/// #include <jsonv/parse.hpp>
373/// #include <jsonv/serialization.hpp>
374/// #include <jsonv/serialization_util.hpp>
375/// #include <jsonv/value.hpp>
376///
377/// #include <iostream>
378///
379/// class my_type
380/// {
381/// public:
382/// my_type(const jsonv::value& from, jsonv::extraction_context& context) :
383/// a(context.extract_sub<int>(from, "a")),
384/// b(context.extract_sub<int>(from, "b")),
385/// c(context.extract_sub<std::string>(from, "c"))
386/// { }
387///
388/// static const jsonv::extractor* get_extractor()
389/// {
390/// static jsonv::extractor_construction<my_type> instance;
391/// return &instance;
392/// }
393///
394/// friend std::ostream& operator<<(std::ostream& os, const my_type& self)
395/// {
396/// return os << "{ a=" << self.a << ", b=" << self.b << ", c=" << self.c << " }";
397/// }
398///
399/// private:
400/// int a;
401/// int b;
402/// std::string c;
403/// };
404///
405/// int main()
406/// {
407/// jsonv::formats local_formats;
408/// local_formats.register_extractor(my_type::get_extractor());
409/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
410///
411/// jsonv::value val = jsonv::parse(R"({ "a": 1, "b": 2, "c": "Hello!" })");
412/// my_type x = jsonv::extract<my_type>(val, format);
413/// std::ostream << x << std::endl;
414/// }
415/// \endcode
416///
417/// Output:
418///
419/// \code
420/// { a=1, b=2, c=Hello! }
421/// \endcode
422///
423/// There is a lot going on in that example, so let's take it one step at a time. First, we are
424/// creating a \c my_type object to store our values, which is nice. Then, we gave it a
425/// funny-looking constructor:
426///
427/// \code
428/// my_type(const jsonv::value& from, jsonv::extraction_context& context) :
429/// a(context.extract_sub<int>(from, "a")),
430/// b(context.extract_sub<int>(from, "b")),
431/// c(context.extract_sub<std::string>(from, "c"))
432/// { }
433/// \endcode
434///
435/// This is an <i>extracting constructor</i>. All that means is that it has those two arguments: a
436/// \c jsonv::value and a \c jsonv::extraction_context. The \c jsonv::extraction_context is an
437/// optional, but extremely helpful class. Inside the constructor, we use the
438/// \c jsonv::extraction_context to access the values of the incoming JSON object in order to build
439/// our object.
440///
441/// \code
442/// static const jsonv::extractor* get_extractor()
443/// {
444/// static jsonv::extractor_construction<my_type> instance;
445/// return &instance;
446/// }
447/// \endcode
448///
449/// A \c jsonv::extractor is a type that knows how to take a \c jsonv::value and create some C++
450/// type out of it. In this case, we are creating a \c jsonv::extractor_construction, which is a
451/// subtype that knows how to call the constructor of a type. There are all sorts of
452/// \c jsonv::extractor implementations in \c jsonv/serialization.hpp, so you should be able to find
453/// one that fits your needs.
454///
455/// \code
456/// jsonv::formats local_formats;
457/// local_formats.register_extractor(my_type::get_extractor());
458/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
459/// \endcode
460///
461/// Now things are starting to get interesting. The \c jsonv::formats object is a collection of
462/// <tt>jsonv::extractor</tt>s, so we create one of our own and add the \c jsonv::extractor* from
463/// the static function of \c my_type. The \c local_formats \e only knows how to extract instances
464/// of \c my_type -- it does \e not know even the most basic things like how to extract an \c int.
465/// We use \c jsonv::formats::compose to create a new instance of \c jsonv::formats that combines
466/// the qualities of \c local_formats (which knows how to deal with \c my_type) and the
467/// \c jsonv::formats::defaults (which knows how to deal with things like \c int and
468/// \c std::string). The \c formats instance now has the power to do everything we need!
469///
470/// \code
471/// my_type x = jsonv::extract<my_type>(val, format);
472/// \endcode
473///
474/// This is not terribly different from the example before, but now we are explicitly passing a
475/// \c jsonv::formats object to the function. If we had not provided \c format as an argument here,
476/// the function would have thrown a \c jsonv::extraction_error complaining about how it did not
477/// know how to extract a \c my_type.
478///
479/// \subsection serialization_to_json Serialization with to_json
480///
481/// JSON Voorhees also allows you to convert from your C++ structures into JSON values, using
482/// \c jsonv::to_json. It should feel like a mirror \c jsonv::extract, with similar argument types
483/// and many shared concepts. Just like extraction, \c jsonv::to_json uses the \c jsonv::formats
484/// class, but it uses a \c jsonv::serializer to convert from C++ into JSON.
485///
486/// \code
487/// #include <jsonv/serialization.hpp>
488/// #include <jsonv/serialization_util.hpp>
489/// #include <jsonv/value.hpp>
490///
491/// #include <iostream>
492///
493/// class my_type
494/// {
495/// public:
496/// my_type(int a, int b, std::string c) :
497/// a(a),
498/// b(b),
499/// c(std::move(c))
500/// { }
501///
502/// static const jsonv::serializer* get_serializer()
503/// {
504/// static auto instance = jsonv::make_serializer<my_type>
505/// (
506/// [] (const jsonv::serialization_context& context, const my_type& self)
507/// {
508/// return jsonv::object({ { "a", context.to_json(self.a) },
509/// { "b", context.to_json(self.b) },
510/// { "c", context.to_json(self.c) }
511/// }
512/// );
513/// }
514/// );
515/// return &instance;
516/// }
517///
518/// private:
519/// int a;
520/// int b;
521/// std::string c;
522/// };
523///
524/// int main()
525/// {
526/// jsonv::formats local_formats;
527/// local_formats.register_serializer(my_type::get_serializer());
528/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
529///
530/// my_type x(5, 6, "Hello");
531/// std::ostream << jsonv::to_json(x, format) << std::endl;
532/// }
533/// \endcode
534///
535/// Output:
536///
537/// \code
538/// {"a":5,"b":6,"c":"Hello"}
539/// \endcode
540///
541/// \subsection serialization_composition Composing Type Adapters
542///
543/// Does all this seem a little bit \e manual to you? Creating an \c extractor and \c serializer for
544/// every single type can get a little bit tedious. Unfortunately, until C++ has a standard way to
545/// do reflection, we must specify the conversions manually. However, there \e is an easier way!
546/// That way is the \ref serialization_builder_dsl "Serialization Builder DSL".
547///
548/// Let's start with a couple of simple structures:
549///
550/// \code
551/// struct foo
552/// {
553/// int a;
554/// int b;
555/// std::string c;
556/// };
557///
558/// struct bar
559/// {
560/// foo x;
561/// foo y;
562/// std::string z;
563/// std::string w;
564/// };
565/// \endcode
566///
567/// Let's make a \c formats for them using the DSL:
568///
569/// \code
570/// jsonv::formats formats =
571/// jsonv::formats_builder()
572/// .type<foo>()
573/// .member("a", &foo::a)
574/// .member("b", &foo::b)
575/// .default_value(10)
576/// .member("c", &foo::c)
577/// .type<bar>()
578/// .member("x", &bar::x)
579/// .member("y", &bar::y)
580/// .member("z", &bar::z)
581/// .since(jsonv::version(2, 0))
582/// .member("w", &bar::w)
583/// .until(jsonv::version(5, 0))
584/// ;
585/// \endcode
586///
587/// What is going on there? The giant chain of function calls is building up a collection of type
588/// adapters into a \c formats for you. The indentation shows the intent -- the
589/// <tt>.member("a", &foo::a)</tt> is attached to the type \c adapter for \c foo (if you tried to
590/// specify \c &bar::y in that same place, it would fail to compile). Each function call returns a
591/// reference back to the builder so you can chain as many of these together as you want to. The
592/// \c jsonv::formats_builder is a proper object, so if you wish to spread out building your type
593/// adapters into multiple functions, you can do that by passing around an instance.
594///
595/// The two most-used functions are \c type and \c member. \c type defines a \c jsonv::adapter for
596/// the C++ class provided at the template parameter. All of the calls before the second \c type
597/// call modify the adapter for \c foo. There, we attach members with the \c member function. This
598/// tells the \c formats how to encode and extract each of the specified members to and from a JSON
599/// object using the provided string as the key. The extra function calls like \c default_value,
600/// \c since and \c until are just a could of the many functions available to modify how the members
601/// of the type get transformed.
602///
603/// The \c formats we built would be perfectly capable of serializing to and extracting from this
604/// JSON document:
605///
606/// \code
607/// {
608/// "x": { "a": 50, "b": 20, "c": "Blah" },
609/// "y": { "a": 10, "c": "No B?" },
610/// "z": "Only serialized in 2.0+",
611/// "w": "Only serialized before 5.0"
612/// }
613/// \endcode
614///
615/// For a more in-depth reference, see the \ref serialization_builder_dsl "Serialization Builder DSL page".
616///
617/// \section demo_algorithm Algorithms
618///
619/// JSON Voorhees takes a "batteries included" approach. A few building blocks for powerful
620/// operations can be found in the \c algorithm.hpp header file.
621///
622/// One of the simplest operations you can perform is the \c map operation. This operation takes in
623/// some \c jsonv::value and returns another. Let's try it.
624///
625/// \code
626/// #include <jsonv/algorithm.hpp>
627/// #include <jsonv/value.hpp>
628///
629/// #include <iostream>
630///
631/// int main()
632/// {
633/// jsonv::value x = 5;
634/// std::cout << jsonv::map([] (const jsonv::value& y) { return y.as_integer() * 2; }, x) << std::endl;
635/// }
636/// \endcode
637///
638/// If everything went right, you should see a number:
639///
640/// \code
641/// 10
642/// \endcode
643///
644/// That is not the most interesting example of using \c map, but it is enough to get the general
645/// idea of what is going on. This operation is so common that it is a member function of \c value
646/// as \c jsonv::value::map. Let's make things a bit more interesting and \c map an \c array...
647///
648/// \code
649/// #include <jsonv/value.hpp>
650///
651/// #include <iostream>
652///
653/// int main()
654/// {
655/// std::cout << jsonv::array({ 1, 2, 3, 4, 5 })
656/// .map([] (const jsonv::value& y) { return y.as_integer() * 2; })
657/// << std::endl;
658/// }
659/// \endcode
660///
661/// Now we're starting to get somewhere!
662///
663/// \code
664/// [2,4,6,8,10]
665/// \endcode
666///
667/// The \c map function maps over whatever the contents of the \c jsonv::value happens to be and
668/// returns something for you based on the \c kind. This simple concept is so ubiquitous that
669/// <a href="http://www.disi.unige.it/person/MoggiE/"> Eugenio Moggi</a> named it a
670/// <a href="http://stackoverflow.com/questions/44965/what-is-a-monad">monad</a>. If you're feeling
671/// adventurous, try using \c map with an \c object or chaining multiple \c map operations together.
672///
673/// Another common building block is the function \c jsonv::traverse. This function walks a JSON
674/// structure and calls a some user-provided function.
675///
676/// \code
677/// #include <jsonv/algorithm.hpp>
678/// #include <jsonv/parse.hpp>
679/// #include <jsonv/value.hpp>
680///
681/// #include <iostream>
682///
683/// int main()
684/// {
685/// jsonv::traverse(jsonv::parse(std::cin),
686/// [] (const jsonv::path& path, const jsonv::value& value)
687/// {
688/// std::cout << path << " => " << value << std::endl;
689/// },
690/// true
691/// );
692/// }
693/// \endcode
694///
695/// Now we have a tiny little program to decompose JSON into <a href="https://jqlang.org/">jq</a>
696/// style path expressions and their values. For example, if you pipe
697/// <tt>{ "bar": [1, 2, 3], "foo": "hello" }</tt> into the program:
698///
699/// \code
700/// .bar[0] => 1
701/// .bar[1] => 2
702/// .bar[2] => 3
703/// .foo => "hello"
704/// \endcode
705///
706/// All of the \e really powerful functions can be found in \c algorithm.hpp. My personal favorite
707/// is \c jsonv::merge. The idea is simple: it merges two (or more) JSON values into one.
708///
709/// \code
710/// #include <jsonv/algorithm.hpp>
711/// #include <jsonv/value.hpp>
712///
713/// #include <iostream>
714///
715/// int main()
716/// {
717/// jsonv::value a = jsonv::object({ { "a", "taco" }, { "b", "cat" } });
718/// jsonv::value b = jsonv::object({ { "c", "burrito" }, { "d", "dog" } });
719/// jsonv::value merged = jsonv::merge(std::move(a), std::move(b));
720/// std::cout << merged << std::endl;
721/// }
722/// \endcode
723///
724/// Output:
725///
726/// \code
727/// {"a":"taco","b":"cat","c":"burrito","d":"dog"}
728/// \endcode
729///
730/// You might have noticed the use of \c std::move into the \c merge function. Like most functions
731/// in JSON Voorhees, \c merge takes advantage of move semantics. In this case, the implementation
732/// will move the contents of the values instead of copying them around. While it may not matter in
733/// this simple case, if you have large JSON structures, the support for movement will save you a
734/// ton of memory.
735///
736/// \see https://github.com/tgockel/json-voorhees
737/// \see http://json.org/
738
739}
740
741#include "algorithm.hpp"
742#include "ast.hpp"
743#include "coerce.hpp"
744#include "config.hpp"
745#include "demangle.hpp"
746#include "encode.hpp"
747#include "forward.hpp"
748#include "functional.hpp"
749#include "kind.hpp"
750#include "parse.hpp"
751#include "parse_index.hpp"
752#include "path.hpp"
753#include "reader.hpp"
754#include "serialization.hpp"
756#include "serialization/all.hpp"
757#include "value.hpp"
758#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.