userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
typed_parser.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/formats/json/parser/typed_parser.hpp
4
/// @brief @copybrief formats::json::parser::TypedParser
5
/// @ingroup userver_universal
6
7
#
include
<
optional
>
8
9
#
include
<
userver
/
formats
/
json
/
parser
/
base_parser
.
hpp
>
10
#
include
<
userver
/
utils
/
assert
.
hpp
>
11
12
USERVER_NAMESPACE_BEGIN
13
14
namespace
formats::
json
::
parser
{
15
16
template
<
typename
T>
17
class
Subscriber
{
18
public
:
19
virtual
~Subscriber() =
default
;
20
21
virtual
void
OnSend(T&&) = 0;
22
};
23
24
template
<
typename
T>
25
class
SubscriberSink
final
:
public
Subscriber
<T> {
26
public
:
27
SubscriberSink(T& data)
28
: data_(data)
29
{}
30
31
void
OnSend(T&& value)
override
{ data_ = std::move(value); }
32
33
private
:
34
T& data_;
35
};
36
37
template
<
typename
T>
38
class
SubscriberSinkOptional
final
:
public
Subscriber
<T>,
public
Subscriber
<std::optional<T>> {
39
public
:
40
SubscriberSinkOptional(std::optional<T>& data)
41
: data_(data)
42
{}
43
44
void
OnSend(T&& value)
override
{ data_ = std::move(value); }
45
46
void
OnSend(std::optional<T>&& value)
override
{ data_ = std::move(value); }
47
48
private
:
49
std::optional<T>& data_;
50
};
51
52
/// @brief Main base class for SAX parsers
53
///
54
/// There are two main groups of SAX parser classes:
55
/// - typed parser
56
/// - proxy parser
57
///
58
/// TypedParser derivative is a parser that handles JSON tokens by itself.
59
/// It implements methods of BaseParser for handling specific tokens (e.g.
60
/// Null(), StartArray(), Double()). Usually parser implements only 1-2 methods
61
/// of BaseParser for handling a fixed set of JSON tokens and leaves default
62
/// implementation for the rest (iow, treat other JSON tokens as a parse error).
63
///
64
/// Parser usually maintains its state as a field(s). Parse methods are called
65
/// when a specific input token is read, and implementation updates the parser
66
/// state. When finished, the parser calls SetResult() with the cooked value. It
67
/// pops current parser from the parser stack and signals the subscriber with
68
/// the result.
69
///
70
/// TypedParser may delegate part of its job to subparsers. It is very common to
71
/// define a parser for an object/array and reuse field parsers for JSON object
72
/// fields parsing. A subparser is usually implemented as a field of a parser
73
/// class. When such parser wants to start subobject parsing, it pushes the
74
/// subparser onto the stack (and maybe calls some of its parse methods).
75
///
76
/// E.g.:
77
///
78
/// ~~~~~~~~~~~~~~{.cpp}
79
/// void SomeParser::Double(double d) {
80
/// subparser_->Reset();
81
/// parser_state_->PushParser(subparser_.GetParser());
82
/// subparser_->Double(d);
83
/// }
84
/// ~~~~~~~~~~~~~~
85
///
86
/// You may also implement a proxy parser. It derives neither from TypedParser
87
/// nor any other userver's parser class. A proxy parser is a class that
88
/// delegates the whole job of input token handling to subparser(s), but somehow
89
/// mutates the result (e.g. converts or validates it) - proxies the result. It
90
/// doesn't implement any JSON token handling methods by itself. Usually proxy
91
/// parser stores a subparser as a field and maybe stores some housekeeping
92
/// settings for result handling.
93
///
94
/// Duck typing is used in proxy parsers to negate virtual methods overhead.
95
/// A proxy parser must implement the following methods:
96
///
97
/// ~~~~~~~~~{.cpp}
98
/// class ProxyParser final
99
/// : public formats::json::parser::Subscriber<Subparser::ResultType> {
100
/// public:
101
/// // Define result type that will be passed to OnSend() of a subscriber
102
/// using ResultType = Result;
103
///
104
/// ProxyParser() {
105
/// // Proxy parser wants to be called when the subparser
106
/// // signals with the result
107
/// subparser.Subscribe(*this);
108
/// }
109
///
110
/// // Reset() of proxy parser MUST call Reset() of subparsers in contrast to
111
/// // a typed parser as a proxy parser doesn't control pushing of subparser
112
/// // onto the stack.
113
/// void Reset() {
114
/// subparser_.Reset();
115
/// }
116
///
117
/// void Subscribe(formats::json::parser::Subscriber<Result>& subscriber) {
118
/// subscriber_ = &subscriber;
119
/// }
120
///
121
/// // The core method of proxy parser. It converts/filters the result value
122
/// // and signals the (maybe mutated) result further to its subscriber.
123
/// void OnSend(Subparser::ResultType&& result) override {
124
/// if (subscriber_) subscriber_->OnSend(Result(std::move(result)));
125
/// }
126
///
127
/// // Returns a typed parser that is responsible for actual JSON parsing.
128
/// auto& GetParser() { return subparser_.GetParser(); }
129
///
130
/// private:
131
/// Subparser subparser_;
132
/// Subscriber* subscriber_{nullptr};
133
/// }
134
/// ~~~~~~~~~
135
///
136
template
<
typename
T>
137
class
TypedParser
:
public
BaseParser
{
138
public
:
139
void
Subscribe(
Subscriber
<T>& subscriber) { subscriber_ = &subscriber; }
140
141
using
ResultType = T;
142
143
/// Resets parser's internal state.
144
/// It should not call Reset() of subparsers (if any).
145
/// Subparsers' Reset() should be called just before pushing it onto the
146
/// stack.
147
virtual
void
Reset
() {}
148
149
/// Returns an actual parser.
150
/// It is commonly used in PushParser() to identify typed parser
151
/// of a proxy parser.
152
TypedParser
<T>&
GetParser
() {
return
*
this
; }
153
154
protected
:
155
void
SetResult(T&& value) {
156
parser_state_->PopMe(*
this
);
157
if
(subscriber_) {
158
subscriber_->OnSend(std::move(value));
159
}
160
}
161
162
private
:
163
Subscriber
<T>* subscriber_{
nullptr
};
164
};
165
166
namespace
impl {
167
168
template
<
typename
Parser>
169
typename
Parser::ResultType ParseSingle(Parser& parser, std::string_view input) {
170
using
ResultType =
typename
Parser::ResultType;
171
ResultType result{};
172
173
parser.Reset();
174
SubscriberSink<ResultType> sink(result);
175
parser.Subscribe(sink);
176
177
ParserState state;
178
state.PushParser(parser.GetParser());
179
state.ProcessInput(input);
180
181
return
result;
182
}
183
184
}
// namespace impl
185
186
template
<
typename
T,
typename
Parser>
187
T ParseToType(std::string_view input) {
188
Parser parser;
189
return
impl::ParseSingle(parser, input);
190
}
191
192
}
// namespace formats::json::parser
193
194
USERVER_NAMESPACE_END
userver
formats
json
parser
typed_parser.hpp
Generated on
for userver by
Doxygen
1.17.0