JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
jsonv::formats Class Reference

Simply put, this class is a collection of deserializer and serializer instances. More...

#include <jsonv/serialization/formats.hpp>

Public Types

using list = std::vector< formats >
 

Public Member Functions

 formats ()
 Create a new, empty formats instance.
 
std::expected< void, ast_node_type > deserialize (const std::type_info &type, reader &from, void *into, deserialization_context &context) const
 Deserialize the provided type from a reader into an area of memory.
 
const deserializer & get_deserializer (std::type_index type) const
 Get the deserializer for the given type.
 
const deserializer & get_deserializer (const std::type_info &type) const
 Get the deserializer for the given type.
 
void serialize (const std::type_info &type, const void *from, writer &to, const serialization_context &context) const
 Write the object of type at from into to.
 
value to_json (const std::type_info &type, const void *from, const serialization_context &context) const
 Encode the provided value from into a JSON value: serialize into a value_encoder.
 
const serializer & get_serializer (std::type_index type) const
 Gets the serializer for the given type.
 
const serializer & get_serializer (const std::type_info &type) const
 Gets the serializer for the given type.
 
void register_deserializer (const deserializer *, duplicate_type_action action=duplicate_type_action::exception)
 Register a deserializer that lives in some unmanaged space.
 
void register_deserializer (std::shared_ptr< const deserializer >, duplicate_type_action action=duplicate_type_action::exception)
 Register a deserializer with shared ownership between this formats instance and anything else.
 
void register_serializer (const serializer *, duplicate_type_action action=duplicate_type_action::exception)
 Register a serializer that lives in some managed space.
 
void register_serializer (std::shared_ptr< const serializer >, duplicate_type_action action=duplicate_type_action::exception)
 Register a serializer with shared ownership between this formats instance and anything else.
 
void register_adapter (const adapter *, duplicate_type_action action=duplicate_type_action::exception)
 Register an adapter that lives in some unmanaged space.
 
void register_adapter (std::shared_ptr< const adapter >, duplicate_type_action action=duplicate_type_action::exception)
 Register an adapter with shared ownership between this formats instance and anything else.
 
bool operator== (const formats &other) const
 Test for equality between this instance and other.
 
bool operator!= (const formats &other) const
 Test for inequality between this instance and other. The opposite of operator==.
 
 formats (const formats &)=default
 Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.
 
 formats (formats &&) noexcept=default
 Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.
 
formats & operator= (const formats &)=default
 Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.
 
formats & operator= (formats &&) noexcept=default
 Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.
 

Static Public Member Functions

static formats defaults ()
 Get the default formats instance.
 
static formats global ()
 Get the global formats instance.
 
static formats set_global (formats)
 Set the global formats instance.
 
static formats reset_global ()
 Reset the global formats instance to defaults.
 
static formats coerce ()
 Get the coercing formats instance.
 
static formats compose (const list &bases)
 Create a new (empty) formats using the bases as backing formats.
 

Detailed Description

Simply put, this class is a collection of deserializer and serializer instances.

Ultimately, formats form a directed graph of possible types to load. This allows you to compose formats including your application with any number of 3rd party libraries an base formats. Imagine an application that has both a user facing API and an object storage system, both of which speak JSON. When loading from the database, you would like strict type enforcement – check that when you say deserialize<int>(val), that val actually has kind::integer. When getting values from the API, you happily convert kind::string with the value "51" into the integer 51. You really don't want to have to write two versions of decoders for all of your objects: one which uses the standard checked value::as_integer and one that uses coerce_integer – you want the same object model.

To do this, you would create your object model (called my_app_formats in the chart) with the object models for your application-specific types. This can use any number of 3rd party libraries to get the job done. To make a functional formats, you would compose different formats instances into a single one. From there,

jsonv::formats get_api_formats()
{
static jsonv::formats instance = jsonv::formats::compose({ jsonv::formats::coerce(), get_app_formats() });
return instance;
}
jsonv::formats get_db_formats()
{
static jsonv::formats instance = jsonv::formats::compose({ jsonv::formats::defaults(), get_app_formats() });
return instance;
}
MyType deserialize_thing(const jsonv::value& from, bool from_db)
{
return jsonv::deserialize<MyType>(from, from_db ? get_db_formats() : get_api_formats());
}
Simply put, this class is a collection of deserializer and serializer instances.
Definition formats.hpp:157
static formats defaults()
Get the default formats instance.
static formats compose(const list &bases)
Create a new (empty) formats using the bases as backing formats.
static formats coerce()
Get the coercing formats instance.
Represents a single JSON value, which can be any one of a potential kind, each behaving slightly diff...
Definition value.hpp:113

Definition at line 156 of file formats.hpp.

Member Typedef Documentation

◆ list

using jsonv::formats::list = std::vector<formats>

Definition at line 159 of file formats.hpp.

Constructor & Destructor Documentation

