1use std::fmt;
10
11use super::{Node, Path};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct SelectError {
16 pub message: String,
17 pub column: Option<usize>,
19}
20
21impl SelectError {
22 pub fn new(message: impl Into<String>, column: Option<usize>) -> Self {
23 SelectError {
24 message: message.into(),
25 column,
26 }
27 }
28}
29
30impl fmt::Display for SelectError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self.column {
33 Some(column) => write!(f, "{} at column {column}", self.message),
34 None => f.write_str(&self.message),
35 }
36 }
37}
38
39impl std::error::Error for SelectError {}
40
41pub trait Selector {
43 fn select<'a>(&self, root: &'a Node) -> Result<Vec<(Path, &'a Node)>, SelectError>;
45}
46
47pub trait SelectorBackend {
49 fn name(&self) -> &str;
51 fn compile(&self, expr: &str) -> Result<Box<dyn Selector>, SelectError>;
53}
54
55pub struct Selectors {
68 backends: Vec<Box<dyn SelectorBackend>>,
69}
70
71impl Default for Selectors {
72 fn default() -> Self {
75 #[allow(unused_mut)]
76 let mut selectors = Selectors::new();
77 #[cfg(feature = "jsonpath")]
78 selectors.register(Box::new(JsonPath));
79 selectors
80 }
81}
82
83impl Selectors {
84 pub fn new() -> Self {
86 Selectors {
87 backends: Vec::new(),
88 }
89 }
90
91 pub fn register(&mut self, backend: Box<dyn SelectorBackend>) -> &mut Self {
93 self.backends.retain(|b| b.name() != backend.name());
94 self.backends.push(backend);
95 self
96 }
97
98 pub fn get(&self, name: &str) -> Option<&dyn SelectorBackend> {
100 self.backends
101 .iter()
102 .find(|b| b.name() == name)
103 .map(|b| &**b)
104 }
105
106 pub fn names(&self) -> Vec<&str> {
108 self.backends.iter().map(|b| b.name()).collect()
109 }
110
111 pub fn compile(&self, backend: &str, expr: &str) -> Result<Box<dyn Selector>, SelectError> {
113 match self.get(backend) {
114 Some(b) => b.compile(expr),
115 None => Err(SelectError::new(
116 format!("no selector backend named `{backend}`"),
117 None,
118 )),
119 }
120 }
121}
122
123#[cfg(feature = "jsonpath")]
124pub use jsonpath::{JsonPath, JsonPathSelector};
125
126#[cfg(feature = "jsonpath")]
127mod jsonpath {
128 use std::cmp::Ordering;
129
130 use super::{SelectError, Selector, SelectorBackend};
131 use crate::data::{value_eq, Node, Path, PathSegment, Value};
132
133 #[derive(Clone, Copy, Debug, Default)]
156 pub struct JsonPath;
157
158 impl SelectorBackend for JsonPath {
159 fn name(&self) -> &str {
160 "jsonpath"
161 }
162 fn compile(&self, expr: &str) -> Result<Box<dyn Selector>, SelectError> {
163 Ok(Box::new(JsonPathSelector::parse(expr)?))
164 }
165 }
166
167 #[derive(Clone, Debug)]
169 pub struct JsonPathSelector {
170 steps: Vec<Step>,
171 }
172
173 #[derive(Clone, Debug)]
174 struct Step {
175 descendant: bool,
176 selectors: Vec<Sel>,
177 }
178
179 #[derive(Clone, Debug)]
180 enum Sel {
181 Name(String),
182 Wildcard,
183 Index(i64),
184 Slice(Option<i64>, Option<i64>, i64),
185 Filter(Box<Expr>),
186 }
187
188 const MAX_FILTER_DEPTH: usize = 128;
193
194 const MAX_SELECTED: usize = 1_000_000;
198
199 #[derive(Clone, Debug)]
200 enum Expr {
201 Or(Vec<Expr>),
202 And(Vec<Expr>),
203 Not(Box<Expr>),
204 Compare(Operand, Op, Operand),
205 Exists(Operand),
206 }
207
208 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
209 enum Op {
210 Eq,
211 Ne,
212 Lt,
213 Le,
214 Gt,
215 Ge,
216 }
217
218 #[derive(Clone, Debug)]
219 enum Operand {
220 Current(Vec<PathSegment>, Vec<i64>),
221 Root(Vec<PathSegment>, Vec<i64>),
222 Literal(Node),
223 }
224
225 struct Parser {
226 chars: Vec<char>,
227 pos: usize,
228 depth: usize,
230 }
231
232 fn is_name_char(c: char) -> bool {
233 !c.is_whitespace() && !".[]()?,=!<>&|'\"*$:".contains(c)
234 }
235
236 impl Parser {
237 fn error<T>(&self, message: impl Into<String>) -> Result<T, SelectError> {
238 Err(SelectError::new(message, Some(self.pos + 1)))
239 }
240 fn peek(&self) -> Option<char> {
241 self.chars.get(self.pos).copied()
242 }
243 fn peek_at(&self, offset: usize) -> Option<char> {
244 self.chars.get(self.pos + offset).copied()
245 }
246 fn eat(&mut self, c: char) -> bool {
247 if self.peek() == Some(c) {
248 self.pos += 1;
249 true
250 } else {
251 false
252 }
253 }
254 fn expect(&mut self, c: char) -> Result<(), SelectError> {
255 if self.eat(c) {
256 Ok(())
257 } else {
258 self.error(format!("expected `{c}`"))
259 }
260 }
261 fn blanks(&mut self) {
262 while self.peek().is_some_and(char::is_whitespace) {
263 self.pos += 1;
264 }
265 }
266
267 fn name(&mut self) -> Result<String, SelectError> {
268 let start = self.pos;
269 while self.peek().is_some_and(is_name_char) {
270 self.pos += 1;
271 }
272 if start == self.pos {
273 return match self.peek() {
274 Some(c) => self.error(format!("unexpected `{c}`, expected a key")),
275 None => self.error("expected a key"),
276 };
277 }
278 Ok(self.chars[start..self.pos].iter().collect())
279 }
280
281 fn string(&mut self) -> Result<String, SelectError> {
282 let quote = self.peek().expect("called at a quote");
283 let open = self.pos;
284 self.pos += 1;
285 let mut out = String::new();
286 loop {
287 match self.peek() {
288 None => {
289 self.pos = open;
290 return self.error("unterminated string");
291 }
292 Some(c) if c == quote => {
293 self.pos += 1;
294 return Ok(out);
295 }
296 Some('\\') => {
297 self.pos += 1;
298 let escaped = match self.peek() {
299 Some('n') => '\n',
300 Some('t') => '\t',
301 Some('r') => '\r',
302 Some(c @ ('\\' | '\'' | '"' | '/')) => c,
303 Some(c) => return self.error(format!("unknown escape `\\{c}`")),
304 None => return self.error("unterminated string"),
305 };
306 out.push(escaped);
307 self.pos += 1;
308 }
309 Some(c) => {
310 out.push(c);
311 self.pos += 1;
312 }
313 }
314 }
315 }
316
317 fn integer(&mut self) -> Result<i64, SelectError> {
318 let start = self.pos;
319 if self.peek() == Some('-') {
320 self.pos += 1;
321 }
322 while self.peek().is_some_and(|c| c.is_ascii_digit()) {
323 self.pos += 1;
324 }
325 let text: String = self.chars[start..self.pos].iter().collect();
326 text.parse().or_else(|_| {
327 self.pos = start;
328 self.error("expected an integer")
329 })
330 }
331
332 fn path(&mut self) -> Result<Vec<Step>, SelectError> {
333 let mut steps = Vec::new();
334 self.blanks();
335 if !self.eat('$') && self.peek().is_some_and(is_name_char) {
336 steps.push(Step {
337 descendant: false,
338 selectors: vec![Sel::Name(self.name()?)],
339 });
340 }
341 loop {
342 match self.peek() {
343 None => break,
344 Some('.') if self.peek_at(1) == Some('.') => {
345 self.pos += 2;
346 let selectors = match self.peek() {
347 Some('[') => self.bracket()?,
348 Some('*') => {
349 self.pos += 1;
350 vec![Sel::Wildcard]
351 }
352 _ => vec![Sel::Name(self.name()?)],
353 };
354 steps.push(Step {
355 descendant: true,
356 selectors,
357 });
358 }
359 Some('.') => {
360 self.pos += 1;
361 let selectors = if self.eat('*') {
362 vec![Sel::Wildcard]
363 } else {
364 vec![Sel::Name(self.name()?)]
365 };
366 steps.push(Step {
367 descendant: false,
368 selectors,
369 });
370 }
371 Some('[') => {
372 let selectors = self.bracket()?;
373 steps.push(Step {
374 descendant: false,
375 selectors,
376 });
377 }
378 Some(c) if c.is_whitespace() => {
379 self.blanks();
380 if self.peek().is_some() {
381 return self.error("unexpected text after the path");
382 }
383 }
384 Some(c) => return self.error(format!("unexpected `{c}`")),
385 }
386 }
387 Ok(steps)
388 }
389
390 fn bracket(&mut self) -> Result<Vec<Sel>, SelectError> {
393 self.expect('[')?;
394 self.blanks();
395 let mut selectors = Vec::new();
396 loop {
397 self.blanks();
398 match self.peek() {
399 Some('*') => {
400 self.pos += 1;
401 selectors.push(Sel::Wildcard);
402 }
403 Some('?') => {
404 self.pos += 1;
405 self.blanks();
406 selectors.push(Sel::Filter(Box::new(self.or()?)));
407 }
408 Some('\'' | '"') => selectors.push(Sel::Name(self.string()?)),
409 Some(c) if c == '-' || c == ':' || c.is_ascii_digit() => {
410 selectors.push(self.index_or_slice()?);
411 }
412 Some(c) => return self.error(format!("unexpected `{c}` in brackets")),
413 None => return self.error("expected `]`"),
414 }
415 self.blanks();
416 if !self.eat(',') {
417 break;
418 }
419 }
420 self.expect(']')?;
421 Ok(selectors)
422 }
423
424 fn index_or_slice(&mut self) -> Result<Sel, SelectError> {
425 let bound = |p: &mut Parser| -> Result<Option<i64>, SelectError> {
426 p.blanks();
427 if p.peek().is_some_and(|c| c == '-' || c.is_ascii_digit()) {
428 p.integer().map(Some)
429 } else {
430 Ok(None)
431 }
432 };
433 let start = bound(self)?;
434 self.blanks();
435 if !self.eat(':') {
436 return match start {
437 Some(index) => Ok(Sel::Index(index)),
438 None => self.error("expected an index"),
439 };
440 }
441 let end = bound(self)?;
442 self.blanks();
443 let step = if self.eat(':') {
444 let at = self.pos;
445 match bound(self)? {
446 Some(0) => {
447 self.pos = at;
448 return self.error("slice step cannot be 0");
449 }
450 Some(step) => step,
451 None => 1,
452 }
453 } else {
454 1
455 };
456 Ok(Sel::Slice(start, end, step))
457 }
458
459 fn or(&mut self) -> Result<Expr, SelectError> {
460 let mut terms = vec![self.and()?];
461 loop {
462 self.blanks();
463 if self.peek() == Some('|') && self.peek_at(1) == Some('|') {
464 self.pos += 2;
465 terms.push(self.and()?);
466 } else if terms.len() == 1 {
467 return Ok(terms.pop().expect("one term"));
468 } else {
469 return Ok(Expr::Or(terms));
470 }
471 }
472 }
473
474 fn and(&mut self) -> Result<Expr, SelectError> {
475 let mut terms = vec![self.unary()?];
476 loop {
477 self.blanks();
478 if self.peek() == Some('&') && self.peek_at(1) == Some('&') {
479 self.pos += 2;
480 terms.push(self.unary()?);
481 } else if terms.len() == 1 {
482 return Ok(terms.pop().expect("one term"));
483 } else {
484 return Ok(Expr::And(terms));
485 }
486 }
487 }
488
489 fn nest(&mut self) -> Result<(), SelectError> {
491 if self.depth >= MAX_FILTER_DEPTH {
492 return self.error(format!(
493 "filter nested too deeply (more than {MAX_FILTER_DEPTH} levels)"
494 ));
495 }
496 self.depth += 1;
497 Ok(())
498 }
499
500 fn unary(&mut self) -> Result<Expr, SelectError> {
501 self.blanks();
502 if self.peek() == Some('!') && self.peek_at(1) != Some('=') {
503 self.nest()?;
504 self.pos += 1;
505 let inner = self.unary()?;
506 self.depth -= 1;
507 return Ok(Expr::Not(Box::new(inner)));
508 }
509 if self.peek() == Some('(') {
510 self.nest()?;
511 self.pos += 1;
512 let inner = self.or()?;
513 self.blanks();
514 self.expect(')')?;
515 self.depth -= 1;
516 return Ok(inner);
517 }
518 let left = self.operand()?;
519 self.blanks();
520 let op = match (self.peek(), self.peek_at(1)) {
521 (Some('='), Some('=')) => Some((Op::Eq, 2)),
522 (Some('!'), Some('=')) => Some((Op::Ne, 2)),
523 (Some('<'), Some('=')) => Some((Op::Le, 2)),
524 (Some('>'), Some('=')) => Some((Op::Ge, 2)),
525 (Some('<'), _) => Some((Op::Lt, 1)),
526 (Some('>'), _) => Some((Op::Gt, 1)),
527 (Some('='), _) => return self.error("expected `==`"),
528 _ => None,
529 };
530 let Some((op, width)) = op else {
531 return Ok(Expr::Exists(left));
532 };
533 self.pos += width;
534 self.blanks();
535 let right = self.operand()?;
536 Ok(Expr::Compare(left, op, right))
537 }
538
539 fn operand(&mut self) -> Result<Operand, SelectError> {
541 self.blanks();
542 match self.peek() {
543 Some(anchor @ ('@' | '$')) => {
544 self.pos += 1;
545 let mut keys = Vec::new();
546 let mut negatives = Vec::new();
547 loop {
548 match self.peek() {
549 Some('.') if self.peek_at(1) != Some('.') => {
550 self.pos += 1;
551 keys.push(PathSegment::Key(self.name()?));
552 }
553 Some('[') => {
554 self.pos += 1;
555 self.blanks();
556 match self.peek() {
557 Some('\'' | '"') => keys.push(PathSegment::Key(self.string()?)),
558 _ => {
559 let index = self.integer()?;
560 if index < 0 {
561 negatives.push(keys.len() as i64);
562 }
563 let magnitude = usize::try_from(index.unsigned_abs())
565 .unwrap_or(usize::MAX);
566 keys.push(PathSegment::Index(magnitude));
567 }
568 }
569 self.blanks();
570 self.expect(']')?;
571 }
572 _ => break,
573 }
574 }
575 Ok(if anchor == '@' {
576 Operand::Current(keys, negatives)
577 } else {
578 Operand::Root(keys, negatives)
579 })
580 }
581 Some('\'' | '"') => Ok(Operand::Literal(Node::new(Value::String(self.string()?)))),
582 Some(c) if c == '-' || c.is_ascii_digit() => {
583 let start = self.pos;
584 self.pos += 1;
585 while self
586 .peek()
587 .is_some_and(|c| c.is_ascii_digit() || ".eE+-".contains(c))
588 {
589 self.pos += 1;
590 }
591 let text: String = self.chars[start..self.pos].iter().collect();
592 let value = if let Ok(i) = text.parse::<i64>() {
593 Value::Int(i)
594 } else if let Ok(f) = text.parse::<f64>() {
595 Value::Float(f)
596 } else {
597 self.pos = start;
598 return self.error(format!("invalid number `{text}`"));
599 };
600 Ok(Operand::Literal(Node::new(value)))
601 }
602 Some(c) if c.is_ascii_alphabetic() => {
603 let start = self.pos;
604 while self.peek().is_some_and(|c| c.is_ascii_alphabetic()) {
605 self.pos += 1;
606 }
607 let word: String = self.chars[start..self.pos].iter().collect();
608 let value = match word.as_str() {
609 "true" => Value::Bool(true),
610 "false" => Value::Bool(false),
611 "null" => Value::Null,
612 _ => {
613 self.pos = start;
614 return self.error(format!(
615 "unexpected `{word}`; expected `@`, `$` or a literal"
616 ));
617 }
618 };
619 Ok(Operand::Literal(Node::new(value)))
620 }
621 Some(c) => self.error(format!("unexpected `{c}` in filter")),
622 None => self.error("unexpected end of filter"),
623 }
624 }
625 }
626
627 impl JsonPathSelector {
628 pub fn parse(expr: &str) -> Result<Self, SelectError> {
630 let mut parser = Parser {
631 chars: expr.chars().collect(),
632 pos: 0,
633 depth: 0,
634 };
635 if parser.chars.iter().all(|c| c.is_whitespace()) {
636 return parser.error("empty expression");
637 }
638 Ok(JsonPathSelector {
639 steps: parser.path()?,
640 })
641 }
642 }
643
644 fn children<'a>(path: &Path, node: &'a Node) -> Vec<(Path, &'a Node)> {
645 match &node.value {
646 Value::Seq(items) => items
647 .iter()
648 .enumerate()
649 .map(|(i, item)| (path.child_index(i), item))
650 .collect(),
651 Value::Map(entries) => entries
652 .iter()
653 .map(|(k, v)| (path.child_key(k), v))
654 .collect(),
655 _ => Vec::new(),
656 }
657 }
658
659 fn normalize(index: i64, len: usize) -> i64 {
660 if index < 0 {
661 len as i64 + index
662 } else {
663 index
664 }
665 }
666
667 fn resolve<'a>(root: &'a Node, keys: &[PathSegment], negatives: &[i64]) -> Option<&'a Node> {
668 let mut node = root;
669 for (i, key) in keys.iter().enumerate() {
670 node = match key {
671 PathSegment::Key(k) => node.get(k)?,
672 PathSegment::Index(n) => {
673 let n = if negatives.contains(&(i as i64)) {
675 node.len().checked_sub(*n)?
676 } else {
677 *n
678 };
679 node.index(n)?
680 }
681 };
682 }
683 Some(node)
684 }
685
686 fn operand<'a>(operand: &'a Operand, current: &'a Node, root: &'a Node) -> Option<&'a Node> {
687 match operand {
688 Operand::Current(keys, negatives) => resolve(current, keys, negatives),
689 Operand::Root(keys, negatives) => resolve(root, keys, negatives),
690 Operand::Literal(node) => Some(node),
691 }
692 }
693
694 fn number(value: &Value) -> Option<f64> {
695 match value {
696 Value::Int(i) => Some(*i as f64),
697 Value::UInt(u) => Some(*u as f64),
698 Value::Float(f) => Some(*f),
699 _ => None,
700 }
701 }
702
703 fn order(a: &Node, b: &Node) -> Option<Ordering> {
704 match (&a.value, &b.value) {
705 (Value::Int(x), Value::Int(y)) => Some(x.cmp(y)),
706 (Value::String(x), Value::String(y)) => Some(x.cmp(y)),
707 (x, y) => number(x)?.partial_cmp(&number(y)?),
708 }
709 }
710
711 fn compare(a: Option<&Node>, op: Op, b: Option<&Node>) -> bool {
712 let equal = match (a, b) {
713 (None, None) => true,
714 (Some(a), Some(b)) => match (number(&a.value), number(&b.value)) {
715 (Some(x), Some(y)) => order(a, b) == Some(Ordering::Equal) || x == y,
716 _ => value_eq(a, b),
717 },
718 _ => false,
719 };
720 let ordering = match (a, b) {
721 (Some(a), Some(b)) => order(a, b),
722 _ => None,
723 };
724 match op {
725 Op::Eq => equal,
726 Op::Ne => !equal,
727 Op::Lt => ordering == Some(Ordering::Less),
728 Op::Gt => ordering == Some(Ordering::Greater),
729 Op::Le => ordering == Some(Ordering::Less) || (ordering.is_some() && equal),
730 Op::Ge => ordering == Some(Ordering::Greater) || (ordering.is_some() && equal),
731 }
732 }
733
734 fn eval(expr: &Expr, current: &Node, root: &Node) -> bool {
735 match expr {
736 Expr::Or(terms) => terms.iter().any(|t| eval(t, current, root)),
737 Expr::And(terms) => terms.iter().all(|t| eval(t, current, root)),
738 Expr::Not(a) => !eval(a, current, root),
739 Expr::Exists(o) => match o {
740 Operand::Literal(node) => node.value == Value::Bool(true),
741 _ => operand(o, current, root).is_some(),
742 },
743 Expr::Compare(a, op, b) => {
744 compare(operand(a, current, root), *op, operand(b, current, root))
745 }
746 }
747 }
748
749 fn apply<'a>(
750 sel: &Sel,
751 path: &Path,
752 node: &'a Node,
753 root: &'a Node,
754 out: &mut Vec<(Path, &'a Node)>,
755 ) {
756 match sel {
757 Sel::Name(name) => {
758 if let Value::Map(entries) = &node.value {
759 if let Some((k, v)) = entries.iter().rev().find(|(k, _)| k == name) {
760 out.push((path.child_key(k), v));
761 }
762 }
763 }
764 Sel::Wildcard => out.extend(children(path, node)),
765 Sel::Index(index) => {
766 if let Value::Seq(items) = &node.value {
767 let i = normalize(*index, items.len());
768 if let Some(item) = usize::try_from(i).ok().and_then(|i| items.get(i)) {
769 out.push((path.child_index(i as usize), item));
770 }
771 }
772 }
773 Sel::Slice(start, end, step) => {
774 if let Value::Seq(items) = &node.value {
775 let len = items.len() as i64;
776 let step = *step;
777 let clamp = |v: i64, lo: i64, hi: i64| v.max(lo).min(hi);
778 let mut push = |i: i64| {
779 out.push((path.child_index(i as usize), &items[i as usize]));
780 };
781 if step > 0 {
782 let lower = clamp(normalize(start.unwrap_or(0), items.len()), 0, len);
783 let upper = clamp(normalize(end.unwrap_or(len), items.len()), 0, len);
784 let mut i = lower;
785 while i < upper {
786 push(i);
787 let Some(following) = i.checked_add(step) else {
788 break;
789 };
790 i = following;
791 }
792 } else {
793 let upper = clamp(
794 normalize(start.unwrap_or(len - 1), items.len()),
795 -1,
796 len - 1,
797 );
798 let lower =
799 clamp(normalize(end.unwrap_or(-len - 1), items.len()), -1, len - 1);
800 let mut i = upper;
801 while lower < i {
802 push(i);
803 let Some(following) = i.checked_add(step) else {
804 break;
805 };
806 i = following;
807 }
808 }
809 }
810 }
811 Sel::Filter(expr) => {
812 for (child_path, child) in children(path, node) {
813 if eval(expr, child, root) {
814 out.push((child_path, child));
815 }
816 }
817 }
818 }
819 }
820
821 fn too_many() -> SelectError {
822 SelectError::new(
823 format!("the selection matches more than {MAX_SELECTED} nodes"),
824 None,
825 )
826 }
827
828 impl Selector for JsonPathSelector {
829 fn select<'a>(&self, root: &'a Node) -> Result<Vec<(Path, &'a Node)>, SelectError> {
830 let mut current: Vec<(Path, &'a Node)> = vec![(Path::root(), root)];
831 let mut visited = 0usize;
833 for step in &self.steps {
834 let mut next = Vec::new();
835 for (path, node) in ¤t {
836 let targets: Vec<(Path, &'a Node)> = if step.descendant {
837 let mut all = Vec::new();
839 let mut stack = vec![(path.clone(), *node)];
840 while let Some((p, n)) = stack.pop() {
841 visited += 1;
842 if visited > MAX_SELECTED {
843 return Err(too_many());
844 }
845 let mut kids = children(&p, n);
846 kids.reverse();
847 all.push((p, n));
848 stack.extend(kids);
849 }
850 all
851 } else {
852 vec![(path.clone(), *node)]
853 };
854 for (target_path, target) in &targets {
855 for sel in &step.selectors {
856 apply(sel, target_path, target, root, &mut next);
857 }
858 if next.len() > MAX_SELECTED {
859 return Err(too_many());
860 }
861 }
862 }
863 current = next;
864 }
865 Ok(current)
866 }
867 }
868}