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/// - Almost all utility functions have a [strong exception guarantee](http://www.gotw.ca/gotw/082.htm)
42/// - Stable
43/// - Worry less about upgrading -- the API and ABI will not change out from under you
44/// - Documented
45/// - Consumable by human beings
46/// - Answers questions you might actually ask
47///
48/// \dotfile doc/conversions.dot
49///
50/// JSON Voorhees is designed with ease-of-use in mind. So let's look at some code!
51///
52/// \section demo_value The jsonv::value
53///
54/// The central class of JSON Voorhees is the \c jsonv::value, which represents a JSON AST. Putting
55/// values of different types is easy.
56///
57/// \code
58/// #include <jsonv/value.hpp>
59/// #include <iostream>
60///
61/// int main()
62/// {
63/// jsonv::value x = jsonv::null;
64/// std::cout << x << std::endl;
65/// x = 5.9;
66/// std::cout << x << std::endl;
67/// x = -100;
68/// std::cout << x << std::endl;
69/// x = "something else";
70/// std::cout << x << std::endl;
71/// x = jsonv::array({ "arrays", "of", "the", 7, "different", "types?", true });
72/// std::cout << x << std::endl;
73/// x = jsonv::object({
74/// { "objects", jsonv::array({
75/// "Are fun, too.",
76/// "Do what you want."
77/// })
78/// },
79/// { "compose like", "standard library maps" },
80/// });
81/// std::cout << x << std::endl;
82/// }
83/// \endcode
84///
85/// Output:
86///
87/// \code
88/// null
89/// 5.9
90/// -100
91/// "something else"
92/// ["arrays","of","the",7,"different","types?",true]
93/// {"compose like":"standard library maps","objects":["Are fun, too.","Do what you want."]}
94/// \endcode
95///
96/// If that isn't convenient enough for you, there is a user-defined literal \c _json in the
97/// \c jsonv namespace you can use:
98///
99/// \code
100/// // You can use this hideous syntax if you do not want to bring in the whole jsonv namespace:
101/// using jsonv::operator""_json;
102///
103/// jsonv::value x = R"({
104/// "objects": [ "Are fun, too.",
105/// "Do what you want."
106/// ],
107/// "compose like": "You are just writing JSON",
108/// "which I guess": ["is", "also", "neat"]
109/// })"_json;
110/// \endcode
111///
112/// JSON is dynamic, which makes value access a bit more of a hassle, but JSON Voorhees aims to make
113/// it not too horrifying for you. A \c jsonv::value has a number of accessor methods named things
114/// like \c as_integer and \c as_string which let you access the value as if it was that type. But
115/// what if it isn't that type? In that case, the function will throw a \c jsonv::kind_error with a
116/// bit more information as to what rule you violated.
117///
118/// \code
119/// #include <jsonv/value.hpp>
120/// #include <iostream>
121///
122/// int main()
123/// {
124/// jsonv::value x = jsonv::null;
125/// try
126/// {
127/// x.as_string();
128/// }
129/// catch (const jsonv::kind_error& err)
130/// {
131/// std::cout << err.what() << std::endl;
132/// }
133///
134/// x = "now make it a string";
135/// std::cout << x.as_string().size() << std::endl;
136/// std::cout << x.as_string() << "\tis not the same as\t" << x << std::endl;
137/// }
138/// \endcode
139///
140/// Output:
141///
142/// \code
143/// Unexpected type: expected string but found null.
144/// 20
145/// now make it a string is not the same as "now make it a string"
146/// \endcode
147///
148/// You can also deal with container types in a similar manner that you would deal with the
149/// equivalent STL container type, with some minor caveats. Because the \c value_type of a JSON
150/// object and JSON array are different, they have different iterator types in JSON Voorhees. They
151/// are named \c object_iterator and \c array_iterator. The access methods for these iterators are
152/// \c begin_object / \c end_object and \c begin_array / \c end_array, respectively. The object
153/// interface behaves exactly like you would expect a \c std::map<std::string,jsonv::value> to,
154/// while the array interface behaves just like a \c std::deque<jsonv::value> would.
155///
156/// \code
157/// #include <jsonv/value.hpp>
158/// #include <iostream>
159///
160/// int main()
161/// {
162/// jsonv::value x = jsonv::object({ { "one", 1 }});
163/// auto iter = x.find("one");
164/// if (iter != x.end_object())
165/// std::cout << iter->first << ": " << iter->second << std::endl;
166/// else
167/// std::cout << "Nothing..." << std::end;
168///
169/// iter = x.find("two");
170/// if (iter != x.end_object())
171/// std::cout << iter->first << ": " << iter->second << std::endl;
172/// else
173/// std::cout << "Nothing..." << std::end;
174///
175/// x["two"] = 2;
176/// iter = x.find("two");
177/// if (iter != x.end_object())
178/// std::cout << iter->first << ": " << iter->second << std::endl;
179/// else
180/// std::cout << "Nothing..." << std::end;
181///
182/// x["two"] = jsonv::array({ "one", "+", x.at("one") });
183/// iter = x.find("two");
184/// if (iter != x.end_object())
185/// std::cout << iter->first << ": " << iter->second << std::endl;
186/// else
187/// std::cout << "Nothing..." << std::end;
188///
189/// x.erase("one");
190/// iter = x.find("one");
191/// if (iter != x.end_object())
192/// std::cout << iter->first << ": " << iter->second << std::endl;
193/// else
194/// std::cout << "Nothing..." << std::end;
195/// }
196/// \endcode
197///
198/// Output:
199///
200/// \code
201/// one: 1
202/// Nothing...
203/// two: 2
204/// two: ["one","+",1]
205/// Nothing...
206/// \endcode
207///
208/// The iterator types \e work. This means you are free to use all of the C++ things just like you
209/// would a regular container. To use a ranged-based for, simply call \c as_array or \c as_object.
210/// Everything from \c <algorithm> and \c <iterator> or any other library works great with JSON
211/// Voorhees.
212///
213/// \code
214/// #include <jsonv/value.hpp>
215/// #include <algorithm>
216/// #include <iostream>
217///
218/// int main()
219/// {
220/// jsonv::value arr = jsonv::array({ "taco", "cat", 3, -2, jsonv::null, "beef", 4.8, 5 });
221/// std::cout << "Initial: ";
222/// for (const auto& val : arr.as_array())
223/// std::cout << val << '\t';
224/// std::cout << std::endl;
225///
226/// std::sort(arr.begin_array(), arr.end_array());
227/// std::cout << "Sorted: ";
228/// for (const auto& val : arr.as_array())
229/// std::cout << val << '\t';
230/// std::cout << std::endl;
231/// }
232/// \endcode
233///
234/// Output:
235///
236/// \code
237/// Initial: "taco" "cat" 3 -2 null "beef" 4.8 5
238/// Sorted: null -2 3 4.8 5 "beef" "cat" "taco"
239/// \endcode
240///
241/// \section demo_parsing Encoding and decoding
242///
243/// Usually, the reason people are using JSON is as a data exchange format, either for communicating
244/// with other services or storing things in a file or a database. To do this, you need to \e encode
245/// your \c json::value into an \c std::string and \e parse it back. JSON Voorhees makes this easy
246/// for you.
247///
248/// \code
249/// #include <jsonv/value.hpp>
250/// #include <jsonv/encode.hpp>
251/// #include <jsonv/parse.hpp>
252///
253/// #include <iostream>
254/// #include <fstream>
255/// #include <limits>
256///
257/// int main()
258/// {
259/// jsonv::value obj = jsonv::object();
260/// obj["taco"] = "cat";
261/// obj["array"] = jsonv::array({ 1, 2, 3, 4, 5 });
262/// obj["infinity"] = std::numeric_limits<double>::infinity();
263///
264/// {
265/// std::cout << "Saving \"file.json\"... " << obj << std::endl;
266/// std::ofstream file("file.json");
267/// file << obj;
268/// }
269///
270/// jsonv::value loaded;
271/// {
272/// std::cout << "Loading \"file.json\"...";
273/// std::ifstream file("file.json");
274/// loaded = jsonv::parse(file);
275/// }
276/// std::cout << loaded << std::endl;
277///
278/// return obj == loaded ? 0 : 1;
279/// }
280/// \endcode
281///
282/// Output:
283///
284/// \code
285/// Saving "file.json"... {"array":[1,2,3,4,5],"infinity":null,"taco":"cat"}
286/// Loading "file.json"...{"array":[1,2,3,4,5],"infinity":null,"taco":"cat"}
287/// \endcode
288///
289/// If you are paying close attention, you might have noticed that the value for the \c "infinity"
290/// looks a little bit more \c null than \c infinity. This is because, much like mathematicians
291/// before Anaximander, JSON has no concept of infinity, so it is actually \e illegal to serialize a
292/// token like \c infinity anywhere.
293///
294/// By default, when an encoder encounters an unrepresentable value in the JSON it is trying to
295/// encode, it outputs \c null instead. If you wish to change this behavior, implement your own
296/// \c jsonv::encoder (or derive from \c jsonv::ostream_encoder).
297///
298/// If you ran the example program, you might have noticed that the return code was 1, meaning the
299/// value you put into the file and what you got from it were not equal. This is because all the
300/// type and value information is still kept around in the in-memory \c obj. It is only upon
301/// encoding that information is lost.
302///
303/// Getting tired of all this compact rendering of your JSON strings? Want a little more whitespace
304/// in your life? Then \c jsonv::ostream_pretty_encoder is the class for you! Unlike our standard
305/// \e compact encoder, this guy will put newlines and indentation in your JSON so you can present
306/// it in a way more readable format.
307///
308/// \code
309/// #include <jsonv/encode.hpp>
310/// #include <jsonv/parse.hpp>
311/// #include <jsonv/value.hpp>
312///
313/// #include <iostream>
314///
315/// int main()
316/// {
317/// // Make a pretty encoder and point to std::cout
318/// jsonv::ostream_pretty_encoder prettifier(std::cout);
319/// prettifier.encode(jsonv::parse(std::cin));
320/// }
321/// \endcode
322///
323/// Compile that code and you now have your own little JSON prettification program!
324///
325/// \section serialization Serialization
326///
327/// Most of the time, you do not want to deal with \c jsonv::value instances directly. Instead, most
328/// people prefer to convert \c jsonv::value instances into their own strong C++ \c class or
329/// \c struct. JSON Voorhees provides utilities to make this easy for you to use. At the end of the
330/// day, you should be able to create an arbitrary C++ type with
331/// <tt>jsonv::extract&lt;my_type&gt;(value)</tt> and create a \c jsonv::value from your arbitrary
332/// 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 a \c jsonv::value into a custom C++ type with
337/// <tt>jsonv::extract&lt;T&gt;</tt>.
338///
339/// \code
340/// #include <jsonv/parse.hpp>
341/// #include <jsonv/serialization.hpp>
342/// #include <jsonv/value.hpp>
343///
344/// #include <iostream>
345///
346/// int main()
347/// {
348/// jsonv::value val = jsonv::parse(R"({ "a": 1, "b": 2, "c": "Hello!" })");
349/// std::cout << "a=" << jsonv::extract<int>(val.at("a")) << std::endl;
350/// std::cout << "b=" << jsonv::extract<int>(val.at("b")) << std::endl;
351/// std::cout << "c=" << jsonv::extract<std::string>(val.at("c")) << std::endl;
352/// }
353/// \endcode
354///
355/// Output:
356///
357/// \code
358/// a=1
359/// b=2
360/// c=Hello!
361/// \endcode
362///
363/// Overall, this is not very complicated. We did not do anything that could not have been done
364/// through a little use of \c as_integer and \c as_string. So what is this \c extract giving us?
365///
366/// The real power comes in when we start talking about \c jsonv::formats. These objects provide a
367/// set of rules to encode and decode arbitrary types. So let's make a C++ \c class for our JSON
368/// object and write a special constructor for it.
369///
370/// \code
371/// #include <jsonv/parse.hpp>
372/// #include <jsonv/serialization.hpp>
373/// #include <jsonv/serialization_util.hpp>
374/// #include <jsonv/value.hpp>
375///
376/// #include <iostream>
377///
378/// class my_type
379/// {
380/// public:
381/// my_type(const jsonv::value& from, const jsonv::extraction_context& context) :
382/// a(context.extract_sub<int>(from, "a")),
383/// b(context.extract_sub<int>(from, "b")),
384/// c(context.extract_sub<std::string>(from, "c"))
385/// { }
386///
387/// static const jsonv::extractor* get_extractor()
388/// {
389/// static jsonv::extractor_construction<my_type> instance;
390/// return &instance;
391/// }
392///
393/// friend std::ostream& operator<<(std::ostream& os, const my_type& self)
394/// {
395/// return os << "{ a=" << self.a << ", b=" << self.b << ", c=" << self.c << " }";
396/// }
397///
398/// private:
399/// int a;
400/// int b;
401/// std::string c;
402/// };
403///
404/// int main()
405/// {
406/// jsonv::formats local_formats;
407/// local_formats.register_extractor(my_type::get_extractor());
408/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
409///
410/// jsonv::value val = jsonv::parse(R"({ "a": 1, "b": 2, "c": "Hello!" })");
411/// my_type x = jsonv::extract<my_type>(val, format);
412/// std::ostream << x << std::endl;
413/// }
414/// \endcode
415///
416/// Output:
417///
418/// \code
419/// { a=1, b=2, c=Hello! }
420/// \endcode
421///
422/// There is a lot going on in that example, so let's take it one step at a time. First, we are
423/// creating a \c my_type object to store our values, which is nice. Then, we gave it a
424/// funny-looking constructor:
425///
426/// \code
427/// my_type(const jsonv::value& from, const jsonv::extraction_context& context) :
428/// a(context.extract_sub<int>(from, "a")),
429/// b(context.extract_sub<int>(from, "b")),
430/// c(context.extract_sub<std::string>(from, "c"))
431/// { }
432/// \endcode
433///
434/// This is an <i>extracting constructor</i>. All that means is that it has those two arguments: a
435/// \c jsonv::value and a \c jsonv::extraction_context. The \c jsonv::extraction_context is an
436/// optional, but extremely helpful class. Inside the constructor, we use the
437/// \c jsonv::extraction_context to access the values of the incoming JSON object in order to build
438/// our object.
439///
440/// \code
441/// static const jsonv::extractor* get_extractor()
442/// {
443/// static jsonv::extractor_construction<my_type> instance;
444/// return &instance;
445/// }
446/// \endcode
447///
448/// A \c jsonv::extractor is a type that knows how to take a \c jsonv::value and create some C++
449/// type out of it. In this case, we are creating a \c jsonv::extractor_construction, which is a
450/// subtype that knows how to call the constructor of a type. There are all sorts of
451/// \c jsonv::extractor implementations in \c jsonv/serialization.hpp, so you should be able to find
452/// one that fits your needs.
453///
454/// \code
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/// \endcode
459///
460/// Now things are starting to get interesting. The \c jsonv::formats object is a collection of
461/// <tt>jsonv::extractor</tt>s, so we create one of our own and add the \c jsonv::extractor* from
462/// the static function of \c my_type. The \c local_formats \e only knows how to extract instances
463/// of \c my_type -- it does \e not know even the most basic things like how to extract an \c int.
464/// We use \c jsonv::formats::compose to create a new instance of \c jsonv::formats that combines
465/// the qualities of \c local_formats (which knows how to deal with \c my_type) and the
466/// \c jsonv::formats::defaults (which knows how to deal with things like \c int and
467/// \c std::string). The \c formats instance now has the power to do everything we need!
468///
469/// \code
470/// my_type x = jsonv::extract<my_type>(val, format);
471/// \endcode
472///
473/// This is not terribly different from the example before, but now we are explicitly passing a
474/// \c jsonv::formats object to the function. If we had not provided \c format as an argument here,
475/// the function would have thrown a \c jsonv::extraction_error complaining about how it did not
476/// know how to extract a \c my_type.
477///
478/// \subsection serialization_to_json Serialization with to_json
479///
480/// JSON Voorhees also allows you to convert from your C++ structures into JSON values, using
481/// \c jsonv::to_json. It should feel like a mirror \c jsonv::extract, with similar argument types
482/// and many shared concepts. Just like extraction, \c jsonv::to_json uses the \c jsonv::formats
483/// class, but it uses a \c jsonv::serializer to convert from C++ into JSON.
484///
485/// \code
486/// #include <jsonv/serialization.hpp>
487/// #include <jsonv/serialization_util.hpp>
488/// #include <jsonv/value.hpp>
489///
490/// #include <iostream>
491///
492/// class my_type
493/// {
494/// public:
495/// my_type(int a, int b, std::string c) :
496/// a(a),
497/// b(b),
498/// c(std::move(c))
499/// { }
500///
501/// static const jsonv::serializer* get_serializer()
502/// {
503/// static auto instance = jsonv::make_serializer<my_type>
504/// (
505/// [] (const jsonv::serialization_context& context, const my_type& self)
506/// {
507/// return jsonv::object({ { "a", context.to_json(self.a) },
508/// { "b", context.to_json(self.b) },
509/// { "c", context.to_json(self.c) }
510/// }
511/// );
512/// }
513/// );
514/// return &instance;
515/// }
516///
517/// private:
518/// int a;
519/// int b;
520/// std::string c;
521/// };
522///
523/// int main()
524/// {
525/// jsonv::formats local_formats;
526/// local_formats.register_serializer(my_type::get_serializer());
527/// jsonv::formats format = jsonv::formats::compose({ jsonv::formats::defaults(), local_formats });
528///
529/// my_type x(5, 6, "Hello");
530/// std::ostream << jsonv::to_json(x, format) << std::endl;
531/// }
532/// \endcode
533///
534/// Output:
535///
536/// \code
537/// {"a":5,"b":6,"c":"Hello"}
538/// \endcode
539///
540/// \subsection serialization_composition Composing Type Adapters
541///
542/// Does all this seem a little bit \e manual to you? Creating an \c extractor and \c serializer for
543/// every single type can get a little bit tedious. Unfortunately, until C++ has a standard way to
544/// do reflection, we must specify the conversions manually. However, there \e is an easier way!
545/// That way is the \ref serialization_builder_dsl "Serialization Builder DSL".
546///
547/// Let's start with a couple of simple structures:
548///
549/// \code
550/// struct foo
551/// {
552/// int a;
553/// int b;
554/// std::string c;
555/// };
556///
557/// struct bar
558/// {
559/// foo x;
560/// foo y;
561/// std::string z;
562/// std::string w;
563/// };
564/// \endcode
565///
566/// Let's make a \c formats for them using the DSL:
567///
568/// \code
569/// jsonv::formats formats =
570/// jsonv::formats_builder()
571/// .type<foo>()
572/// .member("a", &foo::a)
573/// .member("b", &foo::b)
574/// .default_value(10)
575/// .member("c", &foo::c)
576/// .type<bar>()
577/// .member("x", &bar::x)
578/// .member("y", &bar::y)
579/// .member("z", &bar::z)
580/// .since(jsonv::version(2, 0))
581/// .member("w", &bar::w)
582/// .until(jsonv::version(5, 0))
583/// ;
584/// \endcode
585///
586/// What is going on there? The giant chain of function calls is building up a collection of type
587/// adapters into a \c formats for you. The indentation shows the intent -- the
588/// <tt>.member("a", &foo::a)</tt> is attached to the type \c adapter for \c foo (if you tried to
589/// specify \c &bar::y in that same place, it would fail to compile). Each function call returns a
590/// reference back to the builder so you can chain as many of these together as you want to. The
591/// \c jsonv::formats_builder is a proper object, so if you wish to spread out building your type
592/// adapters into multiple functions, you can do that by passing around an instance.
593///
594/// The two most-used functions are \c type and \c member. \c type defines a \c jsonv::adapter for
595/// the C++ class provided at the template parameter. All of the calls before the second \c type
596/// call modify the adapter for \c foo. There, we attach members with the \c member function. This
597/// tells the \c formats how to encode and extract each of the specified members to and from a JSON
598/// object using the provided string as the key. The extra function calls like \c default_value,
599/// \c since and \c until are just a could of the many functions available to modify how the members
600/// of the type get transformed.
601///
602/// The \c formats we built would be perfectly capable of serializing to and extracting from this
603/// JSON document:
604///
605/// \code
606/// {
607/// "x": { "a": 50, "b": 20, "c": "Blah" },
608/// "y": { "a": 10, "c": "No B?" },
609/// "z": "Only serialized in 2.0+",
610/// "w": "Only serialized before 5.0"
611/// }
612/// \endcode
613///
614/// For a more in-depth reference, see the \ref serialization_builder_dsl "Serialization Builder DSL page".
615///
616/// \section demo_algorithm Algorithms
617///
618/// JSON Voorhees takes a "batteries included" approach. A few building blocks for powerful
619/// operations can be found in the \c algorithm.hpp header file.
620///
621/// One of the simplest operations you can perform is the \c map operation. This operation takes in
622/// some \c jsonv::value and returns another. Let's try it.
623///
624/// \code
625/// #include <jsonv/algorithm.hpp>
626/// #include <jsonv/value.hpp>
627///
628/// #include <iostream>
629///
630/// int main()
631/// {
632/// jsonv::value x = 5;
633/// std::cout << jsonv::map([] (const jsonv::value& y) { return y.as_integer() * 2; }, x) << std::endl;
634/// }
635/// \endcode
636///
637/// If everything went right, you should see a number:
638///
639/// \code
640/// 10
641/// \endcode
642///
643/// That is not the most interesting example of using \c map, but it is enough to get the general
644/// idea of what is going on. This operation is so common that it is a member function of \c value
645/// as \c jsonv::value::map. Let's make things a bit more interesting and \c map an \c array...
646///
647/// \code
648/// #include <jsonv/value.hpp>
649///
650/// #include <iostream>
651///
652/// int main()
653/// {
654/// std::cout << jsonv::array({ 1, 2, 3, 4, 5 })
655/// .map([] (const jsonv::value& y) { return y.as_integer() * 2; })
656/// << std::endl;
657/// }
658/// \endcode
659///
660/// Now we're starting to get somewhere!
661///
662/// \code
663/// [2,4,6,8,10]
664/// \endcode
665///
666/// The \c map function maps over whatever the contents of the \c jsonv::value happens to be and
667/// returns something for you based on the \c kind. This simple concept is so ubiquitous that
668/// <a href="http://www.disi.unige.it/person/MoggiE/"> Eugenio Moggi</a> named it a
669/// <a href="http://stackoverflow.com/questions/44965/what-is-a-monad">monad</a>. If you're feeling
670/// adventurous, try using \c map with an \c object or chaining multiple \c map operations together.
671///
672/// Another common building block is the function \c jsonv::traverse. This function walks a JSON
673/// structure and calls a some user-provided function.
674///
675/// \code
676/// #include <jsonv/algorithm.hpp>
677/// #include <jsonv/parse.hpp>
678/// #include <jsonv/value.hpp>
679///
680/// #include <iostream>
681///
682/// int main()
683/// {
684/// jsonv::traverse(jsonv::parse(std::cin),
685/// [] (const jsonv::path& path, const jsonv::value& value)
686/// {
687/// std::cout << path << " => " << value << std::endl;
688/// },
689/// true
690/// );
691/// }
692/// \endcode
693///
694/// Now we have a tiny little program to decompose JSON into <a href="https://jqlang.org/">jq</a>
695/// style path expressions and their values. For example, if you pipe
696/// <tt>{ "bar": [1, 2, 3], "foo": "hello" }</tt> into the program:
697///
698/// \code
699/// .bar[0] => 1
700/// .bar[1] => 2
701/// .bar[2] => 3
702/// .foo => "hello"
703/// \endcode
704///
705/// All of the \e really powerful functions can be found in \c algorithm.hpp. My personal favorite
706/// is \c jsonv::merge. The idea is simple: it merges two (or more) JSON values into one.
707///
708/// \code
709/// #include <jsonv/algorithm.hpp>
710/// #include <jsonv/value.hpp>
711///
712/// #include <iostream>
713///
714/// int main()
715/// {
716/// jsonv::value a = jsonv::object({ { "a", "taco" }, { "b", "cat" } });
717/// jsonv::value b = jsonv::object({ { "c", "burrito" }, { "d", "dog" } });
718/// jsonv::value merged = jsonv::merge(std::move(a), std::move(b));
719/// std::cout << merged << std::endl;
720/// }
721/// \endcode
722///
723/// Output:
724///
725/// \code
726/// {"a":"taco","b":"cat","c":"burrito","d":"dog"}
727/// \endcode
728///
729/// You might have noticed the use of \c std::move into the \c merge function. Like most functions
730/// in JSON Voorhees, \c merge takes advantage of move semantics. In this case, the implementation
731/// will move the contents of the values instead of copying them around. While it may not matter in
732/// this simple case, if you have large JSON structures, the support for movement will save you a
733/// ton of memory.
734///
735/// \see https://github.com/tgockel/json-voorhees
736/// \see http://json.org/
737
738}
739
740#include "algorithm.hpp"
741#include "ast.hpp"
742#include "coerce.hpp"
743#include "config.hpp"
744#include "demangle.hpp"
745#include "encode.hpp"
746#include "forward.hpp"
747#include "functional.hpp"
748#include "kind.hpp"
749#include "parse.hpp"
750#include "parse_index.hpp"
751#include "path.hpp"
752#include "reader.hpp"
753#include "serialization.hpp"
755#include "serialization/all.hpp"
756#include "value.hpp"
757#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.