Declaratively Parsing BSON Objects#
amongoc
’s BSON library contains a submodule for declaratively decomposing
BSON values and heirarchies declaratively.
High-Level Constructs#
Parse State#
A parse rule has one of three result states after being tested on a value:
- acceptance
The rule successfully parsed the given value.
- local error / soft failure / reject
The rule rejects the given value. This will not necessarily reject the entire value.
- global error / hard failure / error
The rule rejects the given value, and all parent rules should reject immediately.
Parser Rules#
-
struct bson::parse::just_accept#
-
struct bson::parse::just_reject#
-
struct bson::parse::reject_others#
These special rules will parse anything and immediately accept or reject, respectively.
These are useful e.g. to test for the existence/absence of a document element without inspecting its value.
The
reject_others
rule is used with thebson::parse::doc
rule combinator to enforce that the document does not contain any elements that were otherwise unexpected.
-
template<typename T, rule<T> R>
struct bson::parse::type_rule# A rule<bson_iterator::reference> that checks that a document elements contains a value convertible to
T
, and that the value matches ruleR
. The wrapped rule will be invoked with the converted instance ofT
.Use the shorthand
bson::parse::type()
to createtype_rule
instances.
-
template<typename T, rule<T> R = just_accept>
auto bson::parse::type( - R &&rule = {},
Create a
type_rule
rule for the typeT
and the parsing rulerule
. If norule
is given, then the type rule will simply check the type without inspecting the value.
-
template<typename F>
struct bson::parse::action# A parser rule that executes the function
F
with the value being inspected. Always accepts its argument
-
template<typename T>
struct bson::parse::store# A parser rule that stores its operand in a target. The type
T
should usually be an lvalue reference. IfT
is not just abson_iterator::reference
, then the rule will also check that the operand is of the correct type.Upon storing, accepts.
-
template<typename R>
struct bson::parse::must# A special rule combinator that upgrades parse rejections to parse errors. If the wrapped rule rejects, then the resulting error becomes a global failure.
Note
This rule has special meaning when used with
doc
-
template<rule<bson_iterator::reference> R>
struct bson::parse::field# Searches for an element within a document with the given key and matching the given rule
R
. This rule can be invoked with either an element reference to test a single element, or abson_view
to search for an element with the expected key.-
field(std::string_view key, R r)#
Construct a field rule that searches for an element with
key
and matching the ruler
.
-
field(std::string_view key, R r)#
-
template<typename ...Rs>
struct bson::parse::any# A special rule combinator that accepts if any of its sub-rules accepts. Each sub-rule is tried in the order they are given. This is a short-circuiting operation: When any sub-rule accepts or errors, then the
any
rule immediately accepts or errors. If all sub-rules reject, thenany
will also reject.A generated rejection message will explain why each sub-rule was rejected.
-
template<typename ...Rs>
struct bson::parse::all# A rule combinator that accepts only if all of its sub-rules accept. Each sub-rule in
Rs
is tried in the order they are given as arguments. The operation is short-circuiting: If any sub-rule rejects or errors, no subsequent rules will be attempted. If any sub-rules rejects, thenall
will also reject.
-
template<rule<reference> R>
struct bson::parse::each# A rule combinator for arrays or documents treated as an array of elements.
For each element, tests the given rule. Stops and rejects if any sub-rule rejects.
-
template<typename R>
struct bson::parse::maybe# A rule combinator that accepts if the inner rule does not generate a hard failure.
-
template<rule<reference>... Rs>
struct bson::parse::doc# A parsing rule that expects a document or array and decomposes it according to the rules
Rs
.Given a document or array \(D\):
For each element \(E\) in \(D\):
If all rules in
Rs
have accepted an element, accept \(D\) and stop (parsing stops once all rules are satisfied)For each rule \(R\) in
Rs
:If \(R\) has already accepted any previous element, skip \(R\) (a rule will only be tried until it accepts at most once).
If \(R\) is a
must
rule that wraps a rule \(R_1\), let \(R_1\) take the place of \(R\) in the following steps (unwraps amust
rule:must
is handled after the full loop over \(D\)).If \(R\) accepts \(E\), skip to the next element in \(D\) and restart the loop over
Rs
.If \(R\) errors on \(E\), error on \(D\) and stop.
If \(R\) is
reject_others
, reject \(D\) and stop. (reject_others
should only be used as the final rule indoc
, otherwise subsequent rules will be unreachable)If \(R\) rejects \(E\), continue.
(If no rule in
Rs
accepted or errored on \(E\), then \(E\) will just be ignored.)
Finally, for each rule \(R\) in
Rs
:If \(R\) is a
must
rule and it did not accept any element in \(D\), reject \(D\) completely.
Note
If any other rule in
Rs
did not match anything in \(D\), the rule is silently ignored.Note
If
reject_others
is not present in the ruleset, unmatched elements are silently ignored.
Utilities#
-
template<typename T, rule<T> R>
void bson::parse::must_parse(
)# Attempt to parse
value
usingrule
. If the parser rejects or errors, throws astd::system_error
withEPROTO
containing the error message string describing the failure.
-
template<result_type Res>
std::string bson::parse::describe_error( - const Res &res,
Generate a string that describes the result
res
which was returned by a parse rule.
Low-Level Concepts#
-
template<typename R, typename Arg>
concept bson::parse::rule# A type
T
satisfies the requirements forrule
if it is invocable with anArg
instance and such an invocation returns a type that satisfiesresult_type
.