JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
optional_adapter.hpp
Go to the documentation of this file.
1/// \file jsonv/serialization/optional_adapter.hpp
2///
3/// Copyright (c) 2017-2026 by Travis Gockel. All rights reserved.
4///
5/// This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
6/// as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
7/// version.
8///
9/// \author Travis Gockel (travis@gockelhut.com)
10#pragma once
11
12#include <jsonv/ast.hpp>
13#include <jsonv/config.hpp>
14#include <jsonv/kind.hpp>
15#include <jsonv/optional.hpp>
16#include <jsonv/reader.hpp>
18
19#include <expected>
20#include <utility>
21
22#include "adapter_for.hpp"
23
24namespace jsonv
25{
26
27/// \addtogroup Serialization
28/// \{
29
30/// An adapter for optional-like types. This is for convenience of creating an \c adapter for things like
31/// \c std::optional or \c boost::optional.
32///
33/// \tparam TOptional The optional container type. It must have a member type named \c value_type which holds the
34/// actual type. It must default-construct to the "none" type and have a single-argument constructor which takes a
35/// \c TOptional::value_type. It must support a boolean conversion operator for checking if the value is none and a
36/// unary \c operator* for getting the underlying value. Both \c std::optional and \c boost::optional possess all of
37/// these properties.
38template <typename TOptional>
40 public adapter_for<TOptional>
41{
42 using element_type = typename TOptional::value_type;
43
44protected:
46 virtual std::expected<TOptional, ast_node_type> create(extraction_context& context, reader& from) const override
47 {
48 // A value-backed reader renders a non-finite `kind::decimal` as `literal_null`, because the token it writes
49 // has nowhere to put one -- that is what encoding the value produces, not what the tree holds. Where there is
50 // a `value` to ask, its `kind` decides and the rendering does not, which is the same rule the numeric
51 // extractors follow for the same reason.
53 bool none = lent ? lent->kind() == jsonv::kind::null
54 : from.current_type() == ast_node_type::literal_null;
55
56 // Everything past here steps the cursor before it builds anything, so a `TOptional` which refuses -- its
57 // default constructor for the `null` case, its converting one for the other -- fails with the value behind
58 // it rather than in front of it. Saying so is what stops whatever recovers from this skipping the following
59 // sibling as well, and is where the failure gets its location from.
60 try
61 {
62 if (none)
63 {
64 (void) from.next_token();
65 return TOptional();
66 }
67
68 auto element = context.extract<element_type>(from);
69 if (!element)
70 return std::unexpected(element.error());
71
72 return TOptional(*std::move(element));
73 }
74 catch (...)
75 {
76 context.note_value_consumed(from);
77 throw;
78 }
79 }
80
82 virtual value to_json(const serialization_context& context, const TOptional& from) const override
83 {
84 if (from)
85 return context.to_json(*from);
86 else
87 return value();
88 }
89};
90
91/// \}
92
93}
Copyright (c) 2015-2026 by Travis Gockel.
Utilities for directly dealing with a JSON AST.
An adapter for the type T.
Provides extra information to routines used for extraction and serialization.
Definition context.hpp:26
Provides extra information to routines used for extraction, collects the problems they encounter,...
Definition extract.hpp:391
An adapter for optional-like types.
virtual std::expected< TOptional, ast_node_type > create(extraction_context &context, reader &from) const override
Create an instance of T by reading from.
A reader instance reads from some form of JSON source (probably a string) and converts it into a JSON...
Definition reader.hpp:104
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...
Definition value.hpp:113
Copyright (c) 2014-2020 by Travis Gockel.
#define JSONV_NODISCARD
Warn if the caller discards the result of this function.
Definition config.hpp:132
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.
Definition optional.hpp:239
Read a JSON AST.
Conversion between C++ types and JSON values.