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_othersrule is used with thebson::parse::docrule 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_ruleinstances.
-
template<typename T, rule<T> R = just_accept>
auto bson::parse::type( - R &&rule = {},
Create a
type_rulerule for the typeTand the parsing rulerule. If noruleis 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
Fwith 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
Tshould usually be an lvalue reference. IfTis 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_viewto 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
keyand 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
anyrule immediately accepts or errors. If all sub-rules reject, thenanywill 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
Rsis 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, thenallwill 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
Rshave 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
mustrule that wraps a rule \(R_1\), let \(R_1\) take the place of \(R\) in the following steps (unwraps amustrule:mustis 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_othersshould only be used as the final rule indoc, otherwise subsequent rules will be unreachable)If \(R\) rejects \(E\), continue.
(If no rule in
Rsaccepted or errored on \(E\), then \(E\) will just be ignored.)
Finally, for each rule \(R\) in
Rs:If \(R\) is a
mustrule and it did not accept any element in \(D\), reject \(D\) completely.
Note
If any other rule in
Rsdid not match anything in \(D\), the rule is silently ignored.Note
If
reject_othersis 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
valueusingrule. If the parser rejects or errors, throws astd::system_errorwithEPROTOcontaining 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
reswhich was returned by a parse rule.
Low-Level Concepts#
-
template<typename R, typename Arg>
concept bson::parse::rule# A type
Tsatisfies the requirements forruleif it is invocable with anArginstance and such an invocation returns a type that satisfiesresult_type.