1use core::fmt::Write;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{DescendError, IntoKeys, KeysIter, Schema, Transcode};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
34#[repr(transparent)]
35#[serde(transparent)]
36pub struct JsonPathIter<'a>(&'a str);
37
38impl<'a> JsonPathIter<'a> {
39 pub fn new(value: &'a str) -> Self {
41 Self(value)
42 }
43}
44
45impl core::fmt::Display for JsonPathIter<'_> {
46 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47 self.0.fmt(f)
48 }
49}
50
51impl<'a> Iterator for JsonPathIter<'a> {
52 type Item = &'a str;
53
54 fn next(&mut self) -> Option<Self::Item> {
55 enum Close {
56 Inclusive(&'static str),
57 Exclusive(&'static [char]),
58 }
59 use Close::*;
60 for (open, close) in [
61 (".'", Inclusive("'")),
62 (".", Exclusive(&['.', '['])),
63 ("['", Inclusive("']")),
64 ("[", Inclusive("]")),
65 ] {
66 if let Some(rest) = self.0.strip_prefix(open) {
67 let (pre, post) = match close {
68 Exclusive(close) => rest
69 .find(close)
70 .map(|i| rest.split_at(i))
71 .unwrap_or((rest, "")),
72 Inclusive(close) => rest.split_once(close)?,
73 };
74 self.0 = post;
75 return Some(pre);
76 }
77 }
78 None
79 }
80}
81
82impl core::iter::FusedIterator for JsonPathIter<'_> {}
83
84#[derive(
92 Clone, Copy, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash,
93)]
94#[repr(transparent)]
95#[serde(transparent)]
96pub struct JsonPath<T: ?Sized>(pub T);
97
98impl<T> JsonPath<T> {
99 pub fn into_inner(self) -> T {
101 self.0
102 }
103}
104
105impl<T: core::fmt::Display> core::fmt::Display for JsonPath<T> {
106 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107 self.0.fmt(f)
108 }
109}
110
111impl<'a, T: AsRef<str> + ?Sized> IntoKeys for JsonPath<&'a T> {
112 type IntoKeys = KeysIter<JsonPathIter<'a>>;
113 fn into_keys(self) -> Self::IntoKeys {
114 JsonPathIter(self.0.as_ref()).into_keys()
115 }
116}
117
118impl<'a, T: AsRef<str> + ?Sized> IntoKeys for &'a JsonPath<T> {
119 type IntoKeys = <JsonPath<&'a str> as IntoKeys>::IntoKeys;
120 fn into_keys(self) -> Self::IntoKeys {
121 JsonPathIter(self.0.as_ref()).into_keys()
122 }
123}
124
125impl<T: Write + ?Sized> Transcode for JsonPath<T> {
126 type Error = core::fmt::Error;
127
128 fn transcode(
129 &mut self,
130 schema: &Schema,
131 keys: impl IntoKeys,
132 ) -> Result<(), DescendError<Self::Error>> {
133 schema.descend(keys.into_keys(), |_meta, idx_internal| {
134 if let Some((index, internal)) = idx_internal {
135 if let Some(name) = internal.get_name(index) {
136 debug_assert!(!name.contains(['.', '\'', '[', ']']));
137 self.0.write_char('.')?;
138 self.0.write_str(name)?;
139 } else {
140 self.0.write_char('[')?;
141 self.0.write_str(itoa::Buffer::new().format(index))?;
142 self.0.write_char(']')?;
143 }
144 }
145 Ok(())
146 })
147 }
148}