1#![no_std]
11mod private {
12 pub trait Sealed {}
13
14 impl<V> Sealed for super::Chain<V> {}
15 impl<V, C: super::ChainElement> Sealed for super::Link<V, C> {}
16}
17
18pub trait ChainElement: private::Sealed {
20 type Inner;
21 type Parent;
22
23 #[inline]
25 fn append<T>(self, item: T) -> Link<T, Self>
26 where
27 Self: Sized,
28 {
29 Link {
30 object: item,
31 parent: self,
32 }
33 }
34
35 fn len(&self) -> usize;
37
38 fn get(&self) -> &Self::Inner;
39
40 fn get_mut(&mut self) -> &mut Self::Inner;
41
42 fn pop(self) -> (Self::Inner, Self::Parent);
43}
44
45#[derive(Clone, Copy)]
47pub struct Link<V, C>
48where
49 C: ChainElement,
50{
51 pub parent: C,
53
54 pub object: V,
56}
57
58impl<V, VC> ChainElement for Link<V, VC>
59where
60 VC: ChainElement,
61{
62 type Inner = V;
63 type Parent = VC;
64
65 #[inline]
66 fn len(&self) -> usize {
67 self.parent.len() + 1
68 }
69
70 fn get(&self) -> &Self::Inner {
71 &self.object
72 }
73
74 fn get_mut(&mut self) -> &mut Self::Inner {
75 &mut self.object
76 }
77
78 fn pop(self) -> (Self::Inner, Self::Parent) {
79 (self.object, self.parent)
80 }
81}
82
83#[derive(Clone, Copy)]
85pub struct Chain<V> {
86 pub object: V,
88}
89
90impl<V> Chain<V> {
91 pub const fn new(object: V) -> Self {
93 Self { object }
94 }
95}
96
97impl<V> ChainElement for Chain<V> {
98 type Inner = V;
99 type Parent = ();
100
101 #[inline]
102 fn len(&self) -> usize {
103 1
104 }
105
106 fn get(&self) -> &Self::Inner {
107 &self.object
108 }
109
110 fn get_mut(&mut self) -> &mut Self::Inner {
111 &mut self.object
112 }
113
114 fn pop(self) -> (Self::Inner, Self::Parent) {
115 (self.object, ())
116 }
117}
118
119#[doc(hidden)]
121#[macro_export(local_inner_macros)]
122macro_rules! chain_impl {
123 ($x:ty) => {
124 Chain<$x>
125 };
126 ($x:ty,) => {
127 Chain<$x>
128 };
129 ($x:ty, $($rest:tt)+) => {
130 Link<$x, chain_impl! { $($rest)+ }>
131 };
132}
133
134#[doc(hidden)]
136#[macro_export(local_inner_macros)]
137macro_rules! reverse {
138 ([] $($reversed:tt)+) => {
139 chain_impl! { $($reversed)+ }
140 };
141 ([$first:ty] $($reversed:tt)*) => {
142 reverse! { [ ] $first, $($reversed)* }
143 };
144 ([$first:ty, $($rest:ty),*] $($reversed:tt)*) => {
145 reverse! { [ $($rest),* ] $first, $($reversed)* }
146 };
147}
148
149#[macro_export(local_inner_macros)]
179macro_rules! chain {
180 [$($types:ty),+] => {
181 reverse!{ [ $($types),+ ] }
182 };
183}
184
185#[cfg(test)]
186#[allow(dead_code)]
187mod test {
188 use super::*;
189 use core::marker::PhantomData;
190
191 struct CompileTest {
192 chain1: chain![u8],
193 generic_in_chain: chain![Generic<'static, u32>],
194 chain: chain![u8, u16, u32],
195 }
196
197 struct Generic<'a, T> {
198 field: PhantomData<&'a T>,
199 }
200
201 #[test]
202 pub fn test() {
203 fn f(_obj_chain: &chain![u8, u16, u32]) {}
204
205 let test = CompileTest {
206 chain1: Chain::new(0),
207 generic_in_chain: Chain::new(Generic { field: PhantomData }),
208 chain: Chain::new(0u8).append(1u16).append(2u32),
209 };
210
211 f(&test.chain);
212
213 let chain = test.chain;
214 let (obj, chain) = chain.pop();
215 assert_eq!(obj, 2u32);
216
217 let (obj, chain) = chain.pop();
218 assert_eq!(obj, 1u16);
219
220 let (obj, chain) = chain.pop();
221 assert_eq!(obj, 0u8);
222 assert_eq!(chain, ());
223 }
224
225 #[test]
226 pub fn test_count() {
227 assert_eq!(1, Chain::new(0).len());
228 assert_eq!(3, Chain::new(0u8).append(1u16).append(2u32).len());
229 }
230
231 #[test]
232 pub fn test_accessing_elements_with_common_interface() {
233 trait AsU8 {
235 fn as_u8(&self) -> u8;
236 }
237
238 impl AsU8 for u8 {
239 fn as_u8(&self) -> u8 {
240 *self
241 }
242 }
243
244 impl AsU8 for u16 {
245 fn as_u8(&self) -> u8 {
246 *self as u8
247 }
248 }
249
250 trait ReadableAsU8 {
252 fn read_from(&self, index: usize) -> &dyn AsU8;
253 }
254
255 impl<T: AsU8> ReadableAsU8 for Chain<T> {
256 fn read_from(&self, index: usize) -> &dyn AsU8 {
257 assert!(index == 0, "Out of bounds access!");
258 &self.object
259 }
260 }
261
262 impl<T: AsU8, CE: ChainElement<Inner = impl AsU8> + ReadableAsU8> ReadableAsU8 for Link<T, CE> {
263 fn read_from(&self, index: usize) -> &dyn AsU8 {
264 if index == self.len() - 1 {
265 &self.object
266 } else {
267 self.parent.read_from(index - 1)
268 }
269 }
270 }
271
272 fn do_test(obj_chain: &impl ReadableAsU8) {
275 assert_eq!(2, obj_chain.read_from(1).as_u8());
276 }
277
278 do_test(&Chain::new(1u8).append(2u16));
279 }
280}