zenoh_keyexpr/key_expr/format/
parsing.rs1use zenoh_result::{bail, ZResult};
16
17use super::{IKeFormatStorage, KeFormat, Segment};
18use crate::key_expr::keyexpr;
19
20pub struct Parsed<'s, Storage: IKeFormatStorage<'s>> {
21 format: &'s KeFormat<'s, Storage>,
22 results: Storage::ValuesStorage<Option<&'s keyexpr>>,
23}
24
25impl<'s, Storage: IKeFormatStorage<'s>> Parsed<'s, Storage> {
26 pub fn get(&self, id: &str) -> ZResult<&'s str> {
33 let Some(i) = self
34 .format
35 .storage
36 .segments()
37 .iter()
38 .position(|s| s.spec.id() == id)
39 else {
40 bail!("{} has no {id} field", self.format)
41 };
42 Ok(self.results.as_ref()[i].map_or("", keyexpr::as_str))
43 }
44 pub fn values(&self) -> &[Option<&'s keyexpr>] {
46 self.results.as_ref()
47 }
48 pub fn iter(&'s self) -> Iter<'s, Storage> {
50 self.into_iter()
51 }
52}
53
54impl<'s, Storage: IKeFormatStorage<'s>> IntoIterator for &'s Parsed<'s, Storage> {
55 type Item = <Self::IntoIter as Iterator>::Item;
56 type IntoIter = Iter<'s, Storage>;
57 fn into_iter(self) -> Self::IntoIter {
58 Iter {
59 parsed: self,
60 start: 0,
61 end: self.format.storage.segments().len(),
62 }
63 }
64}
65pub struct Iter<'s, Storage: IKeFormatStorage<'s>> {
66 parsed: &'s Parsed<'s, Storage>,
67 start: usize,
68 end: usize,
69}
70impl<'s, Storage: IKeFormatStorage<'s>> Iterator for Iter<'s, Storage> {
71 type Item = (&'s str, Option<&'s keyexpr>);
72 fn next(&mut self) -> Option<Self::Item> {
73 if self.start < self.end {
74 let id = self.parsed.format.storage.segments()[self.start].spec.id();
75 let ke = self.parsed.results.as_ref()[self.start];
76 self.start += 1;
77 Some((id, ke))
78 } else {
79 None
80 }
81 }
82 fn nth(&mut self, n: usize) -> Option<Self::Item> {
83 self.start += n;
84 self.next()
85 }
86 fn size_hint(&self) -> (usize, Option<usize>) {
87 let result = self.end - self.start;
88 (result, Some(result))
89 }
90}
91impl<'s, Storage: IKeFormatStorage<'s>> ExactSizeIterator for Iter<'s, Storage> {
92 fn len(&self) -> usize {
93 self.end - self.start
94 }
95}
96impl<'s, Storage: IKeFormatStorage<'s>> DoubleEndedIterator for Iter<'s, Storage> {
97 fn next_back(&mut self) -> Option<Self::Item> {
98 if self.start < self.end {
99 self.end -= 1;
100 let id = self.parsed.format.storage.segments()[self.end].spec.id();
101 let ke = self.parsed.results.as_ref()[self.end];
102 Some((id, ke))
103 } else {
104 None
105 }
106 }
107}
108
109impl<'s, Storage: IKeFormatStorage<'s> + 's> KeFormat<'s, Storage> {
110 pub fn parse(&'s self, target: &'s keyexpr) -> ZResult<Parsed<'s, Storage>> {
117 let segments = self.storage.segments();
118 if segments.is_empty()
119 && !target.intersects(unsafe { keyexpr::from_str_unchecked(self.suffix) })
121 {
122 bail!("{target} does not intersect with {self}")
123 }
124 let mut results = self.storage.values_storage(|_| None);
125 let results_mut = results.as_mut();
126 debug_assert_eq!(segments.len(), results_mut.len());
127 let found = 'a: {
128 match self.suffix.as_bytes() {
129 [] => do_parse(Some(target), segments, results_mut),
130 [b'/', suffix @ ..] => {
131 let suffix = unsafe { keyexpr::from_slice_unchecked(suffix) };
133 for (target, candidate) in target.iter_splits_rtl() {
134 if suffix.intersects(candidate)
135 && do_parse(Some(target), segments, results_mut)
136 {
137 break 'a true;
138 }
139 }
140 suffix.intersects(target) && do_parse(None, segments, results_mut)
141 }
142 _ => {
143 unreachable!();
144 }
145 }
146 };
147 if found {
148 Ok(Parsed {
149 format: self,
150 results,
151 })
152 } else {
153 bail!("{target} does not intersect with {self}")
154 }
155 }
156}
157
158fn do_parse<'a>(
159 target: Option<&'a keyexpr>,
160 segments: &[Segment],
161 results: &mut [Option<&'a keyexpr>],
162) -> bool {
163 match (segments, results) {
164 ([], []) => target.map_or(true, keyexpr::is_double_wild),
165 ([segment, segments @ ..], [result, results @ ..]) => {
166 let prefix = segment.prefix();
167 let pattern = segment.pattern();
168 let Some(target) = target else {
170 if prefix.is_none() && pattern.is_double_wild() {
172 *result = None;
173 return !segments.iter().zip(results).any(|(segment, result)| {
175 *result = None;
176 segment.prefix().is_some() || !segment.pattern().is_double_wild()
177 });
178 } else {
179 return false;
180 }
181 };
182 macro_rules! try_intersect {
183 ($pattern: expr, $result: expr, $target: expr, $segments: expr, $results: expr) => {{
184 let target = $target;
185 let segments = $segments;
186 if $pattern.intersects(target)
187 && do_parse(
188 target.is_double_wild().then_some(target),
189 segments,
190 $results,
191 )
192 {
193 *$result = Some(target);
194 return true;
195 }
196 for (candidate, target) in target.iter_splits_rtl() {
197 if $pattern.intersects(candidate)
198 && do_parse(Some(target), segments, $results)
199 {
200 *result = Some(candidate);
201 return true;
202 }
203 }
204 if $pattern.is_double_wild() && do_parse(Some(target), segments, $results) {
205 *$result = None;
206 return true;
207 }
208 }};
209 }
210 if prefix.is_none() {
212 try_intersect!(pattern, result, target, segments, results);
213 }
214 for (candidate, target) in target.iter_splits_ltr().take(match prefix {
216 None => 1,
217 Some(prefix) => (prefix.bytes().filter(|&c| c == b'/').count() + 1) * 3,
218 }) {
219 if prefix.map_or(candidate.is_double_wild(), |prefix| {
220 prefix.intersects(candidate)
221 }) {
222 try_intersect!(pattern, result, target, segments, results);
223 }
224 }
225 pattern.is_double_wild()
226 && prefix.is_some_and(|prefix| prefix.intersects(target))
227 && do_parse(None, segments, results)
228 }
229 _ => unreachable!(),
230 }
231}
232
233#[test]
234fn parsing() {
235 use core::convert::TryFrom;
236
237 use crate::key_expr::OwnedKeyExpr;
238 for a_spec in ["${a:*}", "a/${a:*}"] {
239 for b_spec in ["b/${b:**}", "${b:**}"] {
240 let specs = [a_spec, b_spec, "c"];
241 for spec in [2, 3] {
242 let spec = specs[..spec].join("/");
243 let format: KeFormat<[Segment; 2]> = KeFormat::noalloc_new(&spec).unwrap();
244 let mut formatter = format.formatter();
245 for a_val in ["hi"] {
246 formatter.set("a", a_val).unwrap();
247 for b_val in ["hello", "hello/there", ""] {
248 formatter.set("b", b_val).unwrap();
249 let ke = OwnedKeyExpr::try_from(&formatter).unwrap();
250 let parsed = format.parse(&ke).unwrap();
251 assert_eq!(parsed.get("a").unwrap(), a_val);
252 assert_eq!(parsed.get("b").unwrap(), b_val);
253 }
254 }
255 }
256 }
257 }
258 KeFormat::new("**/${a:**}/${b:**}/**").unwrap_err();
259 let format = KeFormat::new("${a:**}/${b:**}").unwrap();
260 assert_eq!(
261 format
262 .parse(keyexpr::new("a/b/c").unwrap())
263 .unwrap()
264 .get("a")
265 .unwrap(),
266 "a/b/c"
267 );
268 assert_eq!(
269 format
270 .parse(keyexpr::new("**").unwrap())
271 .unwrap()
272 .get("a")
273 .unwrap(),
274 "**"
275 );
276 assert_eq!(
277 format
278 .parse(keyexpr::new("**").unwrap())
279 .unwrap()
280 .get("b")
281 .unwrap(),
282 "**"
283 );
284 let format = KeFormat::new("hi/${a:there}/${b:**}").unwrap();
285 assert_eq!(
286 format
287 .parse(keyexpr::new("hi/**").unwrap())
288 .unwrap()
289 .get("a")
290 .unwrap(),
291 "**"
292 );
293 assert_eq!(
294 format
295 .parse(keyexpr::new("hi/**").unwrap())
296 .unwrap()
297 .get("b")
298 .unwrap(),
299 "**"
300 );
301 let format = KeFormat::new("hi/${a:there}/@/${b:**}").unwrap();
302 assert_eq!(
303 format
304 .parse(keyexpr::new("hi/**/@").unwrap())
305 .unwrap()
306 .get("a")
307 .unwrap(),
308 "**"
309 );
310 assert_eq!(
311 format
312 .parse(keyexpr::new("hi/**/@").unwrap())
313 .unwrap()
314 .get("b")
315 .unwrap(),
316 ""
317 );
318}