1use crate::{JsonPointer, JsonPointerItem, Key, Property};
8
9enum TokenType {
10 Unknown,
11 Number,
12 String,
13 Wildcard,
14 Escaped,
15}
16
17struct State<P: Property> {
18 num: u64,
19 buf: Vec<u8>,
20 token: TokenType,
21 start_pos: usize,
22 path: Vec<JsonPointerItem<P>>,
23}
24
25impl<P: Property> JsonPointer<P> {
26 pub fn parse(value: &str) -> Self {
27 let mut state = State {
28 num: 0,
29 buf: Vec::new(),
30 token: TokenType::Unknown,
31 start_pos: 0,
32 path: Vec::new(),
33 };
34 let mut iter = value.as_bytes().iter().enumerate();
35
36 while let Some((pos, &ch)) = iter.next() {
37 match (ch, &state.token) {
38 (b'0'..=b'9', TokenType::Unknown | TokenType::Number) => {
39 state.num = state
40 .num
41 .saturating_mul(10)
42 .saturating_add((ch - b'0') as u64);
43 state.token = TokenType::Number;
44 }
45 (b'*', TokenType::Unknown) => {
46 state.token = TokenType::Wildcard;
47 }
48 (b'0', TokenType::Escaped) => {
49 state.buf.push(b'~');
50 state.token = TokenType::String;
51 }
52 (b'1', TokenType::Escaped) => {
53 state.buf.push(b'/');
54 state.token = TokenType::String;
55 }
56 (b'/', _) => {
57 state.process();
58 state.token = TokenType::Unknown;
59 state.start_pos = pos + 1;
60 }
61 (_, _) => {
62 if matches!(&state.token, TokenType::Number | TokenType::Wildcard)
63 && pos > state.start_pos
64 {
65 state.buf.extend_from_slice(
66 value
67 .as_bytes()
68 .get(state.start_pos..pos)
69 .unwrap_or_default(),
70 );
71 }
72
73 state.token = match ch {
74 b'~' if !matches!(&state.token, TokenType::Escaped) => TokenType::Escaped,
75 b'\\' => {
76 state
77 .buf
78 .push(iter.next().map(|(_, &ch)| ch).unwrap_or(b'\\'));
79 TokenType::String
80 }
81 _ => {
82 state.buf.push(ch);
83 TokenType::String
84 }
85 };
86 }
87 }
88 }
89
90 state.process();
91
92 if state.path.is_empty() {
93 state.path.push(JsonPointerItem::Root);
94 }
95
96 JsonPointer(state.path)
97 }
98}
99
100impl<P: Property> State<P> {
101 pub fn process(&mut self) {
102 match self.token {
103 TokenType::String => {
104 let item = std::str::from_utf8(&self.buf).unwrap_or_default();
105 match P::try_parse(self.path.last().and_then(|item| item.as_key()), item) {
106 Some(prop) => {
107 self.path.push(JsonPointerItem::Key(Key::Property(prop)));
108 }
109 None => {
110 self.path
111 .push(JsonPointerItem::Key(Key::Owned(item.to_string())));
112 }
113 }
114
115 self.buf.clear();
116 }
117 TokenType::Number => {
118 self.path.push(JsonPointerItem::Number(self.num));
119 self.num = 0;
120 }
121 TokenType::Wildcard => {
122 self.path.push(JsonPointerItem::Wildcard);
123 }
124 TokenType::Unknown if self.start_pos > 0 => {
125 self.path.push(JsonPointerItem::Key("".into()));
126 }
127 _ => (),
128 }
129 }
130}
131
132impl<'de, P: Property> serde::Deserialize<'de> for JsonPointer<P> {
133 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
134 where
135 D: serde::Deserializer<'de>,
136 {
137 <&str>::deserialize(deserializer).map(|s| JsonPointer::parse(s))
138 }
139}
140
141impl<P: Property> serde::Serialize for JsonPointer<P> {
142 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
143 where
144 S: serde::Serializer,
145 {
146 serializer.serialize_str(&self.to_string())
147 }
148}
149
150#[cfg(test)]
151mod tests {
152
153 use crate::Null;
154
155 use super::{JsonPointer, JsonPointerItem};
156
157 #[test]
158 fn json_pointer_parse() {
159 for (input, output) in vec![
160 ("hello", vec![JsonPointerItem::<Null>::Key("hello".into())]),
161 ("9a", vec![JsonPointerItem::Key("9a".into())]),
162 ("a9", vec![JsonPointerItem::Key("a9".into())]),
163 ("*a", vec![JsonPointerItem::Key("*a".into())]),
164 (
165 "/hello/world",
166 vec![
167 JsonPointerItem::Key("hello".into()),
168 JsonPointerItem::Key("world".into()),
169 ],
170 ),
171 ("*", vec![JsonPointerItem::Wildcard]),
172 (
173 "/hello/*",
174 vec![
175 JsonPointerItem::Key("hello".into()),
176 JsonPointerItem::Wildcard,
177 ],
178 ),
179 ("1234", vec![JsonPointerItem::Number(1234)]),
180 (
181 "/hello/1234",
182 vec![
183 JsonPointerItem::Key("hello".into()),
184 JsonPointerItem::Number(1234),
185 ],
186 ),
187 ("~0~1", vec![JsonPointerItem::Key("~/".into())]),
188 (
189 "/hello/~0~1",
190 vec![
191 JsonPointerItem::Key("hello".into()),
192 JsonPointerItem::Key("~/".into()),
193 ],
194 ),
195 (
196 "/hello/1~0~1/*~1~0",
197 vec![
198 JsonPointerItem::Key("hello".into()),
199 JsonPointerItem::Key("1~/".into()),
200 JsonPointerItem::Key("*/~".into()),
201 ],
202 ),
203 (
204 "/hello/world/*/99",
205 vec![
206 JsonPointerItem::Key("hello".into()),
207 JsonPointerItem::Key("world".into()),
208 JsonPointerItem::Wildcard,
209 JsonPointerItem::Number(99),
210 ],
211 ),
212 ("/", vec![JsonPointerItem::Key("".into())]),
213 (
214 "///",
215 vec![
216 JsonPointerItem::Key("".into()),
217 JsonPointerItem::Key("".into()),
218 JsonPointerItem::Key("".into()),
219 ],
220 ),
221 ("", vec![JsonPointerItem::Root]),
222 ] {
223 assert_eq!(JsonPointer::parse(input).0, output, "{input}");
224 }
225 }
226}