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
pub use self::traits::{Index, NotEmpty, Size};
use std::mem::forget;

mod traits;

#[derive(Debug, PartialEq, Eq)]
pub struct Empty;

pub struct Node<V, N = Empty> {
    value: *const V,
    next: N,
}

impl Node<Empty, Empty> {
    #[inline]
    const fn new<V>(value: *const V) -> Node<V> {
        Node { value, next: Empty }
    }
}

impl<V, N> Node<V, N> {
    #[inline]
    const fn prepend<V2>(self, value: *const V2) -> Node<V2, Self> {
        Node { value, next: self }
    }
    #[inline]
    pub const fn value(&self) -> &V {
        // Safety: Value read should never be null, as the value is being stored in the heap.
        // See DynamicList add method.
        unsafe { &*self.value }
    }

    #[inline]
    pub fn value_mut(&mut self) -> &mut V {
        // Safety: Value read should never be null, as the value is being stored in the heap.
        // See DynamicList add method.
        unsafe { self.value.cast_mut().as_mut().unwrap_unchecked() }
    }

    #[inline]
    pub const fn next(&self) -> &N {
        &self.next
    }

    #[inline]
    pub fn next_mut(&mut self) -> &mut N {
        &mut self.next
    }
}

pub struct DynamicList<F, B: traits::DropValue> {
    forward: F,
    backward: B,
}

impl DynamicList<Empty, Empty> {
    #[inline]
    pub const fn new() -> Self {
        Self {
            forward: Empty,
            backward: Empty,
        }
    }

    #[inline]
    pub fn push<V>(self, value: V) -> DynamicList<Node<V>, Node<V>> {
        let value = Box::into_raw(Box::new(value));

        DynamicList {
            forward: Node::new(value),
            backward: Node::new(value),
        }
    }
}

impl Default for DynamicList<Empty, Empty> {
    fn default() -> Self {
        Self::new()
    }
}

// Size and Drop Value are always implemented
impl<F, N: Size + traits::DropValue> DynamicList<F, N> {
    #[inline]
    pub const fn forward(&self) -> &F {
        &self.forward
    }

    #[inline]
    pub fn forward_mut(&mut self) -> &mut F {
        &mut self.forward
    }

    #[inline]
    pub const fn backward(&self) -> &N {
        &self.backward
    }

    #[inline]
    pub fn backward_mut(&mut self) -> &mut N {
        &mut self.backward
    }

    #[inline]
    pub const fn len(&self) -> usize {
        N::SIZE
    }

    #[inline]
    pub const fn is_empty(&self) -> bool {
        N::SIZE == 0
    }
}

// Generic push:
impl<F: traits::Append, BV, BN: traits::DropValue> DynamicList<F, Node<BV, BN>> {
    #[inline]
    pub fn push<V>(self, value: V) -> DynamicList<F::Output<V>, Node<V, Node<BV, BN>>>
    where
        <F as traits::Append>::Output<V>: traits::DropValue,
    {
        let value = Box::into_raw(Box::new(value));

        // Safety: We are deconstructing the struct while avoiding calling the drop method. As this
        // method should only be called at the end by the user.
        let forward = unsafe { (&self.forward as *const F).read() };
        let backward = unsafe { (&self.backward as *const Node<BV, BN>).read() };
        forget(self);

        DynamicList {
            forward: forward.append(value),
            backward: backward.prepend(value),
        }
    }
}

impl<F, N: traits::DropValue> Drop for DynamicList<F, N> {
    fn drop(&mut self) {
        // Safety: We can should only call the recursive drop method in one of the branches:
        // Otherwise this could lead to double free calls.
        unsafe {
            self.backward.drop_values();
        }
    }
}

#[macro_export]
macro_rules! list {
    () => {
        DynamicList::new()
    };
    ($($x:expr),+ $(,)?) => {
        DynamicList::new()$(.push($x))+
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    use typenum::*;

    #[test]
    fn works_1() {
        let list = DynamicList::new().push(1);

        assert_eq!(list.forward.value(), &1);
        assert_eq!(list.backward.value(), &1);

        assert_eq!(list.forward.next, Empty);
        assert_eq!(list.backward.next, Empty);

        assert_eq!(list.len(), 1);
    }

    #[test]
    fn works_n() {
        let list = DynamicList::new().push(1).push("two").push(3.0);

        assert_eq!(list.forward.next.next.value(), &3.0);
        assert_eq!(list.backward.next.next.value(), &1);

        assert_eq!(list.len(), 3);
    }

    #[test]
    fn test_macro() {
        let list_1 = list![1, "two", 3.0, true];
        let list_2 = list!().push(1).push("two").push(3.0).push(true);

        assert_eq!(list_1.len(), 4);
        assert_eq!(list_2.len(), 4);
    }

    #[test]
    fn test_drop() {
        static mut N_DROPS: u8 = 0;

        fn drops() -> u8 {
            unsafe { N_DROPS }
        }

        struct Test;

        impl Drop for Test {
            fn drop(&mut self) {
                unsafe {
                    N_DROPS += 1;
                }
            }
        }

        // Test that the struct Test implemented properly drop
        drop(Test);
        assert_eq!(drops(), 1);

        let list = list![Test, Test, Test];
        drop(list);
        assert_eq!(drops(), 4);
    }

    #[test]
    fn test_index() {
        let list_1 = list![1, "two", 3.0, true];

        assert_eq!(&1, Index::<U0>::index(list_1.forward()));
        assert_eq!(&"two", Index::<U1>::index(list_1.forward()));
        assert_eq!(&3.0, Index::<U2>::index(list_1.forward()));
        assert_eq!(&true, Index::<U3>::index(list_1.forward()));
        assert_eq!(Empty, Index::<U4>::index(list_1.forward()));

        assert_eq!(Empty, Index::<U100>::index(list_1.forward()));
    }
}