rsonpath_syntax/
lib.rs

1//! Complete, fast, and fully spec-compliant JSONPath query parser.
2//!
3//! The crate exposes the [`JsonPathQuery`] type and the [`parse`](`crate::parse`)
4//! function that converts a query string into the AST representation. The parsing
5//! complies with the proposed [JSONPath RFC specification](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html).
6//!
7//! A JSONPath query is a sequence of **segments**, each containing one or more
8//! **selectors**. There are two types of segments:
9//! - **child** ([`Segment::Child`]), and
10//! - **descendant** ([`Segment::Descendant`]);
11//!
12//! and five different types of selectors:
13//! - **name** ([`Selector::Name`]),
14//! - **wildcard** ([`Selector::Wildcard`]),
15//! - **index** ([`Selector::Index`]),
16//! - **slice** ([`Selector::Slice`]),
17//! - and **filter** ([`Selector::Filter`]).
18//!
19//! Descriptions of each segment and selector can be found in the documentation of the
20//! relevant type in this crate, while the formal grammar is described in the RFC.
21//!
22//! ## State of the crate
23//!
24//! This is an in-development version that does not yet support functions in filter
25//! expressions.
26//! However, all other constructs are fully supported, tested, and fuzzed. The planned roadmap is:
27//! - [x] support slices
28//! - [x] support filters (without functions)
29//! - [ ] support functions (including type check)
30//! - [ ] polish the API
31//! - [ ] 1.0.0 stable release
32//!
33//! ## Examples
34//! To create a query from a query string:
35//! ```
36//! use rsonpath_syntax::prelude::*;
37//! # use std::error::Error;
38//! #
39//! # fn main() -> Result<(), Box<dyn Error>> {
40//! let query_string = "$..phoneNumbers[*].number";
41//! let query = rsonpath_syntax::parse(query_string)?;
42//!
43//! // Query structure is a linear sequence of segments:
44//! // Descendant '..phoneNumbers', child wildcard, child 'number'.
45//! assert_eq!(query.segments().len(), 3);
46//! assert_eq!(
47//!   query.segments()[0],
48//!   Segment::Descendant(
49//!     Selectors::one(
50//!       Selector::Name(
51//!         JsonString::new("phoneNumbers")
52//! ))));
53//! assert_eq!(
54//!   query.segments()[1],
55//!   Segment::Child(
56//!     Selectors::one(
57//!       Selector::Wildcard
58//! )));
59//! assert_eq!(
60//!   query.segments()[2],
61//!   Segment::Child(
62//!     Selectors::one(
63//!       Selector::Name(
64//!         JsonString::new("number")
65//! ))));
66//!
67//! // Queries stringify to a canonical representation.
68//! assert_eq!(query.to_string(), "$..['phoneNumbers'][*]['number']");
69//! # Ok(())
70//! # }
71//! ```
72//!
73//! Constructing queries programmatically is more ergonomic with the provided builder interface.
74//! For example, to construct the same query as above:
75//!
76//! ```rust
77//! use rsonpath_syntax::builder::JsonPathQueryBuilder;
78//!
79//! let mut query_builder = JsonPathQueryBuilder::new();
80//! query_builder
81//!   .descendant_name("phoneNumbers")
82//!   .child_wildcard()
83//!   .child_name("number");
84//! let query = query_builder.into_query();
85//!
86//! assert_eq!(query.to_string(), "$..['phoneNumbers'][*]['number']");
87//! ```
88//!
89//! ## Crate features
90//!
91//! There are two optional features:
92//! - `arbitrary`, which enables a dependency on the [`arbitrary` crate](https://docs.rs/arbitrary/latest/arbitrary/)
93//!   to provide [`Arbitrary`](`arbitrary::Arbitrary`) implementations on query types; this is used e.g. for fuzzing.
94//! - `color`, which enables a dependency on the [`owo_colors` crate](https://docs.rs/owo-colors/latest/owo_colors/)
95//!   to provide colorful [`Display`] representations of [`ParseError`](error::ParseError);
96//!   see [`ParseError::colored`](error::ParseError::colored).
97
98#![forbid(unsafe_code)]
99#![doc(html_logo_url = "https://raw.githubusercontent.com/V0ldek/rsonpath/main/img/rsonquery-logo.svg")]
100// Documentation lints, enabled only on --release.
101#![cfg_attr(
102    not(debug_assertions),
103    warn(missing_docs, clippy::missing_errors_doc, clippy::missing_panics_doc,)
104)]
105#![cfg_attr(not(debug_assertions), warn(rustdoc::missing_crate_level_docs))]
106// Panic-free lints (disabled for tests).
107#![cfg_attr(not(test), warn(clippy::unwrap_used))]
108// IO hygiene, only on --release.
109#![cfg_attr(
110    not(debug_assertions),
111    warn(clippy::print_stderr, clippy::print_stdout, clippy::todo)
112)]
113// Docs.rs config.
114#![cfg_attr(docsrs, feature(doc_cfg))]
115
116pub mod builder;
117pub mod error;
118pub mod num;
119mod parser;
120pub mod prelude;
121pub mod str;
122
123use std::{
124    fmt::{self, Display},
125    ops::Deref,
126};
127
128/// JSONPath query parser.
129#[derive(Debug, Clone, Default)]
130pub struct Parser {
131    options: ParserOptions,
132}
133
134/// Configurable builder for a [`Parser`] instance.
135#[derive(Debug, Clone, Default)]
136pub struct ParserBuilder {
137    options: ParserOptions,
138}
139
140#[derive(Debug, Clone)]
141struct ParserOptions {
142    recursion_limit: Option<usize>,
143    relaxed_whitespace: bool,
144}
145
146impl ParserBuilder {
147    /// Create a new instance of the builder with the default settings.
148    #[inline]
149    #[must_use]
150    pub fn new() -> Self {
151        Self {
152            options: ParserOptions::default(),
153        }
154    }
155
156    /// Override the default recursion limit in a query.
157    /// Defaults to [Parser::RECURSION_LIMIT_DEFAULT].
158    ///
159    /// JSONPath queries are inherently recursive, since
160    /// - [`LogicalExpr`] can be an arbitrarily deep tree of AND/OR operators;
161    /// - the [`TestExpr`] in a filter can test arbitrary nested JSONPath queries.
162    ///
163    /// Our parser implementation is recursive, so an excessively nested query could overflow the stack.
164    ///
165    /// The limit can be relaxed here, or removed entirely by passing [`None`].
166    ///
167    /// ## Examples
168    /// ```
169    /// # use rsonpath_syntax::{JsonPathQuery, Parser, ParserBuilder};
170    /// let default_parser = ParserBuilder::new().build();
171    /// let no_nesting_parser = ParserBuilder::new()
172    ///     .set_recursion_limit(Some(1))
173    ///     .build();
174    ///
175    /// let query = "$[?@[?@]]";
176    /// assert!(default_parser.parse(query).is_ok());
177    /// assert!(no_nesting_parser.parse(query).is_err());
178    /// ```
179    #[inline]
180    pub fn set_recursion_limit(&mut self, value: Option<usize>) -> &mut Self {
181        self.options.recursion_limit = value;
182        self
183    }
184
185    /// Control whether leading and trailing whitespace is allowed in a query.
186    /// Defaults to false.
187    ///
188    /// The [RFC](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html) grammar
189    /// makes leading and trailing whitespace disallowed. The [`Parser`] defaults to this strict handling,
190    /// but can be relaxed with this setting.
191    ///
192    /// ## Examples
193    /// ```
194    /// # use rsonpath_syntax::{JsonPathQuery, Parser, ParserBuilder};
195    /// let default_parser = ParserBuilder::new().build();
196    /// let relaxed_parser = ParserBuilder::new()
197    ///     .allow_surrounding_whitespace(true)
198    ///     .build();
199    ///
200    /// let query = "  $.leading_whitespace";
201    /// assert!(default_parser.parse(query).is_err());
202    /// assert!(relaxed_parser.parse(query).is_ok());
203    /// ```
204    #[inline]
205    pub fn allow_surrounding_whitespace(&mut self, value: bool) -> &mut Self {
206        self.options.relaxed_whitespace = value;
207        self
208    }
209
210    /// Build a new instance of a [`Parser`].
211    #[inline]
212    #[must_use]
213    pub fn build(&self) -> Parser {
214        Parser {
215            options: self.options.clone(),
216        }
217    }
218}
219
220impl ParserOptions {
221    fn is_leading_whitespace_allowed(&self) -> bool {
222        self.relaxed_whitespace
223    }
224
225    fn is_trailing_whitespace_allowed(&self) -> bool {
226        self.relaxed_whitespace
227    }
228}
229
230impl Default for ParserOptions {
231    #[inline(always)]
232    fn default() -> Self {
233        Self {
234            recursion_limit: Some(Parser::RECURSION_LIMIT_DEFAULT),
235            relaxed_whitespace: false,
236        }
237    }
238}
239
240impl From<ParserBuilder> for Parser {
241    #[inline(always)]
242    fn from(value: ParserBuilder) -> Self {
243        Self { options: value.options }
244    }
245}
246
247/// Convenience alias for [`Result`](std::result::Result) values returned by this crate.
248pub type Result<T> = std::result::Result<T, error::ParseError>;
249
250/// Parse a JSONPath query string using default [`Parser`] configuration.
251///
252/// ## Errors
253/// Fails if the string does not represent a valid JSONPath query
254/// as governed by the [JSONPath RFC specification](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html).
255///
256/// Note that leading and trailing whitespace is explicitly disallowed by the spec.
257/// This can be relaxed with a custom [`Parser`] configured with [`ParserBuilder::allow_surrounding_whitespace`].
258///
259/// # Examples
260/// ```
261/// # use rsonpath_syntax::parse;
262/// let x = "  $.a  ";
263/// let err = rsonpath_syntax::parse(x).expect_err("should fail");
264/// assert_eq!(err.to_string(),
265/// "error: query starting with whitespace
266///
267///     $.a  
268///   ^^ leading whitespace is disallowed
269///   (bytes 0-1)
270///
271///
272///error: query ending with whitespace
273///
274///     $.a  
275///        ^^ trailing whitespace is disallowed
276///   (bytes 5-6)
277///
278///
279///suggestion: did you mean `$.a` ?
280///");
281/// ```
282#[inline]
283pub fn parse(str: &str) -> Result<JsonPathQuery> {
284    Parser::default().parse(str)
285}
286
287impl Parser {
288    /// Default limit on the nesting level of a query.
289    ///
290    /// This can be overridden by [`ParserBuilder::set_recursion_limit`].
291    pub const RECURSION_LIMIT_DEFAULT: usize = 128;
292
293    /// Parse a JSONPath query string.
294    ///
295    /// ## Errors
296    /// Fails if the string does not represent a valid JSONPath query
297    /// as governed by the [JSONPath RFC specification](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html).
298    ///
299    /// Note that leading and trailing whitespace is explicitly disallowed by the spec.
300    /// The parser defaults to this strict behavior unless configured with
301    /// [`ParserBuilder::allow_surrounding_whitespace`].
302    ///
303    /// There is a limit on the complexity of the query measured as the depth of nested filter expressions.
304    /// This limit defaults to [`RECURSION_LIMIT_DEFAULT`](Self::RECURSION_LIMIT_DEFAULT) and can be overridden
305    /// with [`ParserBuilder::set_recursion_limit`].
306    #[inline]
307    pub fn parse(&self, str: &str) -> Result<JsonPathQuery> {
308        crate::parser::parse_with_options(str, &self.options)
309    }
310}
311
312/// JSONPath query segment.
313///
314/// Every query is a sequence of zero or more of segments,
315/// each applying one or more selectors to a node and passing it along to the
316/// subsequent segments.
317#[derive(Debug, PartialEq, Eq, Clone, Hash)]
318#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
319#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
320pub enum Segment {
321    /// A child segment contains a sequence of selectors,
322    /// each of which selects zero or more children of a node.
323    Child(Selectors),
324    /// A child segment contains a sequence of selectors,
325    /// each of which selects zero or more descendants of a node.
326    Descendant(Selectors),
327}
328
329// We don't derive this because an empty Vec of Selectors is not a valid representation.
330#[cfg(feature = "arbitrary")]
331#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
332impl<'a> arbitrary::Arbitrary<'a> for Selectors {
333    #[inline]
334    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
335        let first = u.arbitrary::<Selector>()?;
336        let mut rest = u.arbitrary::<Vec<Selector>>()?;
337        rest.push(first);
338
339        Ok(Self::many(rest))
340    }
341}
342
343/// Collection of one or more [`Selector`] instances.
344///
345/// Guaranteed to be non-empty.
346#[derive(Debug, PartialEq, Eq, Clone, Hash)]
347#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
348pub struct Selectors {
349    inner: Vec<Selector>,
350}
351
352/// Each [`Segment`] defines one or more selectors.
353/// A selector produces one or more children/descendants of the node it is applied to.
354#[derive(Debug, PartialEq, Eq, Clone, Hash)]
355#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
356#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
357pub enum Selector {
358    /// A name selector selects at most one object member value under the key equal to the
359    /// selector's [`JsonString`](str::JsonString).
360    Name(str::JsonString),
361    /// A wildcard selector selects the nodes of all children of an object or array.
362    Wildcard,
363    /// An index selector matches at most one array element value,
364    /// depending on the selector's [`Index`].
365    Index(Index),
366    /// A slice selector matches elements from arrays starting at a given index,
367    /// ending at a given index, and incrementing with a specified step.
368    Slice(Slice),
369    /// A filter selector matches members/elements which satisfy the given
370    /// [`LogicalExpr`].
371    Filter(LogicalExpr),
372}
373
374impl From<str::JsonString> for Selector {
375    #[inline]
376    fn from(value: str::JsonString) -> Self {
377        Self::Name(value)
378    }
379}
380
381impl From<Index> for Selector {
382    #[inline]
383    fn from(value: Index) -> Self {
384        Self::Index(value)
385    }
386}
387
388impl From<Slice> for Selector {
389    #[inline]
390    fn from(value: Slice) -> Self {
391        Self::Slice(value)
392    }
393}
394
395impl From<LogicalExpr> for Selector {
396    #[inline]
397    fn from(value: LogicalExpr) -> Self {
398        Self::Filter(value)
399    }
400}
401
402/// Directional index into a JSON array.
403#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
404#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
405pub enum Index {
406    /// Zero-based index from the start of the array.
407    FromStart(num::JsonUInt),
408    /// Index from the end of the array.
409    ///
410    /// `-1` is the last element, `-2` is the second last, etc.
411    FromEnd(num::JsonNonZeroUInt),
412}
413
414// We don't derive this because FromEnd(0) is not a valid index.
415#[cfg(feature = "arbitrary")]
416#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
417impl<'a> arbitrary::Arbitrary<'a> for Index {
418    #[inline]
419    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
420        let num = u.arbitrary::<num::JsonInt>()?;
421        Ok(Self::from(num))
422    }
423}
424
425impl<N: Into<num::JsonInt>> From<N> for Index {
426    #[inline]
427    fn from(value: N) -> Self {
428        let value = value.into();
429        if value.as_i64() >= 0 {
430            Self::FromStart(value.abs())
431        } else {
432            Self::FromEnd(value.abs().try_into().expect("checked for zero already"))
433        }
434    }
435}
436
437/// Directional step offset within a JSON array.
438#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
439#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
440pub enum Step {
441    /// Step forward by a given offset amount.
442    Forward(num::JsonUInt),
443    /// Step backward by a given offset amount.
444    Backward(num::JsonNonZeroUInt),
445}
446
447// We don't derive this because Backward(0) is not a valid step.
448#[cfg(feature = "arbitrary")]
449#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
450impl<'a> arbitrary::Arbitrary<'a> for Step {
451    #[inline]
452    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
453        let num = u.arbitrary::<num::JsonInt>()?;
454        Ok(Self::from(num))
455    }
456}
457
458impl From<num::JsonInt> for Step {
459    #[inline]
460    fn from(value: num::JsonInt) -> Self {
461        if value.as_i64() >= 0 {
462            Self::Forward(value.abs())
463        } else {
464            Self::Backward(value.abs().try_into().expect("checked for zero already"))
465        }
466    }
467}
468
469/// Slice selector defining the start and end bounds, as well as the step value and direction.
470///
471/// The start index is inclusive defaults to `Index::FromStart(0)`.
472///
473/// The end index is exclusive and optional.
474/// If `None`, the end of the slice depends on the step direction:
475/// - if going forward, the end is `len` of the array;
476/// - if going backward, the end is 0.
477///
478/// The step defaults to `Step::Forward(1)`. Note that `Step::Forward(0)` is a valid
479/// value and is specified to result in an empty slice, regardless of `start` and `end`.
480///
481/// # Examples
482/// ```
483/// # use rsonpath_syntax::{Slice, Index, Step, num::JsonUInt};
484/// let slice = Slice::default();
485/// assert_eq!(slice.start(), Index::FromStart(JsonUInt::ZERO));
486/// assert_eq!(slice.end(), None);
487/// assert_eq!(slice.step(), Step::Forward(JsonUInt::ONE));
488/// ```
489#[derive(Debug, PartialEq, Eq, Clone, Hash)]
490#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
491#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
492pub struct Slice {
493    start: Index,
494    end: Option<Index>,
495    step: Step,
496}
497
498impl Slice {
499    pub(crate) const DEFAULT_START_FORWARDS: Index = Index::FromStart(num::JsonUInt::ZERO);
500    /// This is not const because the required NonZeroU64::MIN is from Rust 1.70.
501    #[inline(always)]
502    pub(crate) fn default_start_backwards() -> Index {
503        Index::FromEnd(1.try_into().expect("const 1 is nonzero"))
504    }
505    pub(crate) const DEFAULT_STEP: Step = Step::Forward(num::JsonUInt::ONE);
506
507    /// Create a new [`Slice`] from given bounds and step.
508    #[inline(always)]
509    #[must_use]
510    pub fn new(start: Index, end: Option<Index>, step: Step) -> Self {
511        Self { start, end, step }
512    }
513
514    /// Get the start index of the [`Slice`].
515    #[inline(always)]
516    #[must_use]
517    pub fn start(&self) -> Index {
518        self.start
519    }
520
521    /// Get the end index of the [`Slice`].
522    #[inline(always)]
523    #[must_use]
524    pub fn end(&self) -> Option<Index> {
525        self.end
526    }
527
528    /// Get the step of the [`Slice`].
529    #[inline(always)]
530    #[must_use]
531    pub fn step(&self) -> Step {
532        self.step
533    }
534}
535
536impl Default for Slice {
537    #[inline]
538    fn default() -> Self {
539        Self {
540            start: Index::FromStart(0.into()),
541            end: None,
542            step: Step::Forward(1.into()),
543        }
544    }
545}
546
547/// JSON literal value available in comparison expressions of a filter selector.
548#[derive(Debug, PartialEq, Eq, Clone, Hash)]
549#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
550#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
551pub enum Literal {
552    /// [`JsonString`](str::JsonString) literal.
553    String(str::JsonString),
554    /// [`JsonNumber`](num::JsonNumber) literal &ndash;
555    /// an integer or a floating point value.
556    Number(num::JsonNumber),
557    /// Boolean JSON value &ndash; `true`` or `false`.
558    Bool(bool),
559    /// The `null` JSON literal value.
560    Null,
561}
562
563impl<S> From<S> for Literal
564where
565    S: Into<str::JsonString>,
566{
567    #[inline(always)]
568    fn from(value: S) -> Self {
569        Self::String(value.into())
570    }
571}
572
573impl From<num::JsonInt> for Literal {
574    #[inline(always)]
575    fn from(value: num::JsonInt) -> Self {
576        Self::Number(num::JsonNumber::Int(value))
577    }
578}
579
580impl From<num::JsonFloat> for Literal {
581    #[inline(always)]
582    fn from(value: num::JsonFloat) -> Self {
583        Self::Number(num::JsonNumber::Float(value))
584    }
585}
586
587impl From<num::JsonNumber> for Literal {
588    #[inline(always)]
589    fn from(value: num::JsonNumber) -> Self {
590        Self::Number(value)
591    }
592}
593
594impl From<bool> for Literal {
595    #[inline(always)]
596    fn from(value: bool) -> Self {
597        Self::Bool(value)
598    }
599}
600
601/// Logical expression used in a [`Filter`](Selector::Filter) selector.
602///
603/// Expressions form a tree, where [`Comparison`](LogicalExpr::Comparison)
604/// and [`Test`](LogicalExpr::Test) expressions can be leaves, and boolean combinators
605/// (OR, AND, NOT) store their children as [`Boxes`](Box).
606#[derive(Debug, PartialEq, Eq, Clone, Hash)]
607#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
608#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
609pub enum LogicalExpr {
610    /// Logical disjunction of two child expressions.
611    Or(LogicalExprNode, LogicalExprNode),
612    /// Logical conjunction of two child expressions.
613    And(LogicalExprNode, LogicalExprNode),
614    /// Logical negation of a child expression.
615    Not(LogicalExprNode),
616    /// Comparison expression &ndash; compare single values determined
617    /// by query or a literal constant.
618    Comparison(ComparisonExpr),
619    /// Existence test &ndash; query and see if any matched nodes exist.
620    Test(TestExpr),
621}
622
623impl LogicalExpr {
624    fn precedence(&self) -> usize {
625        match self {
626            Self::Or(_, _) => 2,
627            Self::And(_, _) => 3,
628            Self::Comparison(_) => 4,
629            Self::Not(_) => 5,
630            Self::Test(_) => 10,
631        }
632    }
633}
634
635type LogicalExprNode = Box<LogicalExpr>;
636
637/// Existence test based on a relative or absolute [`JsonPathQuery`].
638#[derive(Debug, PartialEq, Eq, Clone, Hash)]
639#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
640#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
641pub enum TestExpr {
642    /// Relative test &ndash; query from the selected node.
643    Relative(JsonPathQuery),
644    /// Absolute test &ndash; query from the document root.
645    Absolute(JsonPathQuery),
646}
647
648/// Comparison based on two singular values and a comparison operator.
649///
650/// # Examples
651/// ```rust
652/// # use rsonpath_syntax::{ComparisonExpr, Comparable, ComparisonOp, Literal, SingularJsonPathQuery};
653/// let lhs = Comparable::from(Literal::from("abc"));
654/// let rhs = Comparable::RelativeSingularQuery(
655///     SingularJsonPathQuery::from_iter(vec![])
656/// );
657/// let comparison = ComparisonExpr::from_parts(
658///     lhs.clone(),
659///     ComparisonOp::EqualTo,
660///     rhs.clone());
661///
662/// assert_eq!(&lhs, comparison.lhs());
663/// assert_eq!(ComparisonOp::EqualTo, comparison.op());
664/// assert_eq!(&rhs, comparison.rhs());
665/// ```
666#[derive(Debug, PartialEq, Eq, Clone, Hash)]
667#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
668#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
669pub struct ComparisonExpr {
670    lhs: Comparable,
671    op: ComparisonOp,
672    rhs: Comparable,
673}
674
675impl ComparisonExpr {
676    /// Get the comparable left-hand side of the comparison operation.
677    #[inline]
678    #[must_use]
679    pub fn lhs(&self) -> &Comparable {
680        &self.lhs
681    }
682
683    /// Get the comparison operator.
684    #[inline]
685    #[must_use]
686    pub fn op(&self) -> ComparisonOp {
687        self.op
688    }
689
690    /// Get the comparable right-hand side of the comparison operation.
691    #[inline]
692    #[must_use]
693    pub fn rhs(&self) -> &Comparable {
694        &self.rhs
695    }
696
697    /// Construct a [`ComparisonExpr`] from its constituent parts.
698    #[inline]
699    #[must_use]
700    pub fn from_parts(lhs: Comparable, op: ComparisonOp, rhs: Comparable) -> Self {
701        Self { lhs, op, rhs }
702    }
703}
704
705/// Comparison operator usable in a [`ComparisonExpr`].
706#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
707#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
708#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
709pub enum ComparisonOp {
710    /// Compares two values for equality; `==`
711    EqualTo,
712    /// Compares two values for non-equality; `!=`
713    NotEqualTo,
714    /// Compares whether the lhs is smaller or equal to rhs; '<='
715    LesserOrEqualTo,
716    /// Compares whether the lhs is bigger or equal to rhs; '>='
717    GreaterOrEqualTo,
718    /// Compares whether the lhs is smaller than rhs; '<'
719    LessThan,
720    /// Compares whether the lhs is bigger than rhs; '>'
721    GreaterThan,
722}
723
724/// One of the sides of a [`ComparisonExpr`], either a constant literal or a singular JSONPath query.
725#[derive(Debug, PartialEq, Eq, Clone, Hash)]
726#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
727#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
728pub enum Comparable {
729    /// Constant [`Literal`] value.
730    Literal(Literal),
731    /// Single value queried from the current node.
732    RelativeSingularQuery(SingularJsonPathQuery),
733    /// Single value queried from the JSON root.
734    AbsoluteSingularQuery(SingularJsonPathQuery),
735}
736
737impl From<Literal> for Comparable {
738    #[inline(always)]
739    fn from(value: Literal) -> Self {
740        Self::Literal(value)
741    }
742}
743
744/// Singular JSONPath query.
745///
746/// A singular JSONPath query returns at most one value, and can be used in
747/// [`ComparisonExprs`](ComparisonExpr) as any of the comparison sides.
748///
749/// This is guaranteed syntactically &ndash; only child name and index selectors are allowed
750/// in a [`SingularJsonPathQuery`], which naturally matches only the precise specified path,
751/// if it exists.
752#[derive(Debug, PartialEq, Eq, Clone, Hash)]
753#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
754#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
755pub struct SingularJsonPathQuery {
756    segments: Vec<SingularSegment>,
757}
758
759impl SingularJsonPathQuery {
760    /// Iterate over the [`SingularSegments`](SingularSegment) of this query.
761    #[inline]
762    pub fn segments(&self) -> impl Iterator<Item = &'_ SingularSegment> {
763        self.segments.iter()
764    }
765}
766
767/// Segment allowed in a [`SingularJsonPathQuery`].
768#[derive(Debug, PartialEq, Eq, Clone, Hash)]
769#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
770#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
771pub enum SingularSegment {
772    /// Child name selector. Equivalent of [`Selector::Name`].
773    Name(str::JsonString),
774    /// Child index selector. Equivalent of [`Selector::Index`].
775    Index(Index),
776}
777
778impl FromIterator<SingularSegment> for SingularJsonPathQuery {
779    #[inline]
780    fn from_iter<T: IntoIterator<Item = SingularSegment>>(iter: T) -> Self {
781        Self {
782            segments: iter.into_iter().collect(),
783        }
784    }
785}
786
787impl From<SingularSegment> for Segment {
788    #[inline]
789    fn from(value: SingularSegment) -> Self {
790        match value {
791            SingularSegment::Name(n) => Self::Child(Selectors::one(Selector::Name(n))),
792            SingularSegment::Index(i) => Self::Child(Selectors::one(Selector::Index(i))),
793        }
794    }
795}
796
797/// JSONPath query structure represented by a sequence of [`Segments`](Segment).
798#[derive(Debug, PartialEq, Eq, Clone, Hash)]
799#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
800#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
801pub struct JsonPathQuery {
802    segments: Vec<Segment>,
803}
804
805impl FromIterator<Segment> for JsonPathQuery {
806    #[inline]
807    fn from_iter<T: IntoIterator<Item = Segment>>(iter: T) -> Self {
808        Self {
809            segments: iter.into_iter().collect(),
810        }
811    }
812}
813
814impl JsonPathQuery {
815    fn try_to_singular(self) -> std::result::Result<SingularJsonPathQuery, Self> {
816        if self.segments.iter().all(Segment::is_singular) {
817            let mut singular_segments = Vec::with_capacity(self.segments.len());
818            for segment in self.segments {
819                singular_segments.push(segment.into_singular());
820            }
821            Ok(SingularJsonPathQuery {
822                segments: singular_segments,
823            })
824        } else {
825            Err(self)
826        }
827    }
828}
829
830impl JsonPathQuery {
831    /// Returns all [`Segments`](Segment) of the query as a slice.
832    #[inline(always)]
833    #[must_use]
834    pub fn segments(&self) -> &[Segment] {
835        &self.segments
836    }
837}
838
839impl Segment {
840    /// Returns all [`Selector`] instances of the segment.
841    #[inline(always)]
842    #[must_use]
843    pub fn selectors(&self) -> &Selectors {
844        match self {
845            Self::Child(s) | Self::Descendant(s) => s,
846        }
847    }
848
849    /// Check if this is a child segment.
850    ///
851    /// # Examples
852    /// ```
853    /// # use rsonpath_syntax::{Selectors, Segment, Selector};
854    /// let segment = Segment::Child(Selectors::one(Selector::Wildcard));
855    /// assert!(segment.is_child());
856    /// ```
857    #[inline(always)]
858    #[must_use]
859    pub fn is_child(&self) -> bool {
860        matches!(self, Self::Child(_))
861    }
862
863    /// Check if this is a descendant segment.
864    ///
865    /// # Examples
866    /// ```
867    /// # use rsonpath_syntax::{Selectors, Segment, Selector};
868    /// let segment = Segment::Descendant(Selectors::one(Selector::Wildcard));
869    /// assert!(segment.is_descendant());
870    /// ```
871    #[inline(always)]
872    #[must_use]
873    pub fn is_descendant(&self) -> bool {
874        matches!(self, Self::Descendant(_))
875    }
876
877    fn is_singular(&self) -> bool {
878        match self {
879            Self::Child(s) => s.len() == 1 && s.first().is_singular(),
880            Self::Descendant(_) => false,
881        }
882    }
883
884    fn into_singular(self) -> SingularSegment {
885        assert!(self.is_singular());
886        match self {
887            Self::Child(mut s) => match s.inner.drain(..).next().expect("is_singular") {
888                Selector::Name(n) => SingularSegment::Name(n),
889                Selector::Index(i) => SingularSegment::Index(i),
890                _ => unreachable!(),
891            },
892            Self::Descendant(_) => unreachable!(),
893        }
894    }
895}
896
897impl Selectors {
898    /// Create a singleton [`Selectors`] instance.
899    #[inline(always)]
900    #[must_use]
901    pub fn one(selector: Selector) -> Self {
902        Self { inner: vec![selector] }
903    }
904
905    /// Create a [`Selectors`] instance taking ownership of the `vec`.
906    ///
907    /// ## Panics
908    /// If the `vec` is empty.
909    ///
910    /// ```should_panic
911    /// # use rsonpath_syntax::Selectors;
912    /// Selectors::many(vec![]);
913    /// ```
914    #[inline]
915    #[must_use]
916    pub fn many(vec: Vec<Selector>) -> Self {
917        assert!(!vec.is_empty(), "cannot create an empty Selectors collection");
918        Self { inner: vec }
919    }
920
921    /// Get a reference to the first [`Selector`] in the collection.
922    #[inline]
923    #[must_use]
924    pub fn first(&self) -> &Selector {
925        &self.inner[0]
926    }
927
928    /// Get the selectors as a non-empty slice.
929    #[inline]
930    #[must_use]
931    pub fn as_slice(&self) -> &[Selector] {
932        // Deref magic.
933        self
934    }
935}
936
937impl Selector {
938    /// Check if this is a name selector.
939    ///
940    /// # Examples
941    /// ```
942    /// # use rsonpath_syntax::{Selector, str::JsonString};
943    /// let selector = Selector::Name(JsonString::new("abc"));
944    /// assert!(selector.is_name());
945    /// ```
946    #[inline(always)]
947    #[must_use]
948    pub const fn is_name(&self) -> bool {
949        matches!(self, Self::Name(_))
950    }
951
952    /// Check if this is a wildcard selector.
953    ///
954    /// # Examples
955    /// ```
956    /// # use rsonpath_syntax::Selector;
957    /// let selector = Selector::Wildcard;
958    /// assert!(selector.is_wildcard());
959    /// ```
960    #[inline(always)]
961    #[must_use]
962    pub const fn is_wildcard(&self) -> bool {
963        matches!(self, Self::Wildcard)
964    }
965
966    /// Check if this is an index selector.
967    ///
968    /// # Examples
969    /// ```
970    /// # use rsonpath_syntax::{Selector, Index};
971    /// let selector = Selector::Index(Index::FromStart(0.into()));
972    /// assert!(selector.is_index());
973    /// ```
974    #[inline(always)]
975    #[must_use]
976    pub const fn is_index(&self) -> bool {
977        matches!(self, Self::Index(_))
978    }
979
980    /// Check if this is a slice selector.
981    ///
982    /// # Examples
983    /// ```
984    /// # use rsonpath_syntax::{Selector, Slice};
985    /// let selector = Selector::Slice(Slice::default());
986    /// assert!(selector.is_slice());
987    /// ```
988    #[inline(always)]
989    #[must_use]
990    pub const fn is_slice(&self) -> bool {
991        matches!(self, Self::Slice(_))
992    }
993
994    /// Check if this is a filter selector.
995    ///
996    /// # Examples
997    /// ```
998    /// # use rsonpath_syntax::{JsonPathQuery, TestExpr, LogicalExpr, Selector, Index};
999    /// let selector = Selector::Filter(LogicalExpr::Test(TestExpr::Relative(JsonPathQuery::from_iter(vec![]))));
1000    /// assert!(selector.is_filter());
1001    /// ```
1002    #[inline(always)]
1003    #[must_use]
1004    pub const fn is_filter(&self) -> bool {
1005        matches!(self, Self::Filter(_))
1006    }
1007
1008    fn is_singular(&self) -> bool {
1009        matches!(self, Self::Name(_) | Self::Index(_))
1010    }
1011}
1012
1013impl Index {
1014    /// Check if this is an index counting from the start of an array.
1015    ///
1016    /// # Examples
1017    /// ```
1018    /// # use rsonpath_syntax::{Selector, Index};
1019    /// let index = Index::FromStart(0.into());
1020    /// assert!(index.is_start_based());
1021    /// ```
1022    #[inline(always)]
1023    #[must_use]
1024    pub const fn is_start_based(&self) -> bool {
1025        matches!(self, Self::FromStart(_))
1026    }
1027
1028    /// Check if this is an index counting from the end of an array.
1029    ///
1030    /// # Examples
1031    /// ```
1032    /// # use rsonpath_syntax::{Selector, Index};
1033    /// let index = Index::FromEnd(1.try_into().unwrap());
1034    /// assert!(index.is_end_based());
1035    /// ```
1036    #[inline(always)]
1037    #[must_use]
1038    pub const fn is_end_based(&self) -> bool {
1039        matches!(self, Self::FromEnd(_))
1040    }
1041}
1042
1043impl Step {
1044    /// Check if this is a step going forward in an array.
1045    ///
1046    /// # Examples
1047    /// ```
1048    /// # use rsonpath_syntax::{Selector, Step};
1049    /// let step = Step::Forward(2.try_into().unwrap());
1050    /// assert!(step.is_forward());
1051    /// ```
1052    #[inline(always)]
1053    #[must_use]
1054    pub const fn is_forward(&self) -> bool {
1055        matches!(self, Self::Forward(_))
1056    }
1057
1058    /// Check if this is a step going backward in an array.
1059    ///
1060    /// # Examples
1061    /// ```
1062    /// # use rsonpath_syntax::{Selector, Step};
1063    /// let step = Step::Backward(2.try_into().unwrap());
1064    /// assert!(step.is_backward());
1065    /// ```
1066    #[inline(always)]
1067    #[must_use]
1068    pub const fn is_backward(&self) -> bool {
1069        matches!(self, Self::Backward(_))
1070    }
1071}
1072
1073impl Deref for Selectors {
1074    type Target = [Selector];
1075
1076    #[inline(always)]
1077    fn deref(&self) -> &Self::Target {
1078        &self.inner
1079    }
1080}
1081
1082impl Display for JsonPathQuery {
1083    #[inline]
1084    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1085        write!(f, "$")?;
1086        for s in &self.segments {
1087            write!(f, "{s}")?;
1088        }
1089        Ok(())
1090    }
1091}
1092
1093impl Display for Segment {
1094    #[inline]
1095    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1096        match self {
1097            Self::Child(s) => write!(f, "{s}"),
1098            Self::Descendant(s) => write!(f, "..{s}"),
1099        }
1100    }
1101}
1102
1103impl Display for Selectors {
1104    #[inline]
1105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1106        write!(f, "[{}", self.first())?;
1107        for s in self.inner.iter().skip(1) {
1108            write!(f, ", {s}")?;
1109        }
1110        write!(f, "]")?;
1111        Ok(())
1112    }
1113}
1114
1115impl Display for Selector {
1116    #[inline]
1117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1118        match self {
1119            Self::Name(n) => write!(f, "'{}'", str::escape(n.unquoted(), str::EscapeMode::SingleQuoted)),
1120            Self::Wildcard => write!(f, "*"),
1121            Self::Index(idx) => write!(f, "{idx}"),
1122            Self::Slice(slice) => write!(f, "{slice}"),
1123            Self::Filter(filter) => write!(f, "?{filter}"),
1124        }
1125    }
1126}
1127
1128impl Display for Index {
1129    #[inline]
1130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131        match self {
1132            Self::FromStart(idx) => write!(f, "{idx}"),
1133            Self::FromEnd(idx) => write!(f, "-{idx}"),
1134        }
1135    }
1136}
1137
1138impl Display for Step {
1139    #[inline]
1140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1141        match self {
1142            Self::Forward(idx) => write!(f, "{idx}"),
1143            Self::Backward(idx) => write!(f, "-{idx}"),
1144        }
1145    }
1146}
1147
1148impl Display for Slice {
1149    #[inline]
1150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1151        if (self.step.is_forward() && self.start != Self::DEFAULT_START_FORWARDS)
1152            || (self.step.is_backward() && self.start != Self::default_start_backwards())
1153        {
1154            write!(f, "{}", self.start)?;
1155        }
1156        write!(f, ":")?;
1157        if let Some(end) = self.end {
1158            write!(f, "{end}")?;
1159        }
1160        if self.step != Self::DEFAULT_STEP {
1161            write!(f, ":{}", self.step)?;
1162        }
1163        Ok(())
1164    }
1165}
1166
1167impl Display for LogicalExpr {
1168    #[inline]
1169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1170        match self {
1171            Self::Or(lhs, rhs) => {
1172                if lhs.precedence() <= self.precedence() {
1173                    write!(f, "({lhs})")?;
1174                } else {
1175                    write!(f, "{lhs}")?;
1176                }
1177                write!(f, " || ")?;
1178                if rhs.precedence() < self.precedence() {
1179                    write!(f, "({rhs})")?;
1180                } else {
1181                    write!(f, "{rhs}")?;
1182                }
1183                Ok(())
1184            }
1185            Self::And(lhs, rhs) => {
1186                if lhs.precedence() < self.precedence() {
1187                    write!(f, "({lhs})")?;
1188                } else {
1189                    write!(f, "{lhs}")?;
1190                }
1191                write!(f, " && ")?;
1192                if rhs.precedence() <= self.precedence() {
1193                    write!(f, "({rhs})")?;
1194                } else {
1195                    write!(f, "{rhs}")?;
1196                }
1197                Ok(())
1198            }
1199            Self::Not(expr) => {
1200                if expr.precedence() <= self.precedence() {
1201                    write!(f, "!({expr})")
1202                } else {
1203                    write!(f, "!{expr}")
1204                }
1205            }
1206            Self::Comparison(expr) => write!(f, "{expr}"),
1207            Self::Test(test) => write!(f, "{test}"),
1208        }
1209    }
1210}
1211
1212impl Display for ComparisonExpr {
1213    #[inline]
1214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1215        write!(f, "{} {} {}", self.lhs, self.op, self.rhs)
1216    }
1217}
1218
1219impl Display for TestExpr {
1220    #[inline]
1221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1222        match self {
1223            Self::Relative(q) => {
1224                write!(f, "@")?;
1225                for s in q.segments() {
1226                    write!(f, "{s}")?;
1227                }
1228            }
1229            Self::Absolute(q) => {
1230                write!(f, "$")?;
1231                for s in q.segments() {
1232                    write!(f, "{s}")?;
1233                }
1234            }
1235        }
1236        Ok(())
1237    }
1238}
1239
1240impl Display for Comparable {
1241    #[inline]
1242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1243        match self {
1244            Self::Literal(lit) => write!(f, "{lit}"),
1245            Self::RelativeSingularQuery(q) => {
1246                write!(f, "@")?;
1247                for s in q.segments() {
1248                    write!(f, "{s}")?;
1249                }
1250                Ok(())
1251            }
1252            Self::AbsoluteSingularQuery(q) => {
1253                write!(f, "$")?;
1254                for s in q.segments() {
1255                    write!(f, "{s}")?;
1256                }
1257                Ok(())
1258            }
1259        }
1260    }
1261}
1262
1263impl Display for Literal {
1264    #[inline]
1265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1266        match self {
1267            Self::String(s) => write!(f, "\"{}\"", str::escape(s.unquoted(), str::EscapeMode::DoubleQuoted)),
1268            Self::Number(n) => write!(f, "{n}"),
1269            Self::Bool(true) => write!(f, "true"),
1270            Self::Bool(false) => write!(f, "false"),
1271            Self::Null => write!(f, "null"),
1272        }
1273    }
1274}
1275
1276impl Display for ComparisonOp {
1277    #[inline]
1278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1279        match self {
1280            Self::EqualTo => write!(f, "=="),
1281            Self::NotEqualTo => write!(f, "!="),
1282            Self::LesserOrEqualTo => write!(f, "<="),
1283            Self::GreaterOrEqualTo => write!(f, ">="),
1284            Self::LessThan => write!(f, "<"),
1285            Self::GreaterThan => write!(f, ">"),
1286        }
1287    }
1288}
1289
1290impl Display for SingularJsonPathQuery {
1291    #[inline]
1292    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1293        for s in &self.segments {
1294            write!(f, "[{s}]")?;
1295        }
1296        Ok(())
1297    }
1298}
1299
1300impl Display for SingularSegment {
1301    #[inline]
1302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1303        match self {
1304            Self::Name(n) => write!(f, "['{}']", str::escape(n.unquoted(), str::EscapeMode::SingleQuoted)),
1305            Self::Index(i) => write!(f, "[{i}]"),
1306        }
1307    }
1308}
1309
1310#[cfg(test)]
1311mod tests {
1312    use super::*;
1313    use pretty_assertions::assert_eq;
1314
1315    #[test]
1316    fn leading_whitespace_is_disallowed() {
1317        let err = parse("  $").expect_err("should fail");
1318        let display = format!("{err}");
1319        let expected = r"error: query starting with whitespace
1320
1321    $
1322  ^^ leading whitespace is disallowed
1323  (bytes 0-1)
1324
1325
1326suggestion: did you mean `$` ?
1327";
1328        assert_eq!(display, expected);
1329    }
1330
1331    #[test]
1332    fn trailing_whitespace_is_disallowed() {
1333        let err = parse("$  ").expect_err("should fail");
1334        let display = format!("{err}");
1335        let expected = r"error: query ending with whitespace
1336
1337  $  
1338   ^^ trailing whitespace is disallowed
1339  (bytes 1-2)
1340
1341
1342suggestion: did you mean `$` ?
1343";
1344        assert_eq!(display, expected);
1345    }
1346
1347    mod name_selector {
1348        use super::*;
1349        use pretty_assertions::assert_eq;
1350        use test_case::test_case;
1351
1352        fn parse_single_quoted_name_selector(src: &str) -> Result<JsonPathQuery> {
1353            let query_string = format!("$['{src}']");
1354            parse(&query_string)
1355        }
1356
1357        #[test_case("", ""; "empty")]
1358        #[test_case("dog", "dog"; "ascii")]
1359        #[test_case(r"\\", r"\"; "backslash")]
1360        #[test_case("unescaped 🔥 fire emoji", "unescaped 🔥 fire emoji"; "unescaped emoji")]
1361        #[test_case(r"escape \b backspace", "escape \u{0008} backspace"; "BS escape")]
1362        #[test_case(r"escape \t tab", "escape \t tab"; "HT escape")]
1363        #[test_case(r"escape \n endln", "escape \n endln"; "LF escape")]
1364        #[test_case(r"escape \f formfeed", "escape \u{000C} formfeed"; "FF escape")]
1365        #[test_case(r"escape \r carriage", "escape \r carriage"; "CR escape")]
1366        #[test_case(r#"escape \' apost"#, r"escape ' apost"; "apostrophe escape")]
1367        #[test_case(r"escape \/ slash", r"escape / slash"; "slash escape")]
1368        #[test_case(r"escape \\ backslash", r"escape \ backslash"; "backslash escape")]
1369        #[test_case(r"escape \u2112 script L", "escape â„’ script L"; "U+2112 Script Capital L escape")]
1370        #[test_case(r"escape \u211269 script L", "escape â„’69 script L"; "U+2112 Script Capital L escape followed by digits")]
1371        #[test_case(r"escape \u21a7 bar down arrow", "escape ↧ bar down arrow"; "U+21a7 Downwards Arrow From Bar (lowercase hex)")]
1372        #[test_case(r"escape \u21A7 bar down arrow", "escape ↧ bar down arrow"; "U+21A7 Downwards Arrow From Bar (uppercase hex)")]
1373        #[test_case(r"escape \ud83d\udd25 fire emoji", "escape 🔥 fire emoji"; "U+1F525 fire emoji escape (lowercase hex)")]
1374        #[test_case(r"escape \uD83D\uDD25 fire emoji", "escape 🔥 fire emoji"; "U+1F525 fire emoji escape (uppercase hex)")]
1375        fn parse_correct_single_quoted_name(src: &str, expected: &str) {
1376            let res = parse_single_quoted_name_selector(src).expect("should successfully parse");
1377            match res.segments().first() {
1378                Some(Segment::Child(selectors)) => match selectors.first() {
1379                    Selector::Name(name) => assert_eq!(name.unquoted(), expected),
1380                    _ => panic!("expected to parse a single name selector, got {res:?}"),
1381                },
1382                _ => panic!("expected to parse a single name selector, got {res:?}"),
1383            }
1384        }
1385
1386        #[test]
1387        fn parse_double_quoted_name_with_escaped_double_quote() {
1388            let query_string = r#"$["escape \" quote"]"#;
1389            let res = parse(query_string).expect("should successfully parse");
1390            match res.segments().first() {
1391                Some(Segment::Child(selectors)) => match selectors.first() {
1392                    Selector::Name(name) => assert_eq!(name.unquoted(), "escape \" quote"),
1393                    _ => panic!("expected to parse a single name selector, got {res:?}"),
1394                },
1395                _ => panic!("expected to parse a single name selector, got {res:?}"),
1396            }
1397        }
1398    }
1399}