dynamic_list/list/
mod.rs

1use crate::{Empty, Length};
2use std::mem::forget;
3use traits::*;
4
5pub(crate) mod traits;
6
7pub struct Node<V, N = Empty> {
8    value: *const V,
9    next: N,
10}
11
12impl Node<Empty, Empty> {
13    #[inline]
14    const fn new<V>(value: *const V) -> Node<V> {
15        Node { value, next: Empty }
16    }
17}
18
19impl<V, N> Node<V, N> {
20    #[inline]
21    const fn prepend<V2>(self, value: *const V2) -> Node<V2, Self> {
22        Node { value, next: self }
23    }
24    #[inline]
25    pub const fn value(&self) -> &V {
26        // Safety: Value read should never be null, as the value is being stored in the heap.
27        // See DynamicList add method.
28        unsafe { &*self.value }
29    }
30
31    #[inline]
32    pub fn value_mut(&mut self) -> &mut V {
33        // Safety: Value read should never be null, as the value is being stored in the heap.
34        // See DynamicList add method.
35        unsafe { self.value.cast_mut().as_mut().unwrap_unchecked() }
36    }
37
38    #[inline]
39    pub const fn next(&self) -> &N {
40        &self.next
41    }
42
43    #[inline]
44    pub fn next_mut(&mut self) -> &mut N {
45        &mut self.next
46    }
47}
48
49pub struct DynamicList<F, B: DropValue> {
50    forward: F,
51    backward: B,
52}
53
54impl DynamicList<Empty, Empty> {
55    #[inline]
56    pub const fn new() -> Self {
57        Self {
58            forward: Empty,
59            backward: Empty,
60        }
61    }
62
63    #[inline]
64    pub fn push<V>(self, value: V) -> DynamicList<Node<V>, Node<V>> {
65        let value = Box::into_raw(Box::new(value));
66
67        DynamicList {
68            forward: Node::new(value),
69            backward: Node::new(value),
70        }
71    }
72}
73
74impl Default for DynamicList<Empty, Empty> {
75    fn default() -> Self {
76        Self::new()
77    }
78}
79
80// Size and Drop Value are always implemented
81impl<F, N: Length + DropValue> DynamicList<F, N> {
82    #[inline]
83    pub const fn forward(&self) -> &F {
84        &self.forward
85    }
86
87    #[inline]
88    pub fn forward_mut(&mut self) -> &mut F {
89        &mut self.forward
90    }
91
92    #[inline]
93    pub const fn backward(&self) -> &N {
94        &self.backward
95    }
96
97    #[inline]
98    pub fn backward_mut(&mut self) -> &mut N {
99        &mut self.backward
100    }
101
102    #[inline]
103    pub const fn len(&self) -> usize {
104        N::SIZE
105    }
106
107    #[inline]
108    pub const fn is_empty(&self) -> bool {
109        N::SIZE == 0
110    }
111}
112
113// Generic push:
114impl<F: ListAppend, BV, BN: DropValue> DynamicList<F, Node<BV, BN>> {
115    #[inline]
116    pub fn push<V>(self, value: V) -> DynamicList<F::Output<V>, Node<V, Node<BV, BN>>>
117    where
118        <F as ListAppend>::Output<V>: DropValue,
119    {
120        let value = Box::into_raw(Box::new(value));
121
122        // Safety: We are deconstructing the struct while avoiding calling the drop method. As this
123        // method should only be called at the end by the user.
124        let forward = unsafe { (&self.forward as *const F).read() };
125        let backward = unsafe { (&self.backward as *const Node<BV, BN>).read() };
126        forget(self);
127
128        DynamicList {
129            forward: forward.append(value),
130            backward: backward.prepend(value),
131        }
132    }
133}
134
135impl<F, N: DropValue> Drop for DynamicList<F, N> {
136    fn drop(&mut self) {
137        // Safety: We can should only call the recursive drop method in one of the branches:
138        // Otherwise this could lead to double free calls.
139        unsafe {
140            self.backward.drop_values();
141        }
142    }
143}
144
145#[macro_export]
146macro_rules! list {
147    () => {
148        DynamicList::new()
149    };
150    ($($x:expr),+ $(,)?) => {
151        DynamicList::new()$(.push($x))+
152    };
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    use crate::*;
159    use typenum::*;
160
161    #[test]
162    fn works_1() {
163        let list = DynamicList::new().push(1);
164
165        assert_eq!(list.forward.value(), &1);
166        assert_eq!(list.backward.value(), &1);
167
168        assert_eq!(list.forward.next, Empty);
169        assert_eq!(list.backward.next, Empty);
170
171        assert_eq!(list.len(), 1);
172    }
173
174    #[test]
175    fn works_n() {
176        let list = DynamicList::new().push(1).push("two").push(3.0);
177
178        assert_eq!(list.forward.next.next.value(), &3.0);
179        assert_eq!(list.backward.next.next.value(), &1);
180
181        assert_eq!(list.len(), 3);
182    }
183
184    #[test]
185    fn test_macro() {
186        let list_1 = list![1, "two", 3.0, true];
187        let list_2 = list!().push(1).push("two").push(3.0).push(true);
188
189        assert_eq!(list_1.len(), 4);
190        assert_eq!(list_2.len(), 4);
191    }
192
193    #[test]
194    fn test_drop() {
195        static mut N_DROPS: u8 = 0;
196
197        fn drops() -> u8 {
198            unsafe { N_DROPS }
199        }
200
201        struct Test;
202
203        impl Drop for Test {
204            fn drop(&mut self) {
205                unsafe {
206                    N_DROPS += 1;
207                }
208            }
209        }
210
211        // Test that the struct Test implemented properly drop
212        drop(Test);
213        assert_eq!(drops(), 1);
214
215        let list = list![Test, Test, Test];
216        drop(list);
217        assert_eq!(drops(), 4);
218    }
219
220    #[test]
221    fn test_index() {
222        let list_1 = list![1, "two", 3.0, true];
223
224        assert_eq!(&1, Index::<U0>::index(list_1.forward()));
225        assert_eq!(&"two", Index::<U1>::index(list_1.forward()));
226        assert_eq!(&3.0, Index::<U2>::index(list_1.forward()));
227        assert_eq!(&true, Index::<U3>::index(list_1.forward()));
228        assert_eq!(Empty, Index::<U4>::index(list_1.forward()));
229
230        assert_eq!(Empty, Index::<U100>::index(list_1.forward()));
231    }
232}