1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
//! Helpers for cons tuple type.

use core::marker::PhantomData;

/// Constructs a [trait@Cons] based on the values or identifiers passed in.
///
/// # Examples
/// ```
/// # use muds::cons;
/// let (c1, (c2, (c3, ()))) = cons!(123f32, "hello", Some(45));
/// assert_eq!((c1, c2, c3), (123f32, "hello", Some(45)));
///
/// let cons!(c1, c2, c3) = cons!(123f32, "hello", Some(45));
/// assert_eq!(c3, Some(45));
///
/// let cons!(c1, c2, c3, ..rest) = cons!(1, 2, 3, 4, 5);
/// assert_eq!(rest, cons!(4, 5));
///
/// // rev[..] captures in reverse order.
/// let cons!(rev[c1, c2, c3, c4, c5]) = cons!(1, 2, 3, 4, 5);
/// assert_eq!([c1, c2, c3], [5, 4, 3]);
/// ```
#[macro_export]
macro_rules! cons {
    () => { () };

    // Base cases for rev, calls cons! normally
    (rev[$head:tt] $($reversed:tt)*) => {
        cons!($head, $($reversed)*)
    };
    (rev[$head:expr] $($reversed:tt)*) => {
        cons!($head, $($reversed)*)
    };
    (rev[$head:pat_param] $($reversed:tt)*) => {
        cons!($head, $($reversed)*)
    };

    // Recursively reverses the rev list
    (rev[$head:tt, $($rest:tt)*] $($reversed:tt)*) => {
        cons!(rev[$($rest)*] $head, $($reversed)*)
    };
    (rev[$head:expr, $($rest:tt)*] $($reversed:tt)*) => {
        cons!(rev[$($rest)*] $head, $($reversed)*)
    };
    (rev[$head:pat_param, $($rest:tt)*] $($reversed:tt)*) => {
        cons!(rev[$($rest)*] $head, $($reversed)*)
    };

    // Matches rest params
    (..$rest:tt) => { $rest };
    (..$rest:expr) => { $rest };

    // Base cases, returns single element cons
    ($head:tt) => { ($head, ()) };
    ($head:expr) => { ($head, ()) };
    ($head:pat_param) => { ($head, ()) };

    // Recursively builds the cons
    ($head:tt, $($tail:tt)*) => {
        ($head, cons!($($tail)*))
    };
    ($head:expr, $($tail:tt)*) => {
        ($head, cons!($($tail)*))
    };
    ($head:pat_param, $($tail:tt)*) => {
        ($head, cons!($($tail)*))
    };
}

/// Returns the concrete [trait@Cons] type signature for the provided types.
///
/// # Examples
/// ```
/// # use muds::{cons, Cons};
/// let c: Cons!(f32, &str, Option<i32>) = cons![123f32, "hello", Some(45)];
/// let c: Cons!(f32, ..Cons!(&str, Option<i32>)) = cons![123f32, "hello", Some(45)];
/// ```
#[macro_export]
macro_rules! Cons {
    () => { () };
    (..$Rest:ty) => { $Rest };
    ($A:ty) => { ($A, ()) };
    ($A:ty, $($Tail:tt)*) => {
        ($A, Cons!($($Tail)*))
    };
}

/// Trait for a [Cons](https://en.wikipedia.org/wiki/Cons).
pub trait Cons: Sized {
    const LEN: usize;

    /// Returns the length of cons.
    ///
    /// # Examples
    /// ```
    /// # use muds::{cons, collections::Cons};
    /// assert_eq!(cons!(1, 2, 3, 4, 5).len(), 5);
    /// ```
    #[inline]
    fn len(&self) -> usize {
        Self::LEN
    }

    /// Returns if the cons is empty.
    ///
    /// # Examples
    /// ```
    /// # use muds::{cons, collections::Cons};
    /// assert!(().is_empty());
    /// assert!(!cons!(1, 2, 3, 4, 5).is_empty());
    /// ```
    #[inline]
    fn is_empty(&self) -> bool {
        Self::LEN == 0
    }

    /// Gets an element by type from this cons.
    ///
    /// # Examples
    /// ```
    /// # use muds::{cons, collections::Cons};
    /// assert_eq!(*cons!(1f32, 1i32, 1u32).get::<i32, _>(), 1i32);
    /// ```
    #[inline]
    fn get<T, Index>(&self) -> &T
    where
        Self: ConsGetter<T, Index>,
    {
        ConsGetter::get(self)
    }

