1use core::fmt::Write;
2
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5
6use serde::{Deserialize, Serialize};
7
8use crate::{DescendError, Internal, IntoKeys, Key, Schema, Seeded, Track, Transcode};
9
10macro_rules! impl_key_integer {
12 ($($t:ty)+) => {$(
13 impl Key for $t {
14 fn find(&self, internal: &Internal) -> Option<usize> {
15 (*self).try_into().ok().filter(|i| *i < internal.len().get())
16 }
17 }
18 )+};
19}
20impl_key_integer!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128);
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
24pub struct Indices<T: ?Sized> {
25 len: usize,
26 data: T,
27}
28
29impl<T> Indices<T> {
30 pub fn new(data: T, len: usize) -> Self {
32 Self { len, data }
33 }
34
35 pub fn len(&self) -> usize {
37 self.len
38 }
39
40 pub fn is_empty(&self) -> bool {
42 self.len == 0
43 }
44
45 pub fn into_inner(self) -> (T, usize) {
47 (self.data, self.len)
48 }
49}
50
51impl<T> From<T> for Indices<T> {
52 fn from(value: T) -> Self {
53 Self {
54 len: 0,
55 data: value,
56 }
57 }
58}
59
60impl<U, T: AsRef<[U]> + ?Sized> AsRef<[U]> for Indices<T> {
61 fn as_ref(&self) -> &[U] {
62 &self.data.as_ref()[..self.len]
63 }
64}
65
66impl<'a, U, T: ?Sized> IntoIterator for &'a Indices<T>
67where
68 &'a T: IntoIterator<Item = U>,
69{
70 type Item = U;
71
72 type IntoIter = core::iter::Take<<&'a T as IntoIterator>::IntoIter>;
73
74 fn into_iter(self) -> Self::IntoIter {
75 (&self.data).into_iter().take(self.len)
76 }
77}
78
79impl<T: AsMut<[usize]> + ?Sized> Transcode for Indices<T> {
80 type Error = <[usize] as Transcode>::Error;
81
82 fn transcode(
83 &mut self,
84 schema: &Schema,
85 keys: impl IntoKeys,
86 ) -> Result<(), DescendError<Self::Error>> {
87 let mut slic = Track::new(self.data.as_mut());
88 let ret = slic.transcode(schema, keys);
89 self.len = slic.depth();
90 ret
91 }
92}
93
94impl<T: Default> Seeded for Indices<T> {
95 type Seed = ();
96 const DEFAULT_SEED: Self::Seed = ();
97
98 fn from_seed(_: &Self::Seed) -> Self {
99 Self::from(T::default())
100 }
101}
102
103macro_rules! impl_transcode_slice {
104 ($($t:ty)+) => {$(
105 impl Transcode for [$t] {
106 type Error = ();
107
108 fn transcode(&mut self, schema: &Schema, keys: impl IntoKeys) -> Result<(), DescendError<Self::Error>> {
109 let mut it = self.iter_mut();
110 schema.descend(keys.into_keys(), |_meta, idx_schema| {
111 if let Some((index, internal)) = idx_schema {
112 debug_assert!(internal.len().get() <= <$t>::MAX as _);
113 let i = index.try_into().or(Err(()))?;
114 let idx = it.next().ok_or(())?;
115 *idx = i;
116 }
117 Ok(())
118 })
119 }
120 }
121 )+};
122}
123impl_transcode_slice!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128);
124
125#[cfg(feature = "alloc")]
126impl<T> Transcode for Vec<T>
127where
128 usize: TryInto<T>,
129{
130 type Error = <usize as TryInto<T>>::Error;
131
132 fn transcode(
133 &mut self,
134 schema: &Schema,
135 keys: impl IntoKeys,
136 ) -> Result<(), DescendError<Self::Error>> {
137 schema.descend(keys.into_keys(), |_meta, idx_schema| {
138 if let Some((index, _schema)) = idx_schema {
139 self.push(index.try_into()?);
140 }
141 Ok(())
142 })
143 }
144}
145
146#[cfg(feature = "alloc")]
147impl<T> Seeded for Vec<T> {
148 type Seed = ();
149 const DEFAULT_SEED: Self::Seed = ();
150
151 fn from_seed(_: &Self::Seed) -> Self {
152 Self::default()
153 }
154}
155
156#[cfg(feature = "heapless")]
157impl<T, const N: usize> Transcode for heapless::Vec<T, N>
158where
159 usize: TryInto<T>,
160{
161 type Error = ();
162
163 fn transcode(
164 &mut self,
165 schema: &Schema,
166 keys: impl IntoKeys,
167 ) -> Result<(), DescendError<Self::Error>> {
168 schema.descend(keys.into_keys(), |_meta, idx_schema| {
169 if let Some((index, _schema)) = idx_schema {
170 let i = index.try_into().or(Err(()))?;
171 self.push(i).or(Err(()))?;
172 }
173 Ok(())
174 })
175 }
176}
177
178#[cfg(feature = "heapless")]
179impl<T, const N: usize> Seeded for heapless::Vec<T, N> {
180 type Seed = ();
181 const DEFAULT_SEED: Self::Seed = ();
182
183 fn from_seed(_: &Self::Seed) -> Self {
184 Self::default()
185 }
186}
187
188#[cfg(feature = "heapless-09")]
189impl<T, const N: usize> Transcode for heapless_09::Vec<T, N>
190where
191 usize: TryInto<T>,
192{
193 type Error = ();
194
195 fn transcode(
196 &mut self,
197 schema: &Schema,
198 keys: impl IntoKeys,
199 ) -> Result<(), DescendError<Self::Error>> {
200 schema.descend(keys.into_keys(), |_meta, idx_schema| {
201 if let Some((index, _schema)) = idx_schema {
202 let i = index.try_into().or(Err(()))?;
203 self.push(i).or(Err(()))?;
204 }
205 Ok(())
206 })
207 }
208}
209
210#[cfg(feature = "heapless-09")]
211impl<T, const N: usize> Seeded for heapless_09::Vec<T, N> {
212 type Seed = ();
213 const DEFAULT_SEED: Self::Seed = ();
214
215 fn from_seed(_: &Self::Seed) -> Self {
216 Self::default()
217 }
218}
219
220impl Key for str {
224 fn find(&self, internal: &Internal) -> Option<usize> {
225 internal.get_index(self)
226 }
227}
228
229#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
239pub struct Path<T> {
240 pub path: T,
242 pub separator: char,
244}
245
246impl<T> Default for Path<T>
247where
248 T: Default,
249{
250 fn default() -> Self {
251 Self {
252 path: T::default(),
253 separator: '/',
254 }
255 }
256}
257
258impl<T> Path<T> {
259 pub const fn new(path: T, separator: char) -> Self {
261 Self { path, separator }
262 }
263
264 pub const fn separator(&self) -> char {
266 self.separator
267 }
268
269 pub fn into_inner(self) -> T {
271 self.path
272 }
273}
274
275impl<T: AsRef<str>> AsRef<str> for Path<T> {
276 fn as_ref(&self) -> &str {
277 self.path.as_ref()
278 }
279}
280
281impl<T: core::fmt::Display> core::fmt::Display for Path<T> {
282 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
283 self.path.fmt(f)
284 }
285}
286
287impl<T: Default> Seeded for Path<T> {
288 type Seed = char;
289 const DEFAULT_SEED: Self::Seed = '/';
290
291 fn from_seed(seed: &Self::Seed) -> Self {
292 Self::new(T::default(), *seed)
293 }
294}
295
296#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
298#[repr(transparent)]
299#[serde(transparent)]
300pub struct ConstPath<T, const S: char>(pub T);
301
302impl<T, const S: char> ConstPath<T, S> {
303 pub const fn separator(&self) -> char {
305 S
306 }
307
308 pub fn into_inner(self) -> T {
310 self.0
311 }
312}
313
314impl<T: AsRef<str>, const S: char> AsRef<str> for ConstPath<T, S> {
315 fn as_ref(&self) -> &str {
316 self.0.as_ref()
317 }
318}
319
320impl<T: core::fmt::Display, const S: char> core::fmt::Display for ConstPath<T, S> {
321 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322 self.0.fmt(f)
323 }
324}
325
326impl<T: Default, const S: char> Seeded for ConstPath<T, S> {
327 type Seed = ();
328 const DEFAULT_SEED: Self::Seed = ();
329
330 fn from_seed(_: &Self::Seed) -> Self {
331 Self::default()
332 }
333}
334
335fn split_path(path: &str, separator: char) -> (&str, Option<&str>) {
336 let pos = path
337 .chars()
338 .map_while(|c| (c != separator).then_some(c.len_utf8()))
339 .sum();
340 let (left, right) = path.split_at(pos);
341 (left, right.get(separator.len_utf8()..))
342}
343
344#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
346pub struct PathIter<'a> {
347 path: Option<&'a str>,
348 separator: char,
349}
350
351impl<'a> PathIter<'a> {
352 pub fn new(path: Option<&'a str>, separator: char) -> Self {
354 Self { path, separator }
355 }
356
357 pub fn root(path: &'a str, separator: char) -> Self {
361 let mut s = Self::new(Some(path), separator);
362 s.next();
371 s
372 }
373}
374
375impl<'a> Iterator for PathIter<'a> {
376 type Item = &'a str;
377
378 fn next(&mut self) -> Option<Self::Item> {
379 let (left, right) = split_path(self.path?, self.separator);
380 self.path = right;
381 Some(left)
382 }
383}
384
385impl core::iter::FusedIterator for PathIter<'_> {}
386
387#[repr(transparent)]
389#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
390#[serde(transparent)]
391pub struct ConstPathIter<'a, const S: char>(Option<&'a str>);
392
393impl<'a, const S: char> ConstPathIter<'a, S> {
394 pub fn new(path: Option<&'a str>) -> Self {
396 Self(path)
397 }
398
399 pub fn root(path: &'a str) -> Self {
401 let mut s = Self::new(Some(path));
402 s.next();
403 s
404 }
405}
406
407impl<'a, const S: char> Iterator for ConstPathIter<'a, S> {
408 type Item = &'a str;
409
410 fn next(&mut self) -> Option<Self::Item> {
411 let s = self.0?;
412 if S.is_ascii() {
413 if let Some(i) = s.as_bytes().iter().position(|b| *b == S as u8) {
414 self.0 = s.get(i + 1..);
415 s.get(..i)
416 } else {
417 self.0 = None;
418 Some(s)
419 }
420 } else {
421 let (left, right) = split_path(s, S);
422 self.0 = right;
423 Some(left)
424 }
425 }
426}
427
428impl<const S: char> core::iter::FusedIterator for ConstPathIter<'_, S> {}
429
430impl<'a, T: AsRef<str> + ?Sized> IntoKeys for Path<&'a T> {
431 type IntoKeys = <PathIter<'a> as IntoKeys>::IntoKeys;
432
433 fn into_keys(self) -> Self::IntoKeys {
434 PathIter::root(self.path.as_ref(), self.separator).into_keys()
435 }
436}
437
438impl<'a, T: AsRef<str>> IntoKeys for &'a Path<T> {
439 type IntoKeys = <Path<&'a str> as IntoKeys>::IntoKeys;
440
441 fn into_keys(self) -> Self::IntoKeys {
442 PathIter::root(self.path.as_ref(), self.separator).into_keys()
443 }
444}
445
446impl<'a, T: AsRef<str> + ?Sized, const S: char> IntoKeys for ConstPath<&'a T, S> {
447 type IntoKeys = <ConstPathIter<'a, S> as IntoKeys>::IntoKeys;
448
449 fn into_keys(self) -> Self::IntoKeys {
450 ConstPathIter::root(self.0.as_ref()).into_keys()
451 }
452}
453
454impl<'a, T: AsRef<str>, const S: char> IntoKeys for &'a ConstPath<T, S> {
455 type IntoKeys = <ConstPath<&'a str, S> as IntoKeys>::IntoKeys;
456
457 fn into_keys(self) -> Self::IntoKeys {
458 ConstPathIter::root(self.0.as_ref()).into_keys()
459 }
460}
461
462impl<T: Write> Transcode for Path<T> {
463 type Error = core::fmt::Error;
464
465 fn transcode(
466 &mut self,
467 schema: &Schema,
468 keys: impl IntoKeys,
469 ) -> Result<(), DescendError<Self::Error>> {
470 schema.descend(keys.into_keys(), |_meta, idx_schema| {
471 if let Some((index, internal)) = idx_schema {
472 self.path.write_char(self.separator)?;
473 let mut buf = itoa::Buffer::new();
474 let name = internal
475 .get_name(index)
476 .unwrap_or_else(|| buf.format(index));
477 debug_assert!(!name.contains(self.separator));
478 self.path.write_str(name)
479 } else {
480 Ok(())
481 }
482 })
483 }
484}
485
486impl<T: Write, const S: char> Transcode for ConstPath<T, S> {
487 type Error = core::fmt::Error;
488
489 fn transcode(
490 &mut self,
491 schema: &Schema,
492 keys: impl IntoKeys,
493 ) -> Result<(), DescendError<Self::Error>> {
494 schema.descend(keys.into_keys(), |_meta, idx_schema| {
495 if let Some((index, internal)) = idx_schema {
496 self.0.write_char(S)?;
497 let mut buf = itoa::Buffer::new();
498 let name = internal
499 .get_name(index)
500 .unwrap_or_else(|| buf.format(index));
501 debug_assert!(!name.contains(S));
502 self.0.write_str(name)
503 } else {
504 Ok(())
505 }
506 })
507 }
508}
509
510#[cfg(test)]
511mod test {
512 use super::*;
513
514 #[test]
515 fn strsplit() {
516 use heapless_09::Vec;
517 for p in ["/d/1", "/a/bccc//d/e/", "", "/", "a/b", "a"] {
518 let a: Vec<_, 10> = PathIter::root(p, '/').collect();
519 let b: Vec<_, 10> = p.split('/').skip(1).collect();
520 assert_eq!(a, b);
521 }
522 }
523
524 #[test]
525 fn ascii_strsplit() {
526 use heapless_09::Vec;
527 for p in ["/d/1", "/a/bccc//d/e/", "", "/", "a/b", "a"] {
528 let a: Vec<_, 10> = ConstPathIter::<'/'>::root(p).collect();
529 let b: Vec<_, 10> = p.split('/').skip(1).collect();
530 assert_eq!(a, b);
531 }
532 }
533}