use core::fmt::Write;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use crate::{DescendError, Internal, IntoKeys, Key, Schema, Track, Transcode};
macro_rules! impl_key_integer {
($($t:ty)+) => {$(
impl Key for $t {
fn find(&self, internal: &Internal) -> Option<usize> {
(*self).try_into().ok().filter(|i| *i < internal.len().get())
}
}
)+};
}
impl_key_integer!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
pub struct Indices<T: ?Sized> {
len: usize,
data: T,
}
impl<T> Indices<T> {
pub fn new(data: T, len: usize) -> Self {
Self { len, data }
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn into_inner(self) -> (T, usize) {
(self.data, self.len)
}
}
impl<T> From<T> for Indices<T> {
fn from(value: T) -> Self {
Self {
len: 0,
data: value,
}
}
}
impl<U, T: AsRef<[U]> + ?Sized> AsRef<[U]> for Indices<T> {
fn as_ref(&self) -> &[U] {
&self.data.as_ref()[..self.len]
}
}
impl<'a, U, T: ?Sized> IntoIterator for &'a Indices<T>
where
&'a T: IntoIterator<Item = U>,
{
type Item = U;
type IntoIter = core::iter::Take<<&'a T as IntoIterator>::IntoIter>;
fn into_iter(self) -> Self::IntoIter {
(&self.data).into_iter().take(self.len)
}
}
impl<T: AsMut<[usize]> + ?Sized> Transcode for Indices<T> {
type Error = <[usize] as Transcode>::Error;
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
let mut slic = Track::new(self.data.as_mut());
let ret = slic.transcode(schema, keys);
self.len = slic.depth();
ret
}
}
macro_rules! impl_transcode_slice {
($($t:ty)+) => {$(
impl Transcode for [$t] {
type Error = ();
fn transcode(&mut self, schema: &Schema, keys: impl IntoKeys) -> Result<(), DescendError<Self::Error>> {
let mut it = self.iter_mut();
schema.descend(keys.into_keys(), |_meta, idx_schema| {
if let Some((index, internal)) = idx_schema {
debug_assert!(internal.len().get() <= <$t>::MAX as _);
let i = index.try_into().or(Err(()))?;
let idx = it.next().ok_or(())?;
*idx = i;
}
Ok(())
})
}
}
)+};
}
impl_transcode_slice!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128);
#[cfg(feature = "alloc")]
impl<T> Transcode for Vec<T>
where
usize: TryInto<T>,
{
type Error = <usize as TryInto<T>>::Error;
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
schema.descend(keys.into_keys(), |_meta, idx_schema| {
if let Some((index, _schema)) = idx_schema {
self.push(index.try_into()?);
}
Ok(())
})
}
}
#[cfg(feature = "heapless")]
impl<T, const N: usize> Transcode for heapless::Vec<T, N>
where
usize: TryInto<T>,
{
type Error = ();
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
schema.descend(keys.into_keys(), |_meta, idx_schema| {
if let Some((index, _schema)) = idx_schema {
let i = index.try_into().or(Err(()))?;
self.push(i).or(Err(()))?;
}
Ok(())
})
}
}
#[cfg(feature = "heapless-09")]
impl<T, const N: usize> Transcode for heapless_09::Vec<T, N>
where
usize: TryInto<T>,
{
type Error = ();
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
schema.descend(keys.into_keys(), |_meta, idx_schema| {
if let Some((index, _schema)) = idx_schema {
let i = index.try_into().or(Err(()))?;
self.push(i).or(Err(()))?;
}
Ok(())
})
}
}
impl Key for str {
fn find(&self, internal: &Internal) -> Option<usize> {
internal.get_index(self)
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(transparent)]
#[serde(transparent)]
pub struct Path<T: ?Sized, const S: char>(pub T);
impl<T: ?Sized, const S: char> Path<T, S> {
pub const fn separator(&self) -> char {
S
}
}
impl<T, const S: char> Path<T, S> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: AsRef<str> + ?Sized, const S: char> AsRef<str> for Path<T, S> {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl<T: core::fmt::Display, const S: char> core::fmt::Display for Path<T, S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct PathIter<'a> {
data: Option<&'a str>,
sep: char,
}
impl<'a> PathIter<'a> {
pub fn new(data: Option<&'a str>, sep: char) -> Self {
Self { data, sep }
}
pub fn root(data: &'a str, sep: char) -> Self {
let mut s = Self::new(Some(data), sep);
s.next();
s
}
}
impl<'a> Iterator for PathIter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
self.data.map(|s| {
let pos = s
.chars()
.map_while(|c| (c != self.sep).then_some(c.len_utf8()))
.sum();
let (left, right) = s.split_at(pos);
self.data = right.get(self.sep.len_utf8()..);
left
})
}
}
impl core::iter::FusedIterator for PathIter<'_> {}
impl<'a, T: AsRef<str> + ?Sized, const S: char> IntoKeys for Path<&'a T, S> {
type IntoKeys = <PathIter<'a> as IntoKeys>::IntoKeys;
fn into_keys(self) -> Self::IntoKeys {
PathIter::root(self.0.as_ref(), S).into_keys()
}
}
impl<'a, T: AsRef<str> + ?Sized, const S: char> IntoKeys for &'a Path<T, S> {
type IntoKeys = <Path<&'a str, S> as IntoKeys>::IntoKeys;
fn into_keys(self) -> Self::IntoKeys {
PathIter::root(self.0.as_ref(), S).into_keys()
}
}
impl<T: Write + ?Sized, const S: char> Transcode for Path<T, S> {
type Error = core::fmt::Error;
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
schema.descend(keys.into_keys(), |_meta, idx_schema| {
if let Some((index, internal)) = idx_schema {
self.0.write_char(S)?;
let mut buf = itoa::Buffer::new();
let name = internal
.get_name(index)
.unwrap_or_else(|| buf.format(index));
debug_assert!(!name.contains(S));
self.0.write_str(name)
} else {
Ok(())
}
})
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn strsplit() {
use heapless_09::Vec;
for p in ["/d/1", "/a/bccc//d/e/", "", "/", "a/b", "a"] {
let a: Vec<_, 10> = PathIter::root(p, '/').collect();
let b: Vec<_, 10> = p.split('/').skip(1).collect();
assert_eq!(a, b);
}
}
}