#![no_std]
mod private {
pub trait Sealed {}
impl<V> Sealed for super::Chain<V> {}
impl<V, C: super::ChainElement> Sealed for super::Link<V, C> {}
}
pub trait ChainElement: private::Sealed {
type Inner;
type Parent;
#[inline]
fn append<T>(self, item: T) -> Link<T, Self>
where
Self: Sized,
{
Link {
object: item,
parent: self,
}
}
fn len(&self) -> usize;
fn get(&self) -> &Self::Inner;
fn get_mut(&mut self) -> &mut Self::Inner;
fn pop(self) -> (Self::Inner, Self::Parent);
}
#[derive(Clone, Copy)]
pub struct Link<V, C>
where
C: ChainElement,
{
pub parent: C,
pub object: V,
}
impl<V, VC> ChainElement for Link<V, VC>
where
VC: ChainElement,
{
type Inner = V;
type Parent = VC;
#[inline]
fn len(&self) -> usize {
self.parent.len() + 1
}
fn get(&self) -> &Self::Inner {
&self.object
}
fn get_mut(&mut self) -> &mut Self::Inner {
&mut self.object
}
fn pop(self) -> (Self::Inner, Self::Parent) {
(self.object, self.parent)
}
}
#[derive(Clone, Copy)]
pub struct Chain<V> {
pub object: V,
}
impl<V> Chain<V> {
pub const fn new(object: V) -> Self {
Self { object }
}
}
impl<V> ChainElement for Chain<V> {
type Inner = V;
type Parent = ();
#[inline]
fn len(&self) -> usize {
1
}
fn get(&self) -> &Self::Inner {
&self.object
}
fn get_mut(&mut self) -> &mut Self::Inner {
&mut self.object
}
fn pop(self) -> (Self::Inner, Self::Parent) {
(self.object, ())
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! chain_impl {
($x:ty) => {
Chain<$x>
};
($x:ty,) => {
Chain<$x>
};
($x:ty, $($rest:tt)+) => {
Link<$x, chain_impl! { $($rest)+ }>
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! reverse {
([] $($reversed:tt)+) => {
chain_impl! { $($reversed)+ }
};
([$first:ty] $($reversed:tt)*) => {
reverse! { [ ] $first, $($reversed)* }
};
([$first:ty, $($rest:ty),*] $($reversed:tt)*) => {
reverse! { [ $($rest),* ] $first, $($reversed)* }
};
}
#[macro_export(local_inner_macros)]
macro_rules! chain {
[$($types:ty),+] => {
reverse!{ [ $($types),+ ] }
};
}
#[cfg(test)]
#[allow(dead_code)]
mod test {
use super::*;
use core::marker::PhantomData;
struct CompileTest {
chain1: chain![u8],
generic_in_chain: chain![Generic<'static, u32>],
chain: chain![u8, u16, u32],
}
struct Generic<'a, T> {
field: PhantomData<&'a T>,
}
#[test]
pub fn test() {
fn f(_obj_chain: &chain![u8, u16, u32]) {}
let test = CompileTest {
chain1: Chain::new(0),
generic_in_chain: Chain::new(Generic { field: PhantomData }),
chain: Chain::new(0u8).append(1u16).append(2u32),
};
f(&test.chain);
let chain = test.chain;
let (obj, chain) = chain.pop();
assert_eq!(obj, 2u32);
let (obj, chain) = chain.pop();
assert_eq!(obj, 1u16);
let (obj, chain) = chain.pop();
assert_eq!(obj, 0u8);
assert_eq!(chain, ());
}
#[test]
pub fn test_count() {
assert_eq!(1, Chain::new(0).len());
assert_eq!(3, Chain::new(0u8).append(1u16).append(2u32).len());
}
#[test]
pub fn test_accessing_elements_with_common_interface() {
trait AsU8 {
fn as_u8(&self) -> u8;
}
impl AsU8 for u8 {
fn as_u8(&self) -> u8 {
*self
}
}
impl AsU8 for u16 {
fn as_u8(&self) -> u8 {
*self as u8
}
}
trait ReadableAsU8 {
fn read_from(&self, index: usize) -> &dyn AsU8;
}
impl<T: AsU8> ReadableAsU8 for Chain<T> {
fn read_from(&self, index: usize) -> &dyn AsU8 {
assert!(index == 0, "Out of bounds access!");
&self.object
}
}
impl<T: AsU8, CE: ChainElement<Inner = impl AsU8> + ReadableAsU8> ReadableAsU8 for Link<T, CE> {
fn read_from(&self, index: usize) -> &dyn AsU8 {
if index == self.len() - 1 {
&self.object
} else {
self.parent.read_from(index - 1)
}
}
}
fn do_test(obj_chain: &impl ReadableAsU8) {
assert_eq!(2, obj_chain.read_from(1).as_u8());
}
do_test(&Chain::new(1u8).append(2u16));
}
}