pub struct Evaluator<L, G> { /* private fields */ }pointer only.Expand description
Evaluates JSON Pointers against a stream of JSON text.
An Evaluator wraps a syntax::Parser in a lightweight, stream-oriented, JSON Pointer
evaluation layer.
§Events
Unlike lexical::Analyzer and syntax::Parser, an evaluator produces Event values
instead of raw lexical tokens.
An Event connects a lexical token with an optional JSON Pointer match event. If [ or {
triggers Event::Enter, all subsequent tokens, until the matching ] or } triggers the
corresponding Event::Exit, are known to be contained within the connected pointer. If a
primitive token triggers Event::Match, that single token matches the paired pointer.
§Escape expansion
Object member name strings can possibly include JSON escape sequences (e.g., \n, \",
\u1234, and so on). When it compares object member names against its JSON Pointer group,
Evaluator can optionally either expand the JSON escape sequences (e.g., \t becomes the tab
character, and so on); or it can do a literal comparison (e.g., \t is treated as the two
characters \ and t). This is controlled by the unescape parameter in new. There is a
slight performance hit for escape expansion.
§Case sensitivity
JSON Pointer evaluation is case-sensitive by default, but it can optionally be switched to
case-insensitive by constructing a case-insensitive pointer group. Refer to the Group
documentation for more.
§Performance considerations
Evaluator is a very lightweight type. Its performance, allocation behavior, and memory
consumption are almost entirely determined by the wrapped parser, which is in turn determined by
the parser’s wrapped lexical analyzer. An evaluator is as performant as its underlying lexer
implementation.
The next method only triggers allocation if:
- The underlying parser’s
nextmethod allocates. - A
{or[in a matchable path causes the parser’s current nesting level to exceed about 3-4. This is only possible for pointers with more than 3 levels (e.g./1/2/3/4) and then only if there is a viable path into such a pointer. - Member name escape expansion is turned on (
unescape=true) and the escape expansion buffer needs to grow. This should be rare in practice, since the buffer is reused.
The next method’s companion methods, next_non_white and next_meaningful have the same
underlying behavior as next.
§Memory considerations
The content method passes through the underlying lexical analyzer’s content. The content
value may contain references to internal buffers that will not be deallocated until the content
value is dropped. Refer to the specific lexical analyzer’s documentation for more.
§Examples
Create an evaluator with new:
use bufjson::{lexical::fixed::FixedAnalyzer, pointer::{Evaluator, Group, Pointer}};
// Create the underlying lexer and parser.
let parser = FixedAnalyzer::new(&b"[1, 2, 3]"[..]).into_parser();
// Create the JSON Pointer group.
let group = Group::from_pointers([Pointer::from_static(""), Pointer::from_static("/1")]);
// Create an evaluator that does expand escape sequences in member names.
let mut evaluator = Evaluator::new(parser, group, /* unescape */ true);
// Use the evaluator...Extract the JSON text that matches the pointer /foo/2.
use bufjson::{lexical::fixed::FixedAnalyzer, pointer::{Evaluator, Event, Group, Pointer}};
// Create the evaluator.
let parser = FixedAnalyzer::new(&br#"{"foo":[null, 1, {"bar":true}]}"#[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static("/foo/2"));
let mut evaluator = Evaluator::new(parser, group, /* unescape */ false);
// Extract the tokens that match.
let mut extract = String::new();
let mut in_match = false;
loop {
let event = evaluator.next();
match event {
Event::Enter(t, _) | Event::Exit(t, _) => {
in_match = event.is_enter();
extract.push_str(&format!("{}", evaluator.content()));
},
_ if in_match && !event.token().is_terminal() => {
extract.push_str(&format!("{}", evaluator.content()));
},
_ if event.token().is_terminal() => break,
_ => (),
}
}
assert_eq!(r#"{"bar":true}"#, extract);Implementations§
Source§impl<L, G> Evaluator<L, G>
impl<L, G> Evaluator<L, G>
Sourcepub fn new(parser: Parser<L>, group: G, unescape: bool) -> Self
pub fn new(parser: Parser<L>, group: G, unescape: bool) -> Self
Constructs a new evaluator wrapping an underlying parser and JSON Pointer group.
The parser and group can be unwrapped using into_parts.
The group can be an owned Group or anything that is AsRef<Group>. Since Group is
immutable, the latter approach allows a single group to be shared across many evaluators.
§Example
use bufjson::{lexical::fixed::FixedAnalyzer, pointer::{Evaluator, Group, Pointer}};
// Create the underlying lexer and parser.
let parser = FixedAnalyzer::new(&b"[1, 2, 3]"[..]).into_parser();
// Create the JSON Pointer group.
let group = Group::from_pointers([Pointer::from_static(""), Pointer::from_static("/1")]);
// Create an evaluator that does expand escape sequences in member names.
let mut evaluator = Evaluator::new(parser, group, /* unescape */ true);
// Use the evaluator...Sourcepub fn next(&mut self) -> Event<&Pointer>
pub fn next(&mut self) -> Event<&Pointer>
Returns the next evaluation event.
The event contains the next syntactically valid lexical token. For enter, exit, and match events it also contains the matched JSON Pointer.
If a lexical or syntax error is detected, the event returned is Event::Nil containing a
Token::Err and the specific error can be obtained from err. Otherwise,
the event contains the next non-error token and the token content can be obtained from
content.
§Example
use bufjson::{lexical::fixed::FixedAnalyzer, pointer::{Evaluator, Event, Group, Pointer}};
// Create the evaluator.
let parser = FixedAnalyzer::new(&br#"{"foo":[null, 1, {"bar":true}]}"#[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static("/foo/2"));
let mut evaluator = Evaluator::new(parser, group, false);
// Extract the tokens that match.
let mut extract = String::new();
let mut in_match = false;
loop {
let event = evaluator.next();
match event {
Event::Enter(t, _) | Event::Exit(t, _) => {
in_match = event.is_enter();
extract.push_str(&format!("{}", evaluator.content()));
},
_ if in_match && !event.token().is_terminal() => {
extract.push_str(&format!("{}", evaluator.content()));
},
_ if event.token().is_terminal() => break,
_ => (),
}
}
assert_eq!(r#"{"bar":true}"#, extract);Sourcepub fn next_non_white(&mut self) -> Event<&Pointer>
pub fn next_non_white(&mut self) -> Event<&Pointer>
Returns the next evaluation event containing a non-whitespace token, i.e. next but
skips whitespace.
This is a convenience method to simplify evaluation in use cases where whitespace does not need to be preserved.
See also next_meaningful.
§Example
use bufjson::{
lexical::{Token, fixed::FixedAnalyzer},
pointer::{Evaluator, Event, Group, Pointer}
};
// Create the evaluator.
let parser = FixedAnalyzer::new(&br#" "hello, world" "#[..]).into_parser();
let root = Pointer::default();
let group = Group::from_pointer(root.clone());
let mut evaluator = Evaluator::new(parser, group, false);
// Get the evaluation events, skipping the leading and trailing whitespace.
assert!(matches!(evaluator.next_non_white(), Event::Match(Token::Str, p) if *p == root));
assert!(matches!(evaluator.next_non_white(), Event::Nil(Token::Eof)));Sourcepub fn next_meaningful(&mut self) -> Event<&Pointer>
pub fn next_meaningful(&mut self) -> Event<&Pointer>
Returns the next evaluation event containing a meaningful token.
This method skips whitespace like next_non_white but also skips past the following
meaningless punctuation characters:
:orToken::NameSep;,orToken::ValueSep.
The colon : and comma , are meaningless because, even though they are required by the
JSON spec (and sometimes necessary for tokenization), they don’t add any meaning to
the stream of lexical tokens.
See also next_non_white.
§Example
use bufjson::{
lexical::{Token, fixed::FixedAnalyzer},
pointer::{Evaluator, Event, Group, Pointer}
};
// Create the evaluator.
let parser = FixedAnalyzer::new(&br#" {"foo": "bar"} "#[..]).into_parser();
let ptr = Pointer::from_static("/foo");
let group = Group::from_pointer(ptr.clone());
let mut evaluator = Evaluator::new(parser, group, false);
// Get the evaluation events, skipping meaningless tokens.
assert!(matches!(evaluator.next_meaningful(), Event::Nil(Token::ObjBegin))); // {
assert!(matches!(evaluator.next_meaningful(), Event::Nil(Token::Str))); // "foo"
assert!( // "bar"
matches!(evaluator.next_meaningful(),
Event::Match(Token::Str, p) if *p == ptr)
);
assert!(matches!(evaluator.next_meaningful(), Event::Nil(Token::ObjEnd))); // }
assert!(matches!(evaluator.next_meaningful(), Event::Nil(Token::Eof)));Sourcepub fn content(&self) -> L::Content
pub fn content(&self) -> L::Content
Fetches the text content for the current non-error token.
The current token is the token contained in the event most recently returned by next,
next_non_white, or next_meaningful.
This method does not allocate unless the underlying lexical analyzer’s try_content
method allocates.
§Panics
Panics if the current token is Token::Err.
§Example
use bufjson::{
lexical::{Token, fixed::FixedAnalyzer},
pointer::{Evaluator, Event, Group, Pointer}
};
let parser = FixedAnalyzer::new(&b"123"[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static("/foo"));
let mut evaluator = Evaluator::new(parser, group, false);
assert!(matches!(evaluator.next(), Event::Nil(Token::Num)));
assert_eq!("123", evaluator.content().literal());Sourcepub fn err(&self) -> Error
pub fn err(&self) -> Error
Fetches the error value associated with the current error token.
The current token is the token contained in the event most recently returned by next,
next_non_white, or next_meaningful.
§Panics
Panics if the current token is not Token::Err.
§Example
use bufjson::{
lexical::{Token, fixed::FixedAnalyzer},
pointer::{Evaluator, Event, Group, Pointer},
syntax::ErrorKind,
};
let parser = FixedAnalyzer::new(&b"{]"[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static("/foo"));
let mut evaluator = Evaluator::new(parser, group, false);
assert!(matches!(evaluator.next(), Event::Nil(Token::ObjBegin))); // {
assert!(matches!(evaluator.next(), Event::Nil(Token::Err))); // ]
assert!(matches!(evaluator.err().kind(), ErrorKind::Syntax { .. }));Sourcepub fn pos(&self) -> &Pos
pub fn pos(&self) -> &Pos
Returns the position of the current lexical token.
The current token is the token contained in the event most recently returned by next,
next_non_white, or next_meaningful.
Sourcepub fn try_content(&self) -> Result<L::Content, Error>
pub fn try_content(&self) -> Result<L::Content, Error>
Fetches the content or error associated with the current token.
The current token is the token contained in event most recently returned by next,
next_non_white, or next_meaningful.
If the current token is Token::Err, an Err result is returned. Otherwise, an Ok
result containing the text content of the recognized lexical token is returned.
This method does not allocate unless the underlying lexical analyzer’s try_content
method allocates.
§Examples
An Ok value is returned as long as the evaluator isn’t in an error state.
let parser = FixedAnalyzer::new(&b"[123"[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static("/foo"));
let mut evaluator = Evaluator::new(parser, group, false);
assert!(matches!(evaluator.next(), Event::Nil(Token::ArrBegin)));
assert!(matches!(evaluator.next(), Event::Nil(Token::Num)));
assert!(matches!(evaluator.try_content(), Ok(c) if c.literal() == "123"));Once the evaluator detects an error, it will return an Err value describing the error.
use bufjson::{
lexical::{Token, fixed::FixedAnalyzer},
pointer::{Evaluator, Event, Group, Pointer},
syntax::ErrorKind,
};
let parser = FixedAnalyzer::new(&b"[123"[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static("/foo"));
let mut evaluator = Evaluator::new(parser, group, false);
assert!(matches!(evaluator.next(), Event::Nil(Token::ArrBegin)));
assert!(matches!(evaluator.next(), Event::Nil(Token::Num)));
assert!(matches!(evaluator.next(), Event::Nil(Token::Err)));
let error_kind = evaluator.try_content().unwrap_err().kind().clone();
assert!(matches!(error_kind, ErrorKind::Syntax { context: _, token: Token::Eof }));Sourcepub fn context(&self) -> &Context
pub fn context(&self) -> &Context
Returns the current parse context, which includes the nesting state and next expected token.
Refer to the Parser::context documentation for more.
Sourcepub fn level(&self) -> usize
pub fn level(&self) -> usize
Returns the current nesting level of the parse.
This is a convenience method that returns the level of the parse context obtainable via the
context method.
Sourcepub fn into_parts(self) -> (Parser<L>, G)
pub fn into_parts(self) -> (Parser<L>, G)
Returns the contained parser and JSON Pointer group, consuming the self value.
§Examples
use bufjson::{
lexical::{Token, fixed::FixedAnalyzer},
pointer::{Evaluator, Event, Group, Pointer}
};
// Create the evaluator.
let parser = FixedAnalyzer::new(&b"{}"[..]).into_parser();
let group = Group::from_pointer(Pointer::from_static(""));
let mut evaluator = Evaluator::new(parser, group, false);
// Read next event from evaluator.
assert!(matches!(evaluator.next(), Event::Enter(Token::ObjBegin, _)));
// Unwrap the parser and group.
let (parser, group) = evaluator.into_parts();
// Continue working with the parser and group...Auto Trait Implementations§
impl<L, G> Freeze for Evaluator<L, G>
impl<L, G> !RefUnwindSafe for Evaluator<L, G>
impl<L, G> Send for Evaluator<L, G>
impl<L, G> Sync for Evaluator<L, G>
impl<L, G> Unpin for Evaluator<L, G>
impl<L, G> UnsafeUnpin for Evaluator<L, G>where
L: UnsafeUnpin,
G: UnsafeUnpin,
impl<L, G> !UnwindSafe for Evaluator<L, G>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.