1use std::convert::TryFrom;
2
3use anyhow::{anyhow, bail};
4
5pub type JsonPath = Vec<JsonPathStep>;
16
17#[derive(Debug, Clone)]
21pub enum JsonPathStep {
22 Key(String),
23 Index(usize),
24}
25
26pub struct JsonPathLiteral<'a>(pub &'a str);
28
29impl<'a> std::ops::Deref for JsonPathLiteral<'a> {
30 type Target = &'a str;
31
32 fn deref(&self) -> &Self::Target {
33 &self.0
34 }
35}
36
37impl<'a> From<&'a str> for JsonPathLiteral<'a> {
38 fn from(s: &'a str) -> Self {
39 JsonPathLiteral(s)
40 }
41}
42
43impl<'a> TryFrom<JsonPathLiteral<'a>> for JsonPath {
44 type Error = anyhow::Error;
45
46 fn try_from(path: JsonPathLiteral<'a>) -> Result<Self, Self::Error> {
51 let mut steps: Vec<JsonPathStep> = vec![];
52 let raw_steps = path.split('.');
53
54 for step in raw_steps {
55 if let Ok((step_key, step_index)) = try_parse_indexed_field(step) {
56 steps.push(JsonPathStep::Key(step_key.to_string()));
57 steps.push(JsonPathStep::Index(step_index));
58 } else {
59 steps.push(JsonPathStep::Key(step.to_string()))
60 };
61 }
62 Ok(steps)
63 }
64}
65
66fn try_parse_indexed_field(step: &str) -> Result<(String, usize), anyhow::Error> {
68 let chars: Vec<char> = step.chars().collect();
69 let index_open = chars.iter().position(|c| c == &'[');
70 let index_close = chars.iter().position(|c| c == &']');
71
72 if index_open.is_none() {
73 bail!("open index bracket not found");
74 }
75 if index_close.is_none() {
76 bail!("close index bracket not found");
77 }
78 if index_open > index_close {
79 bail!("open bracket is ahead of close bracket")
80 }
81 if index_close.unwrap() != chars.len() - 1 {
82 bail!("the close bracket must be the last character")
83 }
84
85 let index_str: String = chars[index_open.unwrap() + 1..index_close.unwrap()]
86 .iter()
87 .collect();
88
89 let index: usize = index_str
90 .parse()
91 .map_err(|e| anyhow!("unable to parse '{}' into usize: {}", index_str, e))?;
92 let key: String = chars[0..index_open.unwrap()].iter().collect();
93
94 Ok((key, index))
95}
96
97#[cfg(test)]
98mod test {
99 use super::*;
100
101 #[test]
102 fn test_parse_indexed_field() {
103 let input = "data[1]";
104 let (key, index) = try_parse_indexed_field(input).unwrap();
105
106 assert_eq!("data", key);
107 assert_eq!(1, index);
108
109 let input = "数据[3]";
110 let (key, index) = try_parse_indexed_field(input).unwrap();
111
112 assert_eq!("数据", key);
113 assert_eq!(3, index);
114
115 let input = "data---__[1]";
116 let (key, index) = try_parse_indexed_field(input).unwrap();
117
118 assert_eq!("data---__", key);
119 assert_eq!(1, index);
120
121 let input = "";
122 assert!(try_parse_indexed_field(input).is_err());
123 assert_eq!(
124 try_parse_indexed_field(input).unwrap_err().to_string(),
125 "open index bracket not found"
126 );
127
128 let input = "da[0]ta";
129 assert!(try_parse_indexed_field(input).is_err());
130 assert_eq!(
131 try_parse_indexed_field(input).unwrap_err().to_string(),
132 "the close bracket must be the last character"
133 );
134
135 let input = "data[string]";
136 assert!(try_parse_indexed_field(input).is_err());
137 assert_eq!(
138 try_parse_indexed_field(input).unwrap_err().to_string(),
139 "unable to parse 'string' into usize: invalid digit found in string"
140 );
141 }
142}