◆ formats() [1/3]

jsonv::formats::formats ( )

Create a new, empty formats instance.

By default, this does not know how to deserialize anything – not even the basic types like int64_t or std::string.

◆ formats() [2/3]

jsonv::formats::formats ( const formats &  )
default

Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.

Moving transfers the node and leaves the source empty: it finds no deserializer or serializer, a register_ call starts a new node, and compose adds nothing for it. A moved-from formats is equal only to another one in that state, since it is no node in the graph.

◆ formats() [3/3]

jsonv::formats::formats ( formats &&  )
defaultnoexcept

Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.

Moving transfers the node and leaves the source empty: it finds no deserializer or serializer, a register_ call starts a new node, and compose adds nothing for it. A moved-from formats is equal only to another one in that state, since it is no node in the graph.

Member Function Documentation

◆ coerce()

static formats jsonv::formats::coerce ( )
static

Get the coercing formats instance.

This uses loose type-checking and behaves by the same rules as the coerce_ functions in coerce.hpp: a string holding "10" deserializes as the integer 10, an integer deserializes as the string "5", and every kind has a truth value – kind::null's is false. It is composed over defaults, so anything it does not redefine – value and std::string_view among them – behaves as it does there, range checking included.

Note
This function actually returns a copy of the default formats, so modifications do not affect the actual instance.

◆ compose()

static formats jsonv::formats::compose ( const list &  bases)
static

Create a new (empty) formats using the bases as backing formats.

This forms a directed graph of formats objects. When searching for a deserializer or serializer, the formats is searched, then each base is searched depth-first left-to-right.

Parameters
basesIs the list of formats objects to use as bases for the newly-created formats. Order matters – the bases are searched left-to-right, so formats that are farther left take precedence over those more to the right.
Note
It is impossible to form an endless loop of formats objects, since the base of all formats are eventually empty. If there is an existing set of nodes \( k \) and each new format created with compose is in \( k+1 \), there is no way to create a link from \( k \) into \( k+1 \) and so there is no way to create a circuit.

◆ defaults()

static formats jsonv::formats::defaults ( )
static

Get the default formats instance.

This uses strict type-checking and behaves by the same rules as the value as_ member functions (as_integer, as_string, etc): the JSON node has to be the kind the C++ type is built from.

Range is the one place the built-ins are stricter than those accessors. An integer literal which does not fit the destination is reported as a problem rather than read as a std::int64_t and then wrapped into it, so 999 is not a std::uint8_t and -1 is not a std::uint64_t.

A std::string_view is deserialized as a view of the source rather than a copy, so the source has to outlive it: the caller's value for an in-memory deserialization, the JSON text for a reader over one. A string the source spelt with escape sequences has no decoded form in it to view and is refused, as is one belonging to a source which is freed when deserialization finishes – a tree the pipeline materialised, or text handed to jsonv::deserialize to own. See deserialization_context::source_is_temporary.

Note
This function actually returns a copy of the default formats, so modifications do not affect the actual instance.

◆ deserialize()

std::expected< void, ast_node_type > jsonv::formats::deserialize ( const std::type_info &  type,
reader &  from,
void *  into,
deserialization_context &  context 
) const

Deserialize the provided type from a reader into an area of memory.

The context is passed to the deserializer which performs the conversion. In general, this should not be used directly as it is quite painful to do so – prefer deserialization_context::deserialize or the free function jsonv::deserialize.

This only finds the deserializer and calls it. What deserialization_context::deserialize does around that call is skipped: an exception is not recorded as a problem but propagates, and a deserialization started from a hook which can see deserialization_context::source_value or deserialization_context::encoded_source does not have them hidden.

Returns
whatever the located deserializer returned; see deserializer::deserialize.
Exceptions
no_deserializerif a deserializer for type could not be found.

◆ get_deserializer() [1/2]

const deserializer & jsonv::formats::get_deserializer ( const std::type_info &  type) const

Get the deserializer for the given type.

Exceptions
no_deserializerif a deserializer for type could not be found.

◆ get_deserializer() [2/2]

const deserializer & jsonv::formats::get_deserializer ( std::type_index  type) const

Get the deserializer for the given type.

Exceptions
no_deserializerif a deserializer for type could not be found.

◆ get_serializer() [1/2]

const serializer & jsonv::formats::get_serializer ( const std::type_info &  type) const

Gets the serializer for the given type.

Exceptions
no_serializerif a serializer for type could not be found.

◆ get_serializer() [2/2]

const serializer & jsonv::formats::get_serializer ( std::type_index  type) const

Gets the serializer for the given type.

Exceptions
no_serializerif a serializer for type could not be found.

◆ global()

static formats jsonv::formats::global ( )
static

Get the global formats instance.

By default, this is the same as defaults, but you can override it with set_global. The deserialize function uses this formats instance if none is provided, so this is convenient if your application only has one type of formats to use.