    /// Mutably gets an element by type from this cons.
    /// # Examples
    /// ```
    /// # use muds::{cons, collections::Cons};
    /// let mut c = cons!(1f32, 1i32, 1u32);
    /// *c.get_mut::<i32, _>() = 10;
    /// assert_eq!(c, cons!(1f32, 10i32, 1u32));
    /// ```
    #[inline]
    fn get_mut<T, Index>(&mut self) -> &mut T
    where
        Self: ConsGetter<T, Index>,
    {
        ConsGetter::get_mut(self)
    }

    /// Append to this cons.
    ///
    /// # Examples
    /// ```
    /// # use muds::{cons, collections::Cons};
    /// let cons!(c1, c2, c3, c4, c5) = cons!(1, 2).append(cons!(3, 4, 5));
    /// assert_eq!([c1, c2, c3, c4, c5], [1, 2, 3, 4, 5]);
    /// ```
    #[inline]
    fn append<RHS: Cons>(self, rhs: RHS) -> <Self as Append<RHS>>::Output
    where
        Self: Append<RHS>,
    {
        Append::append(self, rhs)
    }

    /// Reverse this cons.
    //
    /// # Examples
    /// ```
    /// # use muds::{cons, collections::Cons};
    /// let cons!(c1, c2, c3, c4, c5) = cons!(1, 2, 3, 4, 5).rev();
    /// assert_eq!([c1, c2, c3, c4, c5], [5, 4, 3, 2, 1]);
    /// ```
    #[inline]
    fn rev(self) -> <Self as IntoRev>::Output
    where
        Self: IntoRev,
    {
        IntoRev::rev(self)
    }
}

impl Cons for () {
    const LEN: usize = 0;
}

impl<H, T: Cons> Cons for (H, T) {
    const LEN: usize = 1 + T::LEN;
}

/// Trait for appending to self.
pub trait Append<RHS> {
    /// Output type.
    type Output;

    /// Append to self.
    fn append(self, rhs: RHS) -> Self::Output;
}

impl<RHS> Append<RHS> for ()
where
    RHS: Cons,
{
    type Output = RHS;

    #[inline(always)]
    fn append(self, rhs: RHS) -> RHS {
        rhs
    }
}

impl<H, Tail, RHS> Append<RHS> for (H, Tail)
where
    Tail: Append<RHS>,
    RHS: Cons,
{
    type Output = (H, <Tail as Append<RHS>>::Output);

    #[inline(always)]
    fn append(self, rhs: RHS) -> Self::Output {
        (self.0, self.1.append(rhs))
    }
}

/// Trait for reversing self.
pub trait IntoRev {
    /// Output type.
    type Output;

    /// Revert self.
    fn rev(self) -> Self::Output;
}

impl IntoRev for () {
    type Output = ();

    #[inline(always)]
    fn rev(self) -> Self::Output {
        self
    }
}

impl<T, Tail> IntoRev for (T, Tail)
where
    Tail: IntoRev,
    <Tail as IntoRev>::Output: Append<(T, ())>,
{
    type Output = <<Tail as IntoRev>::Output as Append<(T, ())>>::Output;

    #[inline(always)]
    fn rev(self) -> Self::Output {
        self.1.rev().append((self.0, ()))
    }
}

/// Trait for getting a [trait@Cons] element by type.
pub trait ConsGetter<T, I> {
    /// Gets an element by type from cons.
    fn get(&self) -> &T;

    /// Mutably gets an element by type from cons.
    fn get_mut(&mut self) -> &mut T;
}

impl<T, Tail> ConsGetter<T, Here> for (T, Tail) {
    #[inline(always)]
    fn get(&self) -> &T {
        &self.0
    }

    #[inline(always)]
    fn get_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

impl<Head, Tail, FromTail, TailIndex> ConsGetter<FromTail, There<TailIndex>> for (Head, Tail)
where
    Tail: ConsGetter<FromTail, TailIndex>,
{
    #[inline(always)]
    fn get(&self) -> &FromTail {
        self.1.get()
    }

    #[inline(always)]
    fn get_mut(&mut self) -> &mut FromTail {
        self.1.get_mut()
    }
}

/// Used as an index into a [trait@Cons].
pub struct Here {
    _priv: (),
}

/// Used as an index into a [trait@Cons].
pub struct There<T> {
    _marker: PhantomData<T>,
}