enso_generics/
hlist.rs

1//! HList provides many operations to create and manipulate heterogenous lists (HLists) whose length
2//! and element types are known at compile-time. HLists can be used to implement records, variants,
3//! type-indexed products (TIP), type-indexed co-products (TIC), or keyword arguments.
4
5
6
7// =============
8// === HList ===
9// =============
10
11/// Type of every `HList`.
12pub trait HList = HasLength;
13
14/// Empty `HList` value.
15#[derive(Debug,Clone,Copy)]
16pub struct Nil;
17
18/// Non-empty `HList` with head and tail.
19#[derive(Debug,Clone,Copy)]
20#[allow(missing_docs)]
21pub struct Cons<Head,Tail>(pub Head, pub Tail);
22
23
24
25// === Smart Constructors ===
26
27/// Creates new `HList` from the provided elements, similar to `vec!`. In order to provide type for
28/// the list, use the `ty` macro. In order to pattern match on it, use the `pat` macro.
29///
30/// ```compile_fail
31/// let HList::pat![t1,t2] : HList::ty![&str,usize] = HList::new!["hello",7];
32/// ```
33#[macro_export]
34macro_rules! new {
35    ($(,)*) => { $crate::Nil };
36    ($t:expr $(,$($ts:expr),*)?) => {
37        $crate::Cons($t,$crate::new!{$($($ts),*)?})
38    }
39}
40
41/// Pattern matches on a `HList`. See docs of `new` to learn more.
42#[macro_export]
43macro_rules! pat {
44    ($(,)*) => { $crate::Nil };
45    ($t:pat $(,$($ts:pat),*)?) => {
46        $crate::Cons($t,$crate::pat!{$($($ts),*)?})
47    }
48}
49
50/// Smart `HList` type constructor. See docs of `new` to learn more.
51#[macro_export]
52macro_rules! ty {
53    ($(,)*) => { $crate::Nil };
54    ($t:ty $(,$($ts:ty),*)?) => {
55        $crate::Cons<$t,$crate::ty!{$($($ts),*)?}>
56    }
57}
58
59
60
61// ==============
62// === Length ===
63// ==============
64
65/// Compile-time known length value.
66#[allow(missing_docs)]
67pub trait HasLength {
68    const LEN : usize;
69    fn len() -> usize {
70        Self::LEN
71    }
72}
73
74/// Compile-time known length value.
75pub const fn len<T:HasLength>() -> usize {
76    <T as HasLength>::LEN
77}
78
79impl                HasLength for Nil       { const LEN : usize = 0; }
80impl<H,T:HasLength> HasLength for Cons<H,T> { const LEN : usize = 1 + len::<T>(); }
81
82
83
84// ============
85// === Head ===
86// ============
87
88/// Head element accessor.
89#[allow(missing_docs)]
90pub trait KnownHead {
91    type Head;
92}
93
94/// Head element type accessor.
95pub type Head<T> = <T as KnownHead>::Head;
96
97/// Head element accessor.
98#[allow(missing_docs)]
99pub trait GetHead : KnownHead {
100    fn head(&self) -> &Self::Head;
101}
102
103/// Mutable head element accessor.
104#[allow(missing_docs)]
105pub trait GetHeadMut : KnownHead {
106    fn head_mut(&mut self) -> &mut Self::Head;
107}
108
109/// Head element clone.
110#[allow(missing_docs)]
111pub trait GetHeadClone : KnownHead {
112    fn head_clone(&self) -> Self::Head;
113}
114
115impl<T> GetHeadClone for T
116where T:GetHead, Head<T>:Clone {
117    default fn head_clone(&self) -> Self::Head {
118        self.head().clone()
119    }
120}
121
122
123// === Impls ===
124
125impl<H,T> KnownHead for Cons<H,T> {
126    type Head = H;
127}
128
129impl<H,T> GetHead for Cons<H,T> {
130    fn head(&self) -> &Self::Head {
131        &self.0
132    }
133}
134
135impl<H,T> GetHeadMut for Cons<H,T> {
136    fn head_mut(&mut self) -> &mut Self::Head {
137        &mut self.0
138    }
139}
140
141
142
143// ============
144// === Tail ===
145// ============
146
147/// Tail element accessor.
148#[allow(missing_docs)]
149pub trait KnownTail {
150    type Tail;
151}
152
153/// Tail element type accessor.
154pub type Tail<T> = <T as KnownTail>::Tail;
155
156/// Tail element accessor.
157#[allow(missing_docs)]
158pub trait GetTail : KnownTail {
159    fn tail(&self) -> &Self::Tail;
160}
161
162/// Mutable tail element accessor.
163#[allow(missing_docs)]
164pub trait GetTailMut : KnownTail {
165    fn tail_mut(&mut self) -> &mut Self::Tail;
166}
167
168/// Tail element clone.
169#[allow(missing_docs)]
170pub trait GetTailClone : KnownTail {
171    fn tail_clone(&self) -> Self::Tail;
172}
173
174impl<T> GetTailClone for T
175    where T:GetTail, Tail<T>:Clone {
176    default fn tail_clone(&self) -> Self::Tail {
177        self.tail().clone()
178    }
179}
180
181
182// === Impls ===
183
184impl<H,T> KnownTail for Cons<H,T> {
185    type Tail = T;
186}
187
188impl<H,T> GetTail for Cons<H,T> {
189    fn tail(&self) -> &Self::Tail {
190        &self.1
191    }
192}
193
194impl<H,T> GetTailMut for Cons<H,T> {
195    fn tail_mut(&mut self) -> &mut Self::Tail {
196        &mut self.1
197    }
198}
199
200
201
202// ============
203// === Last ===
204// ============
205
206/// Last element accessor.
207#[allow(missing_docs)]
208pub trait KnownLast {
209    type Last;
210}
211
212/// Last element type accessor.
213pub type Last<T> = <T as KnownLast>::Last;
214
215/// Last element accessor.
216#[allow(missing_docs)]
217pub trait GetLast : KnownLast {
218    fn last(&self) -> &Self::Last;
219}
220
221/// Mutable last element accessor.
222#[allow(missing_docs)]
223pub trait GetLastMut : KnownLast {
224    fn last_mut(&mut self) -> &mut Self::Last;
225}
226
227/// Last element clone.
228#[allow(missing_docs)]
229pub trait GetLastClone : KnownLast {
230    fn last_clone(&self) -> Self::Last;
231}
232
233impl<T> GetLastClone for T
234    where T:GetLast, Last<T>:Clone {
235    default fn last_clone(&self) -> Self::Last {
236        self.last().clone()
237    }
238}
239
240
241// === Impls ===
242
243impl<H>             KnownLast for Cons<H,Nil> { type Last = H; }
244impl<H,T:KnownLast> KnownLast for Cons<H,T>   { type Last = Last<T>; }
245
246impl<H> GetLast for Cons<H,Nil> {
247    fn last(&self) -> &Self::Last {
248        &self.0
249    }
250}
251
252impl<H> GetLastMut for Cons<H,Nil> {
253    fn last_mut(&mut self) -> &mut Self::Last {
254        &mut self.0
255    }
256}
257
258impl<H,T:GetLast> GetLast for Cons<H,T> {
259    fn last(&self) -> &Self::Last {
260        self.tail().last()
261    }
262}
263
264impl<H,T:GetLastMut> GetLastMut for Cons<H,T> {
265    fn last_mut(&mut self) -> &mut Self::Last {
266        self.tail_mut().last_mut()
267    }
268}
269
270
271
272
273// ============
274// === Init ===
275// ============
276
277/// Init elements accessor (all but last).
278#[allow(missing_docs)]
279pub trait KnownInit {
280    type Init;
281}
282
283/// Init elements type accessor.
284pub type Init<T> = <T as KnownInit>::Init;
285
286/// Init element clone.
287#[allow(missing_docs)]
288pub trait GetInitClone : KnownInit {
289    fn init_clone(&self) -> Self::Init;
290}
291
292
293// === Impls ===
294
295impl<H>             KnownInit for Cons<H,Nil> { type Init = Nil; }
296impl<H,T:KnownInit> KnownInit for Cons<H,T>   { type Init = Cons<H,Init<T>>; }
297
298impl<H> GetInitClone for Cons<H,Nil> {
299    fn init_clone(&self) -> Self::Init {
300        Nil
301    }
302}
303
304impl<H:Clone,T:GetInitClone> GetInitClone for Cons<H,T> {
305    fn init_clone(&self) -> Self::Init {
306        Cons(self.head().clone(),self.tail().init_clone())
307    }
308}
309
310
311
312// ================
313// === PushBack ===
314// ================
315
316// TODO: Consider implementing PushBack for everything that converts to and from HList.
317
318/// Add a new element to the back of the list.
319#[allow(missing_docs)]
320pub trait PushBack<T> : Sized {
321    type Output : KnownLast<Last=T> + KnownInit<Init=Self>;
322    fn push_back(self,t:T) -> Self::Output;
323}
324
325impl<X> PushBack<X> for Nil {
326    type Output = Cons<X,Nil>;
327    #[inline(always)]
328    fn push_back(self,x:X) -> Self::Output {
329        Cons(x,Nil)
330    }
331}
332
333impl<X,H,T> PushBack<X> for Cons<H,T>
334    where T:PushBack<X> {
335    type Output = Cons<H,<T as PushBack<X>>::Output>;
336    #[inline(always)]
337    fn push_back(self,x:X) -> Self::Output {
338        let Cons(head,tail) = self;
339        Cons(head,tail.push_back(x))
340    }
341}
342
343
344
345// ===============
346// === PopBack ===
347// ===============
348
349// TODO: Consider implementing PopBack for everything that converts to and from HList.
350
351/// Remove the last element of the list and return it and the new list.
352#[allow(missing_docs)]
353pub trait PopBack : KnownLast + KnownInit {
354    fn pop_back(self) -> (Self::Last,Self::Init);
355}
356
357impl<H> PopBack for Cons<H,Nil> {
358    fn pop_back(self) -> (Self::Last,Self::Init) {
359        (self.0,Nil)
360    }
361}
362
363impl<H,T> PopBack for Cons<H,T>
364where T:PopBack {
365    fn pop_back(self) -> (Self::Last,Self::Init) {
366        let (last,tail) = self.1.pop_back();
367        (last,Cons(self.0,tail))
368    }
369}