Note
This function actually returns a copy of the global formats, so modifications do not affect the actual instance. If you wish to alter the global formats, use set_global.

◆ operator=() [1/2]

formats & jsonv::formats::operator= ( const formats &  )
default

Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.

Moving transfers the node and leaves the source empty: it finds no deserializer or serializer, a register_ call starts a new node, and compose adds nothing for it. A moved-from formats is equal only to another one in that state, since it is no node in the graph.

◆ operator=() [2/2]

formats & jsonv::formats::operator= ( formats &&  )
defaultnoexcept

Copying a formats shares the node in the graph rather than duplicating it, so register_ calls through either one are seen by both.

Moving transfers the node and leaves the source empty: it finds no deserializer or serializer, a register_ call starts a new node, and compose adds nothing for it. A moved-from formats is equal only to another one in that state, since it is no node in the graph.

◆ operator==()

bool jsonv::formats::operator== ( const formats &  other) const

Test for equality between this instance and other.

If two formats are equal, they are the exact same node in the graph. Even if one formats has the exact same types for the exact same deserializers. A moved-from formats is in no node, so it is equal only to another moved-from one.

◆ register_adapter() [1/2]

void jsonv::formats::register_adapter ( const adapter *  ,
duplicate_type_action  action = duplicate_type_action::exception 
)

Register an adapter that lives in some unmanaged space.

Exceptions
duplicate_type_errorif this formats instance already has either a deserializer or serializer that serves the provided adapter::get_type and the duplicate_type_action is exception.

◆ register_adapter() [2/2]

void jsonv::formats::register_adapter ( std::shared_ptr< const adapter >  ,
duplicate_type_action  action = duplicate_type_action::exception 
)

Register an adapter with shared ownership between this formats instance and anything else.

Exceptions
duplicate_type_errorif this formats instance already has either a deserializer or serializer that serves the provided adapter::get_type the duplicate_type_action is exception.

◆ register_deserializer() [1/2]

void jsonv::formats::register_deserializer ( const deserializer *  ,
duplicate_type_action  action = duplicate_type_action::exception 
)

Register a deserializer that lives in some unmanaged space.

Exceptions
duplicate_type_errorif this formats instance already has a deserializer that serves the provided deserializer::get_type and the duplicate_type_action is exception.

◆ register_deserializer() [2/2]

void jsonv::formats::register_deserializer ( std::shared_ptr< const deserializer >  ,
duplicate_type_action  action = duplicate_type_action::exception 
)

Register a deserializer with shared ownership between this formats instance and anything else.

Exceptions
duplicate_type_errorif this formats instance already has a deserializer that serves the provided deserializer::get_type and the duplicate_type_action is exception.

◆ register_serializer() [1/2]

void jsonv::formats::register_serializer ( const serializer *  ,
duplicate_type_action  action = duplicate_type_action::exception 
)

Register a serializer that lives in some managed space.

Exceptions
duplicate_type_errorif this formats instance already has a serializer that serves the provided serializer::get_type and the duplicate_type_action is exception.

◆ register_serializer() [2/2]

void jsonv::formats::register_serializer ( std::shared_ptr< const serializer >  ,
duplicate_type_action  action = duplicate_type_action::exception 
)

Register a serializer with shared ownership between this formats instance and anything else.

Exceptions
duplicate_type_errorif this formats instance already has a serializer that serves the provided serializer::get_type and the duplicate_type_action is exception.

◆ reset_global()

static formats jsonv::formats::reset_global ( )
static

Reset the global formats instance to defaults.

Returns
the previous value of the global formats instance.

◆ serialize()

void jsonv::formats::serialize ( const std::type_info &  type,
const void *  from,
writer &  to,
const serialization_context &  context 
) const

Write the object of type at from into to.

The context is passed to the serializer which performs the conversion. In general, this should not be used directly as it is painful to do so – prefer serialization_context::serialize or the free function jsonv::to_json.

This only finds the serializer and calls it. What serialization_context::serialize does around that call is skipped: an exception which is not a serialization_error propagates as it was thrown rather than being wrapped in one.

Exceptions
no_serializerif a serializer for type could not be found. Its serialization_error::path is to.current_path(), where the value was wanted.

◆ set_global()

static formats jsonv::formats::set_global ( formats  )
static

Set the global formats instance.

Returns
the previous value of the global formats instance.

◆ to_json()

value jsonv::formats::to_json ( const std::type_info &  type,
const void *  from,
const serialization_context &  context 
) const

Encode the provided value from into a JSON value: serialize into a value_encoder.

In general, this should not be used directly – prefer serialization_context::to_json or the free function jsonv::to_json.

Exceptions
no_serializerif a serializer for type could not be found.
std::logic_errorif the serializer wrote nothing or left a structure open, as value_encoder::take does.

The documentation for this class was generated from the following file: