fera_array/
prefixed.rs

1use std::mem;
2use std::ptr;
3use std::slice;
4
5/// This is used as starting point to implement other types. See for example the code for `RcArray`.
6pub struct PrefixedArray<I: PrefixedArrayInfo, T> {
7    inner: *mut Inner<I, T>,
8}
9
10pub trait PrefixedArrayInfo {
11    fn len(&self) -> usize;
12
13    fn capacity(&self) -> usize;
14}
15
16#[repr(C)]
17struct Inner<I, T> {
18    info: I,
19    data: [T; 0],
20}
21
22impl<I: PrefixedArrayInfo, T> PrefixedArray<I, T> {
23    pub fn allocate(info: I) -> Self {
24        assert_ne!(0, ::std::mem::size_of::<T>(), "ZST not supported");
25        let mut data = Vec::<I>::with_capacity(Self::vec_cap(info.capacity()));
26        let inner = data.as_mut_ptr();
27        unsafe {
28            ptr::write(&mut *inner, info);
29        }
30        mem::forget(data);
31        PrefixedArray { inner: inner as _ }
32    }
33
34    fn vec_cap(len: usize) -> usize {
35        // TODO: wrapping
36        // TODO: allocate bytes, alignment?
37        let bytes = mem::size_of::<I>() + mem::size_of::<T>() * len;
38        div_round_up(bytes, mem::size_of::<I>())
39    }
40
41    /// Write `value` to inner data at `offset` using `std::ptr::write`.
42    #[inline]
43    pub unsafe fn write(&mut self, offset: usize, value: T) {
44        ptr::write(self.data_mut().offset(offset as isize), value);
45    }
46
47    /// Returns the inner data as a slice with length `info.len()`.
48    #[inline]
49    pub fn as_slice(&self) -> &[T] {
50        unsafe { slice::from_raw_parts(self.data(), self.len()) }
51    }
52
53    /// Returns the inner data as a mutable slice with length `info.len()`.
54    #[inline]
55    pub fn as_mut_slice(&mut self) -> &mut [T] {
56        unsafe { slice::from_raw_parts_mut(self.data_mut(), self.len()) }
57    }
58
59    /// Creates a new `PrefixedArray` that share the inner data with `self`.
60    #[inline]
61    pub unsafe fn clone_shallow(&self) -> Self {
62        PrefixedArray { inner: self.inner }
63    }
64
65    /// Drop the array elements, the info and deallocate.
66    #[inline]
67    pub unsafe fn drop_and_deallocate(&mut self) {
68        let cap = self.info().capacity();
69        ptr::drop_in_place(self.as_mut_slice());
70        ptr::drop_in_place(&mut *self);
71        Vec::from_raw_parts(self.inner, 0, Self::vec_cap(cap));
72    }
73
74    pub fn info(&self) -> &I {
75        &self.inner().info
76    }
77
78    pub fn info_mut(&mut self) -> &mut I {
79        &mut self.inner_mut().info
80    }
81
82    fn data(&self) -> *const T {
83        self.inner().data.as_ptr()
84    }
85
86    fn data_mut(&mut self) -> *mut T {
87        self.inner_mut().data.as_mut_ptr()
88    }
89
90    fn len(&self) -> usize {
91        self.info().len()
92    }
93
94    fn inner(&self) -> &Inner<I, T> {
95        unsafe { &*self.inner }
96    }
97
98    fn inner_mut(&mut self) -> &mut Inner<I, T> {
99        unsafe { &mut *self.inner }
100    }
101}
102
103#[inline]
104fn div_round_up(divident: usize, divisor: usize) -> usize {
105    1 + ((divident - 1) / divisor)
106}
107
108#[cfg(test)]
109mod tests {
110    use super::{PrefixedArray, PrefixedArrayInfo, div_round_up};
111    use testdrop::{self, TestDrop};
112
113    #[test]
114    fn test_div_round_up() {
115        assert_eq!(6, div_round_up(6, 1));
116        assert_eq!(7, div_round_up(7, 1));
117        assert_eq!(8, div_round_up(8, 1));
118
119        assert_eq!(3, div_round_up(6, 2));
120        assert_eq!(4, div_round_up(7, 2));
121        assert_eq!(4, div_round_up(8, 2));
122
123        assert_eq!(2, div_round_up(6, 3));
124        assert_eq!(3, div_round_up(7, 3));
125        assert_eq!(3, div_round_up(8, 3));
126        assert_eq!(3, div_round_up(9, 3));
127        assert_eq!(4, div_round_up(10, 3));
128    }
129
130    struct Info {
131        len: usize,
132        cap: usize,
133    }
134
135    impl PrefixedArrayInfo for Info {
136        fn len(&self) -> usize {
137            self.len
138        }
139
140        fn capacity(&self) -> usize {
141            self.cap
142        }
143    }
144
145    #[test]
146    fn drop_and_deallocate() {
147        let test = TestDrop::new();
148        let v = &mut PrefixedArray::allocate(Info { len: 0, cap: 5 });
149
150        let (a, item_a) = test.new_item();
151        let (b, item_b) = test.new_item();
152        let (c, item_c) = test.new_item();
153        let (d, item_d) = test.new_item();
154        let (e, item_e) = test.new_item();
155
156        fn test_write<'a>(
157            v: &mut PrefixedArray<Info, testdrop::Item<'a>>,
158            id: usize,
159            item: testdrop::Item<'a>,
160            index: usize,
161        ) {
162            unsafe {
163                let len = v.inner().info.len;
164                v.write(len, item);
165                v.inner_mut().info.len = len + 1;
166            }
167            assert_eq!(index + 1, v.len());
168            assert_eq!(index + 1, v.as_slice().len());
169            assert_eq!(index + 1, v.as_mut_slice().len());
170            assert_eq!(id, v.as_slice()[index].id());
171            assert_eq!(id, v.as_mut_slice()[index].id());
172        }
173
174        test_write(v, a, item_a, 0);
175        test_write(v, b, item_b, 1);
176        test_write(v, c, item_c, 2);
177        test_write(v, d, item_d, 3);
178        test_write(v, e, item_e, 4);
179
180        // change len so d and e will not be dropped
181        v.inner_mut().info.len = 3;
182
183        unsafe {
184            v.drop_and_deallocate();
185        }
186
187        test.assert_drop(a);
188        test.assert_drop(b);
189        test.assert_drop(c);
190        test.assert_no_drop(d);
191        test.assert_no_drop(e);
192    }
193}