Skip to main content

cel_runtime/
tuple_list.rs

1//! Implements [`List`] for tuples where `()` is an empty list and `(H, T)` is a list with a head
2//! and tail.
3
4use typenum::{B1, Bit, Sub1, U0, UInt, Unsigned};
5
6use crate::list_traits::{
7    EmptyList, IntoList, List, ListIndex, ListTypeIterator, ListTypeIteratorAdvance,
8    ListTypeProperty,
9};
10use std::ops::{RangeFrom, Sub};
11
12/// Converts tuples into a `List` representation where `()` is empty and `(H, T)` is a cons cell.
13pub trait IntoTupleList {
14    /// The resulting list type.
15    type Output: List;
16    /// Convert into a `List` where `(H, T)` models a cons cell.
17    fn into_tuple_list(self) -> Self::Output;
18}
19
20impl<T: IntoList> IntoTupleList for T {
21    type Output = T::Output<()>;
22    fn into_tuple_list(self) -> Self::Output {
23        self.into_list()
24    }
25}
26
27//--------------------------------------------------------------------------------------------------
28// ListTypeIteratorAdvance
29
30impl<P: ListTypeProperty> ListTypeIteratorAdvance<P> for () {
31    fn advancer<R: List>(_iter: &mut ListTypeIterator<R, P>) -> Option<P::Output> {
32        None
33    }
34}
35
36impl<P: ListTypeProperty, H: 'static, T: ListTypeIteratorAdvance<P>> ListTypeIteratorAdvance<P>
37    for (H, T)
38{
39    fn advancer<R: List>(iter: &mut ListTypeIterator<R, P>) -> Option<P::Output> {
40        iter.advance = T::advancer::<R>;
41        Some(P::property::<(H, T)>())
42    }
43}
44
45//--------------------------------------------------------------------------------------------------
46// EmptyList for ()
47
48impl EmptyList for () {
49    type PushFirst<U: 'static> = (U, ());
50    fn push_first<U: 'static>(self, item: U) -> Self::PushFirst<U> {
51        (item, ())
52    }
53
54    type RootEmpty = Self;
55    fn root_empty() -> Self::RootEmpty {}
56}
57
58//--------------------------------------------------------------------------------------------------
59// List for (H, T)
60
61impl<H: 'static, T: List> List for (H, T) {
62    type Empty = ();
63    fn empty() -> Self::Empty {}
64
65    type Head = H;
66    fn head(&self) -> &Self::Head {
67        &self.0
68    }
69
70    type Tail = T;
71    fn tail(&self) -> &Self::Tail {
72        &self.1
73    }
74
75    type Push<U: 'static> = (U, Self);
76    fn push<U: 'static>(self, item: U) -> Self::Push<U> {
77        (item, self)
78    }
79
80    type Append<U: List> = <T::Append<U> as List>::Push<H>;
81    fn append<U: List>(self, other: U) -> Self::Append<U> {
82        self.1.append(other).push(self.0)
83    }
84
85    type ReverseOnto<U: List> = T::ReverseOnto<U::Push<H>>;
86    fn reverse_onto<U: List>(self, other: U) -> Self::ReverseOnto<U> {
87        self.1.reverse_onto(other.push(self.0))
88    }
89}
90
91impl ListIndex<RangeFrom<U0>> for () {
92    type Output = ();
93    fn index(&self, _index: RangeFrom<U0>) -> &Self::Output {
94        self
95    }
96}
97
98impl<H: 'static, T: List> ListIndex<RangeFrom<U0>> for (H, T) {
99    type Output = (H, T);
100    fn index(&self, _index: RangeFrom<U0>) -> &Self::Output {
101        self
102    }
103}
104
105impl<H: 'static, T: List, U: Unsigned, B: Bit> ListIndex<RangeFrom<UInt<U, B>>> for (H, T)
106where
107    T: ListIndex<RangeFrom<Sub1<UInt<U, B>>>>,
108    UInt<U, B>: Sub<B1>,
109{
110    type Output = <T as ListIndex<RangeFrom<Sub1<UInt<U, B>>>>>::Output;
111    fn index(&self, index: RangeFrom<UInt<U, B>>) -> &Self::Output {
112        self.tail().index((index.start - B1)..)
113    }
114}
115
116impl<H: 'static, T: List> ListIndex<U0> for (H, T) {
117    type Output = H;
118    fn index(&self, _index: U0) -> &Self::Output {
119        self.head()
120    }
121}
122
123impl<H: 'static, T: List, U: Unsigned, B: Bit> ListIndex<UInt<U, B>> for (H, T)
124where
125    T: ListIndex<Sub1<UInt<U, B>>>,
126    UInt<U, B>: Sub<B1>,
127{
128    type Output = <T as ListIndex<Sub1<UInt<U, B>>>>::Output;
129    fn index(&self, index: UInt<U, B>) -> &Self::Output {
130        self.tail().index(index - B1)
131    }
132}
133
134//--------------------------------------------------------------------------------------------------
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use crate::list_traits::TypeIdIterator;
140    use std::any::TypeId;
141    use typenum::{U0, U1, U2, U3};
142
143    #[test]
144    fn type_id_iterator() {
145        let ids: [TypeId; 3] = [
146            TypeId::of::<u32>(),
147            TypeId::of::<f64>(),
148            TypeId::of::<&str>(),
149        ];
150        assert!(TypeIdIterator::<(u32, (f64, (&str, ())))>::new().eq(ids.iter().copied()));
151    }
152
153    #[test]
154    fn empty_list() {
155        let () = <()>::empty();
156    }
157
158    #[test]
159    fn into_list() {
160        let () = ().into_tuple_list();
161        assert_eq!((1, 2, 3).into_tuple_list(), (1, (2, (3, ()))));
162        assert_eq!(
163            (1, 2.5, "Hello").into_tuple_list(),
164            (1, (2.5, ("Hello", ())))
165        );
166    }
167
168    #[test]
169    fn push() {
170        assert_eq!(().push_first(1), (1, ()));
171        assert_eq!((1, 2, 3).into_tuple_list().push(4), (4, (1, (2, (3, ())))));
172    }
173
174    #[test]
175    fn append() {
176        assert_eq!(
177            (1, 2, 3)
178                .into_tuple_list()
179                .append((4, 5, 6).into_tuple_list()),
180            (1, (2, (3, (4, (5, (6, ()))))))
181        );
182    }
183
184    #[test]
185    fn reverse() {
186        assert_eq!((1, 2, 3).into_tuple_list().reverse(), (3, (2, (1, ()))));
187    }
188
189    #[test]
190    fn list_length() {
191        assert_eq!(<()>::LENGTH, 0);
192        assert_eq!(<(i32, ())>::LENGTH, 1);
193        assert_eq!(<(i32, (f64, ()))>::LENGTH, 2);
194    }
195
196    #[test]
197    fn tuple_list() {
198        let list = (1, 2.5, "Hello").into_tuple_list();
199        println!("{:?}", list);
200    }
201
202    #[test]
203    fn list_index() {
204        let list = (1, 2.5, "Hello").into_tuple_list();
205        assert_eq!(*list.index(U0::new()), 1);
206        assert_eq!(*list.index(U1::new()), 2.5);
207        assert_eq!(*list.index(U2::new()), "Hello");
208    }
209
210    #[test]
211    fn list_range_from_index() {
212        let list = (1, 2.5, "Hello").into_tuple_list();
213        assert_eq!(*list.index(U0::new()..), (1, (2.5, ("Hello", ()))));
214        assert_eq!(*list.index(U1::new()..), (2.5, ("Hello", ())));
215        assert_eq!(*list.index(U2::new()..), ("Hello", ()));
216        let () = *list.index(U3::new()..);
217        // assert_eq!(*list.index(U4::new()..), ()); // Compiler error: index out of bounds
218    }
219}