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: Sized + private::Sealed {
fn len(&self) -> usize;
}
pub struct Link<V, C: ChainElement> {
pub object: V,
pub parent: C,
}
impl<V, C: ChainElement> Link<V, C> {
#[inline]
pub fn append<T>(self, item: T) -> Link<T, Self> {
Link {
object: item,
parent: self,
}
}
}
impl<V, C> Clone for Link<V, C>
where
V: Clone,
C: ChainElement + Clone,
{
fn clone(&self) -> Self {
Self {
object: self.object.clone(),
parent: self.parent.clone(),
}
}
}
impl<V, VC> ChainElement for Link<V, VC>
where
VC: ChainElement,
{
#[inline]
fn len(&self) -> usize {
self.parent.len() + 1
}
}
pub struct Chain<V> {
pub object: V,
}
impl<V> Chain<V> {
#[inline]
pub fn append<T>(self, item: T) -> Link<T, Self> {
Link {
object: item,
parent: self,
}
}
}
impl<V> Chain<V> {
#[inline]
pub const fn new(object: V) -> Self {
Self { object }
}
}
impl<V> Clone for Chain<V>
where
V: Clone,
{
fn clone(&self) -> Self {
Self {
object: self.object.clone(),
}
}
}
impl<V> ChainElement for Chain<V> {
#[inline]
fn len(&self) -> usize {
1
}
}
#[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)]
mod test {
#![allow(dead_code)]
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);
}
#[test]
pub fn test_count() {
assert_eq!(1, Chain::new(0).len());
assert_eq!(3, Chain::new(0u8).append(1u16).append(2u32).len());
}
}
#[cfg(test)]
#[allow(dead_code)]
mod test_macro {
use crate::prelude::*;
use embedded_graphics::primitives::{Rectangle, Triangle};
type Views = chain! {
Rectangle,
Rectangle,
Triangle
};
}