1#![forbid(unsafe_code)]
97#![doc(html_logo_url = "https://raw.githubusercontent.com/V0ldek/rsonpath/main/img/rsonquery-logo.svg")]
98#![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#![cfg_attr(not(test), warn(clippy::unwrap_used))]
112#![cfg_attr(
114 not(debug_assertions),
115 warn(clippy::print_stderr, clippy::print_stdout, clippy::todo)
116)]
117#![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
127pub(crate) const JSONPATH_WHITESPACE: [char; 4] = [' ', '\t', '\n', '\r'];
129pub(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#[derive(Debug, Clone, Default)]
143pub struct Parser {
144 options: ParserOptions,
145}
146
147#[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 #[inline]
162 #[must_use]
163 pub fn new() -> Self {
164 Self {
165 options: ParserOptions::default(),
166 }
167 }
168
169 #[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 #[inline]
218 pub fn allow_surrounding_whitespace(&mut self, value: bool) -> &mut Self {
219 self.options.relaxed_whitespace = value;
220 self
221 }
222
223 #[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
260pub type Result<T> = std::result::Result<T, error::ParseError>;
262
263#[inline]
296pub fn parse(str: &str) -> Result<JsonPathQuery> {
297 Parser::default().parse(str)
298}
299
300impl Parser {
301 pub const RECURSION_LIMIT_DEFAULT: usize = 128;
305
306 #[inline]
320 pub fn parse(&self, str: &str) -> Result<JsonPathQuery> {
321 crate::parser::parse_with_options(str, &self.options)
322 }
323}
324
325#[derive(Debug, PartialEq, Eq, Clone, Hash)]
331#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
332pub enum Segment {
333 Child(Selectors),
336 Descendant(Selectors),
339}
340
341#[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#[derive(Debug, PartialEq, Eq, Clone, Hash)]
353#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
354pub enum Selector {
355 Name(str::JsonString),
358 Wildcard,
360 Index(Index),
363 Slice(Slice),
366 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#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
401#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
402pub enum Index {
403 FromStart(num::JsonUInt),
405 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#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
425#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
426pub enum Step {
427 Forward(num::JsonUInt),
429 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#[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 #[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 #[inline(always)]
483 #[must_use]
484 pub fn build() -> SliceBuilder {
485 SliceBuilder::new()
486 }
487
488 #[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 #[inline(always)]
497 #[must_use]
498 pub fn start(&self) -> Index {
499 self.start
500 }
501
502 #[inline(always)]
504 #[must_use]
505 pub fn end(&self) -> Option<Index> {
506 self.end
507 }
508
509 #[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#[derive(Debug, PartialEq, Eq, Clone, Hash)]
530#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
531pub enum Literal {
532 String(str::JsonString),
534 Number(num::JsonNumber),
537 Bool(bool),
539 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#[derive(Debug, PartialEq, Eq, Clone, Hash)]
587#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
588pub enum LogicalExpr {
589 Or(LogicalExprNode, LogicalExprNode),
591 And(LogicalExprNode, LogicalExprNode),
593 Not(LogicalExprNode),
595 Comparison(ComparisonExpr),
598 Test(TestExpr),
600}
601
602impl LogicalExpr {
603 #[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#[derive(Debug, PartialEq, Eq, Clone, Hash)]
625#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
626pub enum TestExpr {
627 Relative(JsonPathQuery),
629 Absolute(JsonPathQuery),
631}
632
633#[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 #[inline(always)]
662 #[must_use]
663 pub fn build() -> EmptyComparisonExprBuilder {
664 EmptyComparisonExprBuilder
665 }
666
667 #[inline]
669 #[must_use]
670 pub fn lhs(&self) -> &Comparable {
671 &self.lhs
672 }
673
674 #[inline]
676 #[must_use]
677 pub fn op(&self) -> ComparisonOp {
678 self.op
679 }
680
681 #[inline]
683 #[must_use]
684 pub fn rhs(&self) -> &Comparable {
685 &self.rhs
686 }
687
688 #[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#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
698#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
699pub enum ComparisonOp {
700 EqualTo,
702 NotEqualTo,
704 LesserOrEqualTo,
706 GreaterOrEqualTo,
708 LessThan,
710 GreaterThan,
712}
713
714#[derive(Debug, PartialEq, Eq, Clone, Hash)]
716#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
717pub enum Comparable {
718 Literal(Literal),
720 RelativeSingularQuery(SingularJsonPathQuery),
722 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#[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 #[inline(always)]
750 #[must_use]
751 pub fn build() -> SingularJsonPathQueryBuilder {
752 SingularJsonPathQueryBuilder::new()
753 }
754
755 #[inline]
757 pub fn segments(&self) -> impl Iterator<Item = &'_ SingularSegment> {
758 self.segments.iter()
759 }
760}
761
762#[derive(Debug, PartialEq, Eq, Clone, Hash)]
764#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
765pub enum SingularSegment {
766 Name(str::JsonString),
768 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#[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 #[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 #[inline(always)]
833 #[must_use]
834 pub fn segments(&self) -> &[Segment] {
835 &self.segments
836 }
837}
838
839impl Segment {
840 #[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 #[inline(always)]
858 #[must_use]
859 pub fn is_child(&self) -> bool {
860 matches!(self, Self::Child(_))
861 }
862
863 #[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 #[inline(always)]
900 #[must_use]
901 pub fn one(selector: Selector) -> Self {
902 Self { inner: vec![selector] }
903 }
904
905 #[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 #[inline]
923 #[must_use]
924 pub fn first(&self) -> &Selector {
925 &self.inner[0]
926 }
927
928 #[inline]
930 #[must_use]
931 pub fn as_slice(&self) -> &[Selector] {
932 self
934 }
935}
936
937impl Selector {
938 #[inline(always)]
947 #[must_use]
948 pub const fn is_name(&self) -> bool {
949 matches!(self, Self::Name(_))
950 }
951
952 #[inline(always)]
961 #[must_use]
962 pub const fn is_wildcard(&self) -> bool {
963 matches!(self, Self::Wildcard)
964 }
965
966 #[inline(always)]
975 #[must_use]
976 pub const fn is_index(&self) -> bool {
977 matches!(self, Self::Index(_))
978 }
979
980 #[inline(always)]
989 #[must_use]
990 pub const fn is_slice(&self) -> bool {
991 matches!(self, Self::Slice(_))
992 }
993
994 #[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 #[inline(always)]
1023 #[must_use]
1024 pub const fn is_start_based(&self) -> bool {
1025 matches!(self, Self::FromStart(_))
1026 }
1027
1028 #[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 #[inline(always)]
1053 #[must_use]
1054 pub const fn is_forward(&self) -> bool {
1055 matches!(self, Self::Forward(_))
1056 }
1057
1058 #[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}