Reader Reader is an incremental parser (also called a pull parser) that transforms the JSON input into a sequence of C++ tokens. This transformation is done piecemeal, which means that the reader will stay at the first token until explicitly instructed to parse the next token. Based on the Iterator design pattern, reader parses just enough of the input to identify a single token. The reader provides various accessors that can be used to examine or convert the current token. Reader Accessors Reader member function Description token::code::value code() Returns the current token. token::symbol::value symbol() Returns the symbol of the current token. token::category::value category() Returns the category of the current token. size_type level() Returns the current level of nested containers. The levels starts with zero for the outmost level. error_code error() Returns the current error code. const view_type& literal() Returns a view of the raw input of the current value. T value<T>() Returns the current value. The raw input is converted into the requested value type. No data is converted until explicitly requested with reader::value<T>(). Notice that the return type for reader::value<T>() must be specified as a template parameter. The return type can be a boolean, a number, or a string as described below. The requested type must match the current token as returned by reader::type(); otherwise a run-time error will be raised. Requesting the value of an incompatible type will result in a run-time error. For example, attempting to read a string as an integer: assert(reader.symbol() == json::symbol::string); int number = reader.value<int>(); // Throws exception Requesting an unsupported type will result in a compile-time error. For example, attempting to read a user-defined struct: struct dummy {}; dummy d = reader.value<dummy>(); // Causes compilation error The unconverted textual data of the current token can be obtained with reader::literal(). This can be useful when displaying errors. The result of reader::literal() is different from reader::value<std::string>(). When you are done with the current token, the next token is found with reader::next(). This function returns a bool, which is true unless either an error or the end of the input was encountered. Whitespaces and separators are skipped. Errors in the input are identified with an error token, and the current error can be obtained with reader::error(). Boolean Boolean values are indicated by the json::symbol::boolean token. The value is requested by reader::value<bool>(). std::string input = "true"; json::reader reader(input); assert(reader.symbol() == json::symbol::boolean); assert(reader.literal() == "true"); assert(reader.value<bool>()); Number While JSON does not distinguish between integer and floating-point numbers, C++ does make this distinction and therefore Trial.Protocol does too. However, integers can be read as floating-point numbers, and floating-point numbers can be read as integers. Reading a floating-point number as an integer will round the number, so it may result in loss of information. Numbers are identified as integers if the consists of digits only. std::string input = "42"; json::reader reader(input); assert(reader.symbol() == json::symbol::integer); assert(reader.literal() == "42"); assert(reader.value<int>() == 42); Numbers are detected as floating-point if they contain a decimal point or an exponent. std::string input = "3.1415"; json::reader reader(input); assert(reader.symbol() == json::symbol::number); assert(reader.literal() == "3.1415"); assert(reader.value<double>() == 3.1415); Integers can be read as floating-point numbers as well. std::string input = "42"; json::reader reader(input); assert(reader.symbol() == json::symbol::integer); assert(reader.value<double>() == 42.0); Floating-point numbers can also be read as integers. The number will be rounded to the nearest integer. std::string input = "3.1415"; json::reader reader(input); assert(reader.symbol() == json::symbol::number); assert(reader.value<int>() == 3); Any kind of additional constraints have to be enforced by the application layer. For instance, if we have a protocol with a size field, then logically this field cannot be negative or a fraction, even if JSON numbers allow this. String Strings are identified with the json::symbol::string token, and is converted into a UTF-8 encoded string with reader::value<std::string>(). std::string input = "\"alpha\\n\""; json::reader reader(input); assert(reader.symbol() == json::symbol::string); assert(reader.literal() == "\"alpha\\n\""); assert(reader.value<std::string>() == "alpha\n"); Null Null indicates the absence of a value, although it is encoded explicitly in the JSON format as the null literal string. std::string input = "null"; json::reader reader(input); assert(reader.symbol() == json::symbol::null); Array Arrays are delimited by a begin-token and an end-token. Array members are comma separated. Arrays can contain any JSON type, including a nested array or a nested associative array. std::string input = "[42]"; json::reader reader(input); assert(reader.symbol() == json::symbol::begin_array); reader.next(); assert(reader.symbol() == json::symbol::integer); assert(reader.value<int>() == 42); reader.next(); assert(reader.symbol() == json::symbol::end_array); Associative array An associative array is called a JSON object, which as a first approximation can be thought of as a std::map in C++.