Skip to main content

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 is one optional features:
92//! - `color`, which enables a dependency on the [`owo_colors` crate](https://docs.rs/owo-colors/latest/owo_colors/)
93//!   to provide colorful [`Display`] representations of [`ParseError`](error::ParseError);
94//!   see [`ParseError::colored`](error::ParseError::colored).
95
96#![forbid(unsafe_code)]
97#![doc(html_logo_url = "https://raw.githubusercontent.com/V0ldek/rsonpath/main/img/rsonquery-logo.svg")]
98// Documentation lints, enabled only on --release.
99#![cfg_attr(
100    not(debug_assertions),
101    warn(
102        missing_docs,
103        clippy::cargo_common_metadata,
104        clippy::missing_errors_doc,
105        clippy::missing_panics_doc,
106        clippy::too_long_first_doc_paragraph
107    )
108)]
109#![cfg_attr(not(debug_assertions), warn(rustdoc::missing_crate_level_docs))]
110// Panic-free lints (disabled for tests).
111#![cfg_attr(not(test), warn(clippy::unwrap_used))]
112// IO hygiene, only on --release.
113#![cfg_attr(
114    not(debug_assertions),
115    warn(clippy::print_stderr, clippy::print_stdout, clippy::todo)
116)]
117// Docs.rs config.
118#![cfg_attr(docsrs, feature(doc_cfg))]
119
120pub mod builder;
121pub mod error;
122pub mod num;
123mod parser;
124pub mod prelude;
125pub mod str;
126
127/// All characters that are valid whitespace within a JSONPath query.
128pub(crate) const JSONPATH_WHITESPACE: [char; 4] = [' ', '\t', '\n', '\r'];
129/// All ASCII bytes that are valid whitespace within a JSONPath query.
130pub(crate) const JSONPATH_WHITESPACE_BYTES: [u8; 4] = [0x20, 0x09, 0x0A, 0x0D];
131
132use crate::builder::{
133    EmptyComparisonExprBuilder, EmptyLogicalExprBuilder, JsonPathQueryBuilder, SingularJsonPathQueryBuilder,
134    SliceBuilder,
135};
136use std::{
137    fmt::{self, Display},
138    ops::Deref,
139};
140
141/// JSONPath query parser.
142#[derive(Debug, Clone, Default)]
143pub struct Parser {
144    options: ParserOptions,
145}
146
147/// Configurable builder for a [`Parser`] instance.
148#[derive(Debug, Clone, Default)]
149pub struct ParserBuilder {
150    options: ParserOptions,
151}
152
153#[derive(Debug, Clone)]
154struct ParserOptions {
155    recursion_limit: Option<usize>,
156    relaxed_whitespace: bool,
157}
158
159impl ParserBuilder {
160    /// Create a new instance of the builder with the default settings.
161    #[inline]
162    #[must_use]
163    pub fn new() -> Self {
164        Self {
165            options: ParserOptions::default(),
166        }
167    }
168
169    /// Override the default recursion limit in a query.
170    /// Defaults to [Parser::RECURSION_LIMIT_DEFAULT].
171    ///
172    /// JSONPath queries are inherently recursive, since
173    /// - [`LogicalExpr`] can be an arbitrarily deep tree of AND/OR operators;
174    /// - the [`TestExpr`] in a filter can test arbitrary nested JSONPath queries.
175    ///
176    /// Our parser implementation is recursive, so an excessively nested query could overflow the stack.
177    ///
178    /// The limit can be relaxed here, or removed entirely by passing [`None`].
179    ///
180    /// ## Examples
181    /// ```
182    /// # use rsonpath_syntax::{JsonPathQuery, Parser, ParserBuilder};
183    /// let default_parser = ParserBuilder::new().build();
184    /// let no_nesting_parser = ParserBuilder::new()
185    ///     .set_recursion_limit(Some(1))
186    ///     .build();
187    ///
188    /// let query = "$[?@[?@]]";
189    /// assert!(default_parser.parse(query).is_ok());
190    /// assert!(no_nesting_parser.parse(query).is_err());
191    /// ```
192    #[inline]
193    pub fn set_recursion_limit(&mut self, value: Option<usize>) -> &mut Self {
194        self.options.recursion_limit = value;
195        self
196    }
197
198    /// Control whether leading and trailing whitespace is allowed in a query.
199    /// Defaults to false.
200    ///
201    /// The [RFC](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html) grammar
202    /// makes leading and trailing whitespace disallowed. The [`Parser`] defaults to this strict handling,
203    /// but can be relaxed with this setting.
204    ///
205    /// ## Examples
206    /// ```
207    /// # use rsonpath_syntax::{JsonPathQuery, Parser, ParserBuilder};
208    /// let default_parser = ParserBuilder::new().build();
209    /// let relaxed_parser = ParserBuilder::new()
210    ///     .allow_surrounding_whitespace(true)
211    ///     .build();
212    ///
213    /// let query = "  $.leading_whitespace";
214    /// assert!(default_parser.parse(query).is_err());
215    /// assert!(relaxed_parser.parse(query).is_ok());
216    /// ```
217    #[inline]
218    pub fn allow_surrounding_whitespace(&mut self, value: bool) -> &mut Self {
219        self.options.relaxed_whitespace = value;
220        self
221    }
222
223    /// Build a new instance of a [`Parser`].
224    #[inline]
225    #[must_use]
226    pub fn build(&self) -> Parser {
227        Parser {
228            options: self.options.clone(),
229        }
230    }
231}
232
233impl ParserOptions {
234    fn is_leading_whitespace_allowed(&self) -> bool {
235        self.relaxed_whitespace
236    }
237
238    fn is_trailing_whitespace_allowed(&self) -> bool {
239        self.relaxed_whitespace
240    }
241}
242
243impl Default for ParserOptions {
244    #[inline(always)]
245    fn default() -> Self {
246        Self {
247            recursion_limit: Some(Parser::RECURSION_LIMIT_DEFAULT),
248            relaxed_whitespace: false,
249        }
250    }
251}
252
253impl From<ParserBuilder> for Parser {
254    #[inline(always)]
255    fn from(value: ParserBuilder) -> Self {
256        Self { options: value.options }
257    }
258}
259
260/// Convenience alias for [`Result`](std::result::Result) values returned by this crate.
261pub type Result<T> = std::result::Result<T, error::ParseError>;
262
263/// Parse a JSONPath query string using default [`Parser`] configuration.
264///
265/// ## Errors
266/// Fails if the string does not represent a valid JSONPath query
267/// as governed by the [JSONPath RFC specification](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html).
268///
269/// Note that leading and trailing whitespace is explicitly disallowed by the spec.
270/// This can be relaxed with a custom [`Parser`] configured with [`ParserBuilder::allow_surrounding_whitespace`].
271///
272/// # Examples
273/// ```
274/// # use rsonpath_syntax::parse;
275/// let x = "  $.a  ";
276/// let err = rsonpath_syntax::parse(x).expect_err("should fail");
277/// assert_eq!(err.to_string(),
278/// "error: query starting with whitespace
279///
280///     $.a  
281///   ^^ leading whitespace is disallowed
282///   (bytes 0-1)
283///
284///
285///error: query ending with whitespace
286///
287///     $.a  
288///        ^^ trailing whitespace is disallowed
289///   (bytes 5-6)
290///
291///
292///suggestion: did you mean `$.a` ?
293///");
294/// ```
295#[inline]
296pub fn parse(str: &str) -> Result<JsonPathQuery> {
297    Parser::default().parse(str)
298}
299
300impl Parser {
301    /// Default limit on the nesting level of a query.
302    ///
303    /// This can be overridden by [`ParserBuilder::set_recursion_limit`].
304    pub const RECURSION_LIMIT_DEFAULT: usize = 128;
305
306    /// Parse a JSONPath query string.
307    ///
308    /// ## Errors
309    /// Fails if the string does not represent a valid JSONPath query
310    /// as governed by the [JSONPath RFC specification](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html).
311    ///
312    /// Note that leading and trailing whitespace is explicitly disallowed by the spec.
313    /// The parser defaults to this strict behavior unless configured with
314    /// [`ParserBuilder::allow_surrounding_whitespace`].
315    ///
316    /// There is a limit on the complexity of the query measured as the depth of nested filter expressions.
317    /// This limit defaults to [`RECURSION_LIMIT_DEFAULT`](Self::RECURSION_LIMIT_DEFAULT) and can be overridden
318    /// with [`ParserBuilder::set_recursion_limit`].
319    #[inline]
320    pub fn parse(&self, str: &str) -> Result<JsonPathQuery> {
321        crate::parser::parse_with_options(str, &self.options)
322    }
323}
324
325/// JSONPath query segment.
326///
327/// Every query is a sequence of zero or more of segments,
328/// each applying one or more selectors to a node and passing it along to the
329/// subsequent segments.
330#[derive(Debug, PartialEq, Eq, Clone, Hash)]
331#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
332pub enum Segment {
333    /// A child segment contains a sequence of selectors,
334    /// each of which selects zero or more children of a node.
335    Child(Selectors),
336    /// A child segment contains a sequence of selectors,
337    /// each of which selects zero or more descendants of a node.
338    Descendant(Selectors),
339}
340
341/// Collection of one or more [`Selector`] instances.
342///
343/// Guaranteed to be non-empty.
344#[derive(Debug, PartialEq, Eq, Clone, Hash)]
345#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
346pub struct Selectors {
347    inner: Vec<Selector>,
348}
349
350/// Each [`Segment`] defines one or more selectors.
351/// A selector produces one or more children/descendants of the node it is applied to.
352#[derive(Debug, PartialEq, Eq, Clone, Hash)]
353#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
354pub enum Selector {
355    /// A name selector selects at most one object member value under the key equal to the
356    /// selector's [`JsonString`](str::JsonString).
357    Name(str::JsonString),
358    /// A wildcard selector selects the nodes of all children of an object or array.
359    Wildcard,
360    /// An index selector matches at most one array element value,
361    /// depending on the selector's [`Index`].
362    Index(Index),
363    /// A slice selector matches elements from arrays starting at a given index,
364    /// ending at a given index, and incrementing with a specified step.
365    Slice(Slice),
366    /// A filter selector matches members/elements which satisfy the given
367    /// [`LogicalExpr`].
368    Filter(LogicalExpr),
369}
370
371impl From<str::JsonString> for Selector {
372    #[inline]
373    fn from(value: str::JsonString) -> Self {
374        Self::Name(value)
375    }
376}
377
378impl From<Index> for Selector {
379    #[inline]
380    fn from(value: Index) -> Self {
381        Self::Index(value)
382    }
383}
384
385impl From<Slice> for Selector {
386    #[inline]
387    fn from(value: Slice) -> Self {
388        Self::Slice(value)
389    }
390}
391
392impl From<LogicalExpr> for Selector {
393    #[inline]
394    fn from(value: LogicalExpr) -> Self {
395        Self::Filter(value)
396    }
397}
398
399/// Directional index into a JSON array.
400#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
401#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
402pub enum Index {
403    /// Zero-based index from the start of the array.
404    FromStart(num::JsonUInt),
405    /// Index from the end of the array.
406    ///
407    /// `-1` is the last element, `-2` is the second last, etc.
408    FromEnd(num::JsonNonZeroUInt),
409}
410
411impl<N: Into<num::JsonInt>> From<N> for Index {
412    #[inline]
413    fn from(value: N) -> Self {
414        let value = value.into();
415        if value.as_i64() >= 0 {
416            Self::FromStart(value.abs())
417        } else {
418            Self::FromEnd(value.abs().try_into().expect("checked for zero already"))
419        }
420    }
421}
422
423/// Directional step offset within a JSON array.
424#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
425#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
426pub enum Step {
427    /// Step forward by a given offset amount.
428    Forward(num::JsonUInt),
429    /// Step backward by a given offset amount.
430    Backward(num::JsonNonZeroUInt),
431}
432
433impl From<num::JsonInt> for Step {
434    #[inline]
435    fn from(value: num::JsonInt) -> Self {
436        if value.as_i64() >= 0 {
437            Self::Forward(value.abs())
438        } else {
439            Self::Backward(value.abs().try_into().expect("checked for zero already"))
440        }
441    }
442}
443
444/// Slice selector defining the start and end bounds, as well as the step value and direction.
445///
446/// The start index is inclusive defaults to `Index::FromStart(0)`.
447///
448/// The end index is exclusive and optional.
449/// If `None`, the end of the slice depends on the step direction:
450/// - if going forward, the end is `len` of the array;
451/// - if going backward, the end is 0.
452///
453/// The step defaults to `Step::Forward(1)`. Note that `Step::Forward(0)` is a valid
454/// value and is specified to result in an empty slice, regardless of `start` and `end`.
455///
456/// # Examples
457/// ```
458/// # use rsonpath_syntax::{Slice, Index, Step, num::JsonUInt};
459/// let slice = Slice::default();
460/// assert_eq!(slice.start(), Index::FromStart(JsonUInt::ZERO));
461/// assert_eq!(slice.end(), None);
462/// assert_eq!(slice.step(), Step::Forward(JsonUInt::ONE));
463/// ```
464#[derive(Debug, PartialEq, Eq, Clone, Hash)]
465#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
466pub struct Slice {
467    start: Index,
468    end: Option<Index>,
469    step: Step,
470}
471
472impl Slice {
473    pub(crate) const DEFAULT_START_FORWARDS: Index = Index::FromStart(num::JsonUInt::ZERO);
474    /// This is not const because the required NonZeroU64::MIN is from Rust 1.70.
475    #[inline(always)]
476    pub(crate) fn default_start_backwards() -> Index {
477        Index::FromEnd(1.try_into().expect("const 1 is nonzero"))
478    }
479    pub(crate) const DEFAULT_STEP: Step = Step::Forward(num::JsonUInt::ONE);
480
481    /// Start building a new [`Slice`].
482    #[inline(always)]
483    #[must_use]
484    pub fn build() -> SliceBuilder {
485        SliceBuilder::new()
486    }
487
488    /// Create a new [`Slice`] from given bounds and step.
489    #[inline(always)]
490    #[must_use]
491    pub fn new(start: Index, end: Option<Index>, step: Step) -> Self {
492        Self { start, end, step }
493    }
494
495    /// Get the start index of the [`Slice`].
496    #[inline(always)]
497    #[must_use]
498    pub fn start(&self) -> Index {
499        self.start
500    }
501
502    /// Get the end index of the [`Slice`].
503    #[inline(always)]
504    #[must_use]
505    pub fn end(&self) -> Option<Index> {
506        self.end
507    }
508
509    /// Get the step of the [`Slice`].
510    #[inline(always)]
511    #[must_use]
512    pub fn step(&self) -> Step {
513        self.step
514    }
515}
516
517impl Default for Slice {
518    #[inline]
519    fn default() -> Self {
520        Self {
521            start: Index::FromStart(0.into()),
522            end: None,
523            step: Step::Forward(1.into()),
524        }
525    }
526}
527
528/// JSON literal value available in comparison expressions of a filter selector.
529#[derive(Debug, PartialEq, Eq, Clone, Hash)]
530#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
531pub enum Literal {
532    /// [`JsonString`](str::JsonString) literal.
533    String(str::JsonString),
534    /// [`JsonNumber`](num::JsonNumber) literal &ndash;
535    /// an integer or a floating point value.
536    Number(num::JsonNumber),
537    /// Boolean JSON value &ndash; `true`` or `false`.
538    Bool(bool),
539    /// The `null` JSON literal value.
540    Null,
541}
542
543impl<S> From<S> for Literal
544where
545    S: Into<str::JsonString>,
546{
547    #[inline(always)]
548    fn from(value: S) -> Self {
549        Self::String(value.into())
550    }
551}
552
553impl From<num::JsonInt> for Literal {
554    #[inline(always)]
555    fn from(value: num::JsonInt) -> Self {
556        Self::Number(num::JsonNumber::Int(value))
557    }
558}
559
560impl From<num::JsonFloat> for Literal {
561    #[inline(always)]
562    fn from(value: num::JsonFloat) -> Self {
563        Self::Number(num::JsonNumber::Float(value))
564    }
565}
566
567impl From<num::JsonNumber> for Literal {
568    #[inline(always)]
569    fn from(value: num::JsonNumber) -> Self {
570        Self::Number(value)
571    }
572}
573
574impl From<bool> for Literal {
575    #[inline(always)]
576    fn from(value: bool) -> Self {
577        Self::Bool(value)
578    }
579}
580
581/// Logical expression used in a [`Filter`](Selector::Filter) selector.
582///
583/// Expressions form a tree, where [`Comparison`](LogicalExpr::Comparison)
584/// and [`Test`](LogicalExpr::Test) expressions can be leaves, and boolean combinators
585/// (OR, AND, NOT) store their children as [`Boxes`](Box).
586#[derive(Debug, PartialEq, Eq, Clone, Hash)]
587#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
588pub enum LogicalExpr {
589    /// Logical disjunction of two child expressions.
590    Or(LogicalExprNode, LogicalExprNode),
591    /// Logical conjunction of two child expressions.
592    And(LogicalExprNode, LogicalExprNode),
593    /// Logical negation of a child expression.
594    Not(LogicalExprNode),
595    /// Comparison expression &ndash; compare single values determined
596    /// by query or a literal constant.
597    Comparison(ComparisonExpr),
598    /// Existence test &ndash; query and see if any matched nodes exist.
599    Test(TestExpr),
600}
601
602impl LogicalExpr {
603    /// Start building a new [`LogicalExpr`].
604    #[inline(always)]
605    #[must_use]
606    pub fn build() -> EmptyLogicalExprBuilder {
607        EmptyLogicalExprBuilder
608    }
609
610    fn precedence(&self) -> usize {
611        match self {
612            Self::Or(_, _) => 2,
613            Self::And(_, _) => 3,
614            Self::Comparison(_) => 4,
615            Self::Not(_) => 5,
616            Self::Test(_) => 10,
617        }
618    }
619}
620
621type LogicalExprNode = Box<LogicalExpr>;
622
623/// Existence test based on a relative or absolute [`JsonPathQuery`].
624#[derive(Debug, PartialEq, Eq, Clone, Hash)]
625#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
626pub enum TestExpr {
627    /// Relative test &ndash; query from the selected node.
628    Relative(JsonPathQuery),
629    /// Absolute test &ndash; query from the document root.
630    Absolute(JsonPathQuery),
631}
632
633/// Comparison based on two singular values and a comparison operator.
634///
635/// # Examples
636/// ```rust
637/// # use rsonpath_syntax::{ComparisonExpr, Comparable, ComparisonOp, Literal, SingularJsonPathQuery};
638/// let lhs = Comparable::from(Literal::from("abc"));
639/// let rhs = Comparable::RelativeSingularQuery(
640///     SingularJsonPathQuery::from_iter(vec![])
641/// );
642/// let comparison = ComparisonExpr::from_parts(
643///     lhs.clone(),
644///     ComparisonOp::EqualTo,
645///     rhs.clone());
646///
647/// assert_eq!(&lhs, comparison.lhs());
648/// assert_eq!(ComparisonOp::EqualTo, comparison.op());
649/// assert_eq!(&rhs, comparison.rhs());
650/// ```
651#[derive(Debug, PartialEq, Eq, Clone, Hash)]
652#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
653pub struct ComparisonExpr {
654    lhs: Comparable,
655    op: ComparisonOp,
656    rhs: Comparable,
657}
658
659impl ComparisonExpr {
660    /// Start building a new [`ComparisonExpr`].
661    #[inline(always)]
662    #[must_use]
663    pub fn build() -> EmptyComparisonExprBuilder {
664        EmptyComparisonExprBuilder
665    }
666
667    /// Get the comparable left-hand side of the comparison operation.
668    #[inline]
669    #[must_use]
670    pub fn lhs(&self) -> &Comparable {
671        &self.lhs
672    }
673
674    /// Get the comparison operator.
675    #[inline]
676    #[must_use]
677    pub fn op(&self) -> ComparisonOp {
678        self.op
679    }
680
681    /// Get the comparable right-hand side of the comparison operation.
682    #[inline]
683    #[must_use]
684    pub fn rhs(&self) -> &Comparable {
685        &self.rhs
686    }
687
688    /// Construct a [`ComparisonExpr`] from its constituent parts.
689    #[inline]
690    #[must_use]
691    pub fn from_parts(lhs: Comparable, op: ComparisonOp, rhs: Comparable) -> Self {
692        Self { lhs, op, rhs }
693    }
694}
695
696/// Comparison operator usable in a [`ComparisonExpr`].
697#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
698#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
699pub enum ComparisonOp {
700    /// Compares two values for equality; `==`
701    EqualTo,
702    /// Compares two values for non-equality; `!=`
703    NotEqualTo,
704    /// Compares whether the lhs is smaller or equal to rhs; '<='
705    LesserOrEqualTo,
706    /// Compares whether the lhs is bigger or equal to rhs; '>='
707    GreaterOrEqualTo,
708    /// Compares whether the lhs is smaller than rhs; '<'
709    LessThan,
710    /// Compares whether the lhs is bigger than rhs; '>'
711    GreaterThan,
712}
713
714/// One of the sides of a [`ComparisonExpr`], either a constant literal or a singular JSONPath query.
715#[derive(Debug, PartialEq, Eq, Clone, Hash)]
716#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
717pub enum Comparable {
718    /// Constant [`Literal`] value.
719    Literal(Literal),
720    /// Single value queried from the current node.
721    RelativeSingularQuery(SingularJsonPathQuery),
722    /// Single value queried from the JSON root.
723    AbsoluteSingularQuery(SingularJsonPathQuery),
724}
725
726impl From<Literal> for Comparable {
727    #[inline(always)]
728    fn from(value: Literal) -> Self {
729        Self::Literal(value)
730    }
731}
732
733/// Singular JSONPath query.
734///
735/// A singular JSONPath query returns at most one value, and can be used in
736/// [`ComparisonExprs`](ComparisonExpr) as any of the comparison sides.
737///
738/// This is guaranteed syntactically &ndash; only child name and index selectors are allowed
739/// in a [`SingularJsonPathQuery`], which naturally matches only the precise specified path,
740/// if it exists.
741#[derive(Debug, PartialEq, Eq, Clone, Hash)]
742#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
743pub struct SingularJsonPathQuery {
744    segments: Vec<SingularSegment>,
745}
746
747impl SingularJsonPathQuery {
748    /// Start building a new [`SingularJsonPathQuery`].
749    #[inline(always)]
750    #[must_use]
751    pub fn build() -> SingularJsonPathQueryBuilder {
752        SingularJsonPathQueryBuilder::new()
753    }
754
755    /// Iterate over the [`SingularSegments`](SingularSegment) of this query.
756    #[inline]
757    pub fn segments(&self) -> impl Iterator<Item = &'_ SingularSegment> {
758        self.segments.iter()
759    }
760}
761
762/// Segment allowed in a [`SingularJsonPathQuery`].
763#[derive(Debug, PartialEq, Eq, Clone, Hash)]
764#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
765pub enum SingularSegment {
766    /// Child name selector. Equivalent of [`Selector::Name`].
767    Name(str::JsonString),
768    /// Child index selector. Equivalent of [`Selector::Index`].
769    Index(Index),
770}
771
772impl FromIterator<SingularSegment> for SingularJsonPathQuery {
773    #[inline]
774    fn from_iter<T: IntoIterator<Item = SingularSegment>>(iter: T) -> Self {
775        Self {
776            segments: iter.into_iter().collect(),
777        }
778    }
779}
780
781impl From<SingularSegment> for Segment {
782    #[inline]
783    fn from(value: SingularSegment) -> Self {
784        match value {
785            SingularSegment::Name(n) => Self::Child(Selectors::one(Selector::Name(n))),
786            SingularSegment::Index(i) => Self::Child(Selectors::one(Selector::Index(i))),
787        }
788    }
789}
790
791/// JSONPath query structure represented by a sequence of [`Segments`](Segment).
792#[derive(Debug, PartialEq, Eq, Clone, Hash)]
793#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
794pub struct JsonPathQuery {
795    segments: Vec<Segment>,
796}
797
798impl FromIterator<Segment> for JsonPathQuery {
799    #[inline]
800    fn from_iter<T: IntoIterator<Item = Segment>>(iter: T) -> Self {
801        Self {
802            segments: iter.into_iter().collect(),
803        }
804    }
805}
806
807impl JsonPathQuery {
808    /// Start building a new [`JsonPathQuery`].
809    #[inline(always)]
810    #[must_use]
811    pub fn build() -> JsonPathQueryBuilder {
812        JsonPathQueryBuilder::new()
813    }
814
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(), "forcing a non-singular segment, this is a bug");
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}