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