1use yo_common::{Code, Error, Result};
45
46use crate::head::Kind;
47use crate::read::Value;
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum Step<'a> {
52 Key(&'a [u8]),
54 Index(i64),
57}
58
59#[derive(Debug, Clone)]
65pub struct Steps<'a> {
66 rest: &'a [u8],
67}
68
69impl<'a> Steps<'a> {
70 #[must_use]
75 pub fn new(path: &'a [u8]) -> Steps<'a> {
76 let rest = path.strip_prefix(b"$").unwrap_or(path);
77 Steps { rest }
78 }
79}
80
81impl<'a> Iterator for Steps<'a> {
82 type Item = Result<Step<'a>>;
83
84 fn next(&mut self) -> Option<Result<Step<'a>>> {
85 if self.rest.is_empty() {
86 return None;
87 }
88 Some(self.step())
89 }
90}
91
92impl<'a> Steps<'a> {
93 fn step(&mut self) -> Result<Step<'a>> {
94 match self.rest[0] {
95 b'.' => {
96 self.rest = &self.rest[1..];
97 if self.rest.first() == Some(&b'.') {
98 return Err(bad(
99 "a descent, `..`, names more than one place, so it is read by `Path` and not here",
100 ));
101 }
102 let end = self
103 .rest
104 .iter()
105 .position(|&c| c == b'.' || c == b'[')
106 .unwrap_or(self.rest.len());
107 if end == 0 {
108 return Err(bad("a `.` with no name after it"));
109 }
110 let (name, rest) = self.rest.split_at(end);
111 self.rest = rest;
112 Ok(Step::Key(name))
113 }
114 b'[' => self.bracket(),
115 _ => {
116 let end = self
119 .rest
120 .iter()
121 .position(|&c| c == b'.' || c == b'[')
122 .unwrap_or(self.rest.len());
123 let (name, rest) = self.rest.split_at(end);
124 self.rest = rest;
125 Ok(Step::Key(name))
126 }
127 }
128 }
129
130 fn bracket(&mut self) -> Result<Step<'a>> {
131 let body = &self.rest[1..];
132 let Some(close) = body.iter().position(|&c| c == b']') else {
133 return Err(bad("a `[` with no `]` after it"));
134 };
135 let inner = &body[..close];
136 self.rest = &body[close + 1..];
137 if inner == b"*" {
138 return Err(bad(
139 "a wildcard, `[*]`, names more than one place, so it is read by `Path` and not here",
140 ));
141 }
142 if let Some(quoted) = quoted(inner) {
143 return Ok(Step::Key(quoted));
144 }
145 let text = core::str::from_utf8(inner).map_err(|_| bad("an index that is not a number"))?;
146 let i: i64 = text
147 .parse()
148 .map_err(|_| bad("an index that is not a number"))?;
149 Ok(Step::Index(i))
150 }
151}
152
153fn quoted(inner: &[u8]) -> Option<&[u8]> {
155 if inner.len() >= 2 {
156 let (first, last) = (inner[0], inner[inner.len() - 1]);
157 if (first == b'"' || first == b'\'') && last == first {
158 return Some(&inner[1..inner.len() - 1]);
159 }
160 }
161 None
162}
163
164impl<'a> Value<'a> {
165 pub fn path(&self, path: &str) -> Result<Option<Value<'a>>> {
170 self.path_bytes(path.as_bytes())
171 }
172
173 pub fn path_bytes(&self, path: &[u8]) -> Result<Option<Value<'a>>> {
176 let mut at = *self;
177 for step in Steps::new(path) {
178 let Some(next) = at.step(step?) else {
179 return Ok(None);
180 };
181 at = next;
182 }
183 Ok(Some(at))
184 }
185
186 #[must_use]
188 pub fn step(&self, step: Step<'_>) -> Option<Value<'a>> {
189 match step {
190 Step::Key(k) => self.get(k),
191 Step::Index(i) => {
192 if self.kind() != Kind::Array {
193 return None;
194 }
195 let n = self.len();
196 let at = if i < 0 {
197 n.checked_sub(i.unsigned_abs() as usize)?
198 } else {
199 i as usize
200 };
201 self.at(at)
202 }
203 }
204 }
205}
206
207fn bad(what: &str) -> Error {
208 Error::new(Code::Invalid, what)
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214 use crate::Builder;
215
216 fn doc() -> Vec<u8> {
218 let mut b = Builder::new();
219 b.begin_object().expect("open");
220 b.key(b"a").expect("key");
221 b.begin_object().expect("open");
222 b.key(b"b").expect("key");
223 b.begin_array().expect("open");
224 b.int(10).expect("value");
225 b.int(20).expect("value");
226 b.begin_object().expect("open");
227 b.key(b"c").expect("key");
228 b.text("deep").expect("value");
229 b.end_object().expect("close");
230 b.end_array().expect("close");
231 b.end_object().expect("close");
232 b.key(b"empty").expect("key");
233 b.begin_object().expect("open");
234 b.end_object().expect("close");
235 b.end_object().expect("close");
236 b.finish().expect("finished").to_vec()
237 }
238
239 #[test]
240 fn a_path_reaches_what_it_names() {
241 let bytes = doc();
242 let v = Value::new(&bytes).expect("readable");
243 let at = |p: &str| v.path(p).expect("the path parses");
244 assert_eq!(at("$.a.b[0]").expect("there").as_int(), Some(10));
245 assert_eq!(at("$.a.b[2].c").expect("there").as_text(), Some("deep"));
246 assert_eq!(at("$.a.b[-1].c").expect("there").as_text(), Some("deep"));
247 assert_eq!(at("$.a.b[-3]").expect("there").as_int(), Some(10));
248 assert_eq!(at("$").expect("there").len(), 2);
249 assert_eq!(at("").expect("there").len(), 2);
250 assert_eq!(at("$.a.b[0]").expect("there").as_int(), Some(10));
252 assert_eq!(at("$[\"a\"][\"b\"][0]").expect("there").as_int(), Some(10));
253 assert_eq!(at("a.b[0]").expect("there").as_int(), Some(10));
254 assert_eq!(at("$['a'].b[0]").expect("there").as_int(), Some(10));
255 }
256
257 #[test]
258 fn a_path_that_names_nothing_is_an_answer_and_not_a_failure() {
259 let bytes = doc();
260 let v = Value::new(&bytes).expect("readable");
261 let at = |p: &str| v.path(p).expect("the path parses");
262 assert!(at("$.nope").is_none());
263 assert!(at("$.a.nope.deeper").is_none());
264 assert!(at("$.a.b[3]").is_none(), "past the end");
265 assert!(at("$.a.b[-4]").is_none(), "past the start");
266 assert!(at("$.empty.anything").is_none());
267 assert!(at("$.a.b.c").is_none(), "a name into an array");
268 assert!(at("$.a[0]").is_none(), "an index into an object");
269 assert!(at("$.a.b[0][0]").is_none(), "an index into a number");
270 }
271
272 #[test]
273 fn a_path_that_does_not_parse_says_so() {
274 let bytes = doc();
275 let v = Value::new(&bytes).expect("readable");
276 let why = |p: &str| v.path(p).unwrap_err().message().to_string();
277 assert!(why("$.a[").contains("no `]`"));
278 assert!(why("$.a[x]").contains("not a number"));
279 assert!(why("$..a").contains("more than one place"));
280 assert!(why("$.a[*]").contains("more than one place"));
281 assert!(why("$.a.").contains("no name after it"));
282 }
283
284 #[test]
285 fn the_steps_of_a_path_are_what_they_look_like() {
286 let steps: Vec<Step<'_>> = Steps::new(b"$.a[3].bb[-1][\"c c\"]")
287 .map(|s| s.expect("parses"))
288 .collect();
289 assert_eq!(
290 steps,
291 [
292 Step::Key(b"a"),
293 Step::Index(3),
294 Step::Key(b"bb"),
295 Step::Index(-1),
296 Step::Key(b"c c"),
297 ]
298 );
299 }
300
301 #[test]
302 fn a_path_over_bytes_reads_the_same_as_a_path_over_text() {
303 let bytes = doc();
304 let v = Value::new(&bytes).expect("readable");
305 let one = v.path("$.a.b[1]").expect("parses").expect("there");
306 let two = v.path_bytes(b"$.a.b[1]").expect("parses").expect("there");
307 assert_eq!(one.as_int(), two.as_int());
308 }
309}