1use core::{fmt, ops::Deref, str::FromStr};
2use std::borrow::{Borrow, Cow};
3
4use serde::{Deserialize, Serialize};
5
6use crate::BytesBuf;
7
8#[macro_export]
9macro_rules! json_pointer {
10 ($value:literal) => {
11 const {
12 match $crate::JsonPointer::from_str_const($value) {
13 Ok(p) => p,
14 Err(_) => panic!("invalid JSON pointer"),
15 }
16 }
17 };
18}
19
20#[derive(Debug, Clone, Copy, thiserror::Error)]
21#[error("invalid JSON pointer `{0}`")]
22pub struct InvalidJsonPointer<T = String>(pub T);
23
24#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[repr(transparent)]
29pub struct JsonPointer(str);
30
31impl Default for &JsonPointer {
32 fn default() -> Self {
33 JsonPointer::ROOT
34 }
35}
36
37impl JsonPointer {
38 pub const ROOT: &'static Self = json_pointer!("");
39
40 pub fn new<S>(s: &S) -> Result<&Self, InvalidJsonPointer<&S>>
42 where
43 S: AsRef<[u8]> + ?Sized,
44 {
45 core::str::from_utf8(s.as_ref())
46 .ok()
47 .and_then(|s| Self::from_str_const(s).ok())
48 .ok_or(InvalidJsonPointer(s))
49 }
50
51 pub const fn from_str_const(s: &str) -> Result<&Self, InvalidJsonPointer<&str>> {
52 if Self::validate_str(s) {
53 Ok(unsafe { Self::new_unchecked_str(s) })
54 } else {
55 Err(InvalidJsonPointer(s))
56 }
57 }
58
59 pub const unsafe fn new_unchecked_str(s: &str) -> &Self {
65 std::mem::transmute(s)
66 }
67
68 pub const unsafe fn new_unchecked(s: &[u8]) -> &Self {
74 Self::new_unchecked_str(core::str::from_utf8_unchecked(s))
75 }
76
77 pub const fn validate_bytes(s: &[u8]) -> bool {
80 match core::str::from_utf8(s) {
81 Ok(s) => Self::validate_str(s),
82 Err(_) => false,
83 }
84 }
85
86 pub const fn validate_str(s: &str) -> bool {
89 let bytes = s.as_bytes();
90
91 if !matches!(bytes, [] | [b'/', ..]) {
92 return false;
93 }
94
95 let mut i = 0;
96 while i < bytes.len() {
97 if bytes[i] == b'~' {
99 i += 1;
100 if i >= bytes.len() || !matches!(bytes[i], b'0' | b'1') {
101 return false;
102 }
103 }
104
105 i += 1
106 }
107
108 true
109 }
110
111 pub fn as_bytes(&self) -> &[u8] {
112 self.0.as_bytes()
113 }
114
115 pub fn as_str(&self) -> &str {
116 &self.0
117 }
118
119 pub fn is_empty(&self) -> bool {
120 self.0.is_empty()
121 }
122
123 pub fn split_first(&self) -> Option<(&ReferenceToken, &Self)> {
124 self.0.strip_prefix("/").map(|s| {
125 let (left, right) = s.find("/").map(|idx| s.split_at(idx)).unwrap_or((s, ""));
126 let token = unsafe { ReferenceToken::new_unchecked(left) };
129 let remaining = unsafe { Self::new_unchecked_str(right) };
130 (token, remaining)
131 })
132 }
133
134 pub fn iter(&self) -> JsonPointerIter {
135 let mut tokens = self.0.split('/');
136 tokens.next();
137 JsonPointerIter(tokens)
138 }
139}
140
141impl ToOwned for JsonPointer {
142 type Owned = JsonPointerBuf;
143
144 fn to_owned(&self) -> Self::Owned {
145 JsonPointerBuf(self.0.to_owned())
146 }
147}
148
149impl AsRef<JsonPointer> for JsonPointer {
150 fn as_ref(&self) -> &JsonPointer {
151 self
152 }
153}
154
155impl fmt::Display for JsonPointer {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 self.as_str().fmt(f)
158 }
159}
160
161impl<'a> IntoIterator for &'a JsonPointer {
162 type Item = &'a ReferenceToken;
163 type IntoIter = JsonPointerIter<'a>;
164
165 fn into_iter(self) -> Self::IntoIter {
166 self.iter()
167 }
168}
169
170pub struct JsonPointerIter<'a>(std::str::Split<'a, char>);
171
172impl<'a> Iterator for JsonPointerIter<'a> {
173 type Item = &'a ReferenceToken;
174
175 fn next(&mut self) -> Option<Self::Item> {
176 self.0.next().map(|s| unsafe { std::mem::transmute(s) })
177 }
178}
179
180impl<'de> Deserialize<'de> for &'de JsonPointer {
181 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
182 where
183 D: serde::Deserializer<'de>,
184 {
185 let s: &str = <&str as Deserialize>::deserialize(deserializer)?;
186 JsonPointer::new(s).map_err(serde::de::Error::custom)
187 }
188}
189
190#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
194pub struct JsonPointerBuf(String);
195
196impl Default for JsonPointerBuf {
197 fn default() -> Self {
198 JsonPointer::ROOT.to_owned()
199 }
200}
201
202impl JsonPointerBuf {
203 pub fn new<B: BytesBuf>(value: B) -> Result<Self, InvalidJsonPointer<B>> {
205 if JsonPointer::validate_bytes(value.as_ref()) {
206 let v: Vec<u8> = value.into();
207 Ok(Self(unsafe { String::from_utf8_unchecked(v) }))
210 } else {
211 Err(InvalidJsonPointer(value))
212 }
213 }
214
215 pub fn push(&mut self, token: &str) {
216 self.0.reserve(1 + token.len());
217 self.0.push('/');
218 for c in token.chars() {
219 match c {
220 '~' => self.0.push_str("~0"),
221 '/' => self.0.push_str("~1"),
222 _ => self.0.push(c),
223 }
224 }
225 }
226
227 pub fn push_index(&mut self, i: usize) {
228 use core::fmt::Write;
229 write!(self.0, "/{i}").unwrap()
230 }
231
232 pub fn as_json_pointer(&self) -> &JsonPointer {
233 unsafe {
234 JsonPointer::new_unchecked_str(&self.0)
237 }
238 }
239}
240
241impl Deref for JsonPointerBuf {
242 type Target = JsonPointer;
243
244 fn deref(&self) -> &Self::Target {
245 self.as_json_pointer()
246 }
247}
248
249impl Borrow<JsonPointer> for JsonPointerBuf {
250 fn borrow(&self) -> &JsonPointer {
251 self.as_json_pointer()
252 }
253}
254
255impl AsRef<JsonPointer> for JsonPointerBuf {
256 fn as_ref(&self) -> &JsonPointer {
257 self.as_json_pointer()
258 }
259}
260
261impl FromStr for JsonPointerBuf {
262 type Err = InvalidJsonPointer;
263
264 fn from_str(s: &str) -> Result<Self, Self::Err> {
265 s.to_owned().try_into()
266 }
267}
268
269impl TryFrom<String> for JsonPointerBuf {
270 type Error = InvalidJsonPointer;
271
272 fn try_from(value: String) -> Result<Self, Self::Error> {
273 if JsonPointer::validate_str(&value) {
274 Ok(Self(value))
275 } else {
276 Err(InvalidJsonPointer(value))
277 }
278 }
279}
280
281impl fmt::Display for JsonPointerBuf {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 self.as_str().fmt(f)
284 }
285}
286
287impl<'de> Deserialize<'de> for JsonPointerBuf {
288 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289 where
290 D: serde::Deserializer<'de>,
291 {
292 String::deserialize(deserializer)?
293 .try_into()
294 .map_err(serde::de::Error::custom)
295 }
296}
297
298#[derive(Debug)]
299#[repr(transparent)]
300pub struct ReferenceToken(str);
301
302impl ReferenceToken {
303 pub const unsafe fn new_unchecked(s: &str) -> &Self {
310 std::mem::transmute(s)
311 }
312
313 pub fn is_escaped(&self) -> bool {
314 self.0.contains("~")
315 }
316
317 pub fn as_bytes(&self) -> &[u8] {
318 self.0.as_bytes()
319 }
320
321 pub fn as_str(&self) -> &str {
322 &self.0
323 }
324
325 pub fn to_decoded(&self) -> Cow<str> {
326 if self.is_escaped() {
327 Cow::Owned(self.decode())
328 } else {
329 Cow::Borrowed(self.as_str())
330 }
331 }
332
333 pub fn decode(&self) -> String {
334 let mut buf = String::with_capacity(self.0.len());
335 let mut chars = self.0.chars();
336 buf.extend(core::iter::from_fn(|| {
337 Some(match chars.next()? {
338 '~' => match chars.next() {
339 Some('0') => '~',
340 Some('1') => '/',
341 _ => unreachable!(),
342 },
343 c => c,
344 })
345 }));
346 buf
347 }
348
349 pub fn as_array_index(&self) -> Option<usize> {
350 match self.0.as_bytes() {
352 [c @ b'0'..=b'9'] => Some((c - b'0') as usize),
353 [b'1'..=b'9', ..] => self.0.parse().ok(),
354 _ => None,
355 }
356 }
357}
358
359impl fmt::Display for ReferenceToken {
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 self.as_str().fmt(f)
362 }
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368
369 #[test]
370 fn test_serde_borrow() {
371 let s = String::from("\"/foo/b~1ar\"");
372 let p: JsonPointerBuf = serde_json::from_str(&s).unwrap();
373 let jp: &JsonPointer = serde_json::from_str(&s).unwrap();
374 assert_eq!(p.0, jp.0);
375
376 serde_json::from_str::<&JsonPointer>("\"invalid\"").unwrap_err();
377 }
378}