78template <
typename TPo
inter>
95 emplace_subtype<T>(std::move(pred),
false);
102 template <
typename T>
104 value expected_value,
107 std::type_index tidx = std::type_index(
typeid(T));
108 if (!_serialization_actions.emplace(tidx, std::make_tuple(key, expected_value, action)).second)
112 _discriminator_keys.insert(key);
114 match_predicate op = [key = std::move(key), expected_value = std::move(expected_value)]
121 && iter->second == expected_value;
123 emplace_subtype<T>(std::move(op),
true);
132 _check_null_input = on;
138 return _check_null_input;
147 _check_null_output = on;
153 return _check_null_output;
164 if (_check_null_input && (lent ? lent->kind() == jsonv::kind::null
178 context.note_value_consumed(from);
186 std::optional<value> members;
187 std::optional<value> whole;
188 auto subject = [&] (
const subtype& sub) ->
const value&
195 if (sub.keyed && !whole)
198 members.
emplace(detail::peek_members(
context, from, _discriminator_keys));
203 whole.emplace(detail::peek_value(
context, from));
207 const subtype* chosen =
nullptr;
212 std::optional<detail::temporary_source_scope> temporary;
216 for (
const auto& sub : _subtypes)
218 if (sub.predicate(
context, subject(sub)))
229 return chosen->create(
context, from);
233 std::string message =
"No discriminators matched JSON value";
236 const value& unmatched = lent ? *lent
243 return context.problem(
context.problem_path(from), std::move(message));
249 if (_check_null_output && !from)
252 value serialized =
context.to_json(
typeid(*from),
static_cast<const void*
>(&*from));
254 auto action_iter = _serialization_actions.find(std::type_index(
typeid(*from)));
255 if (action_iter != _serialization_actions.end())
259 return " polymorphic_adapter<" +
demangle(
typeid(TPointer).name()) +
">"
260 "subtype(" +
demangle(
typeid(*from).name()) +
")";
263 const std::string& key = std::get<0>(action_iter->second);
264 const value& val = std::get<1>(action_iter->second);
273 throw std::runtime_error(
"Expected keyed subtype to serialize as an object." + errmsg());
274 if (!serialized.
count(key))
275 throw std::runtime_error(
"Expected subtype key not found." + errmsg());
276 if (serialized.
at(key) != val)
277 throw std::runtime_error(
"Expected subtype key is not the expected value." + errmsg());
281 throw std::runtime_error(
"Expected keyed subtype to serialize as an object." + errmsg());
282 if (serialized.
count(key))
283 throw std::runtime_error(
"Subtype key already present when trying to insert." + errmsg());
284 serialized[key] = val;
287 throw std::runtime_error(
"Unknown keyed_subtype_action.");
295 using create_function = std::function<std::expected<TPointer, ast_node_type> (extraction_context&, reader&)>;
299 match_predicate predicate;
303 create_function create;
306 template <
typename T>
307 void emplace_subtype(match_predicate pred,
bool keyed)
309 _subtypes.push_back(subtype{ std::move(pred),
311 [] (extraction_context& context, reader& from)
312 -> std::expected<TPointer, ast_node_type>
320 auto extracted = context.extract<T>(from);
322 return std::unexpected(extracted.error());
324 return TPointer(
new T(*std::move(extracted)));
328 context.note_value_consumed(from);
337 using serialization_action = std::tuple<std::string, value, keyed_subtype_action>;
339 std::vector<subtype> _subtypes;
340 std::set<std::string, std::less<>> _discriminator_keys;
341 std::map<std::type_index, serialization_action> _serialization_actions;
342 bool _check_null_input =
false;
343 bool _check_null_output =
false;
Copyright (c) 2015-2026 by Travis Gockel.
An adapter for the type T.
Provides extra information to routines used for extraction and serialization.
Exception thrown if an insertion of an extractor or serializer into a formats is attempted,...
An adapter which can create polymorphic types.
void add_subtype_keyed(std::string key, value expected_value, keyed_subtype_action action=keyed_subtype_action::none)
Add a subtype which can be transformed into TPointer which will be called if given a JSON value with ...
bool check_null_output() const
When converting with to_json, should a null input translate into a kind::null?
virtual std::expected< TPointer, ast_node_type > create(extraction_context &context, reader &from) const override
Create an instance of T by reading from.
bool check_null_input() const
When extracting a C++ value, should kind::null in JSON automatically become a default-constructed TPo...
void check_null_output(bool on)
When converting with to_json, should a null input translate into a kind::null?
void check_null_input(bool on)
When extracting a C++ value, should kind::null in JSON automatically become a default-constructed TPo...
void add_subtype(match_predicate pred)
Add a subtype which can be transformed into TPointer which will be called if the discriminator pred i...
A reader instance reads from some form of JSON source (probably a string) and converts it into a JSON...
ast_node_type current_type() const
Get the type of the current AST node, which is always current().type().
bool next_token() noexcept
Go to the next token.
optional< const value & > current_value() const noexcept
Get the in-memory value this reader is positioned on, if it has one to lend.
Represents a single JSON value, which can be any one of a potential kind, each behaving slightly diff...
size_type count(const std::string &key) const
Check if the given key exists in this object.
object_iterator end_object()
Get an iterator to the one past the end of this object.
object_iterator find(const std::string &key)
Attempt to locate a key-value pair with the provided key in this object.
value & at(size_type idx)
Get the value in this array at the given idx.
std::pair< object_iterator, bool > emplace(std::string key, value val)
Construct an element from key and val and insert it into this object.
bool is_object() const
Tests if this kind is kind::object.
Copyright (c) 2014-2020 by Travis Gockel.
Copyright (c) 2015 by Travis Gockel.
#define JSONV_NODISCARD
Warn if the caller discards the result of this function.
JSONV_PUBLIC std::string demangle(std::string_view source)
Convert the input source from a mangled type into a human-friendly version.
keyed_subtype_action
What to do when serializing a keyed subtype of a polymorphic_adapter.
@ check
Ensure the correct key/value pair was inserted by serialization. Throws std::runtime_error if it wasn...
@ none
Don't do any checking or insertion of the expected key/value pair.
@ insert
Insert the correct key/value pair as part of serialization.
JSONV_PUBLIC std::string to_string(const ast_node_type &type)
Get what operator<< writes for type as a std::string.
JSONV_PUBLIC const value null
An instance with kind::null.
Copyright (c) 2019-2020 by Travis Gockel.
Pulls in an implementation of optional.
typename detail::optional_type< T >::type optional
Represents a value that may or may not be present.
Conversion between C++ types and JSON values.