| 1 | use std::fmt::{Display, Formatter}; |
| 2 | |
| 3 | mod iter_any; |
| 4 | mod iter_txn; |
| 5 | mod parse; |
| 6 | |
| 7 | pub use iter_txn::JsonPathIter; |
| 8 | |
| 9 | /// Trait implemented by types capable of evaluating JSON Paths. |
| 10 | pub trait JsonPathEval { |
| 11 | type Iter<'a> |
| 12 | where |
| 13 | Self: 'a; |
| 14 | fn json_path<'a>(&'a self, path: &'a JsonPath<'a>) -> Self::Iter<'a>; |
| 15 | } |
| 16 | |
| 17 | #[derive(Debug, Clone, PartialEq)] |
| 18 | pub struct JsonPath<'a> { |
| 19 | tokens: Vec<JsonPathToken<'a>>, |
| 20 | } |
| 21 | |
| 22 | impl<'a> AsRef<[JsonPathToken<'a>]> for JsonPath<'a> { |
| 23 | fn as_ref(&self) -> &[JsonPathToken<'a>] { |
| 24 | &self.tokens |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | #[derive(Debug, Clone, PartialEq)] |
| 29 | pub(super) enum JsonPathToken<'a> { |
| 30 | Root, |
| 31 | Current, |
| 32 | Member(&'a str), |
| 33 | Index(i32), |
| 34 | Wildcard, |
| 35 | RecursiveDescend, |
| 36 | Slice(u32, u32, u32), |
| 37 | MemberUnion(Vec<&'a str>), |
| 38 | IndexUnion(Vec<i32>), |
| 39 | } |
| 40 | |
| 41 | impl<'a> Display for JsonPathToken<'a> { |
| 42 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
| 43 | match self { |
| 44 | JsonPathToken::Root => write!(f, r#"$"#), |
| 45 | JsonPathToken::Current => write!(f, "@"), |
| 46 | JsonPathToken::Member(key) => { |
| 47 | if key.chars().any(char::is_whitespace) { |
| 48 | write!(f, "['{}']", key) |
| 49 | } else { |
| 50 | write!(f, ".{}", key) |
| 51 | } |
| 52 | } |
| 53 | JsonPathToken::Index(index) => write!(f, "[{}]", index), |
| 54 | JsonPathToken::Wildcard => write!(f, ".*"), |
| 55 | JsonPathToken::RecursiveDescend => write!(f, ".."), |
| 56 | JsonPathToken::Slice(from, to, by) => write!(f, "[{}:{}:{}]", from, to, by), |
| 57 | JsonPathToken::MemberUnion(members) => { |
| 58 | let mut i = members.iter(); |
| 59 | write!(f, "[")?; |
| 60 | if let Some(m) = i.next() { |
| 61 | write!(f, "{}", m)?; |
| 62 | } |
| 63 | while let Some(m) = i.next() { |
| 64 | write!(f, ", {}", m)?; |
| 65 | } |
| 66 | write!(f, "]") |
| 67 | } |
| 68 | JsonPathToken::IndexUnion(indices) => { |
| 69 | let mut i = indices.iter(); |
| 70 | write!(f, "[")?; |
| 71 | if let Some(m) = i.next() { |
| 72 | write!(f, "{}", m)?; |
| 73 | } |
| 74 | while let Some(m) = i.next() { |
| 75 | write!(f, ", {}", m)?; |
| 76 | } |
| 77 | write!(f, "]") |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | #[derive(Debug, thiserror::Error)] |
| 84 | pub enum ParseError { |
| 85 | #[error("{0}")] |
| 86 | InvalidJsonPath(String), |
| 87 | } |
| 88 | |