dynvec/
raw.rs

1use crate::region::Region;
2
3use std::alloc::Layout;
4use std::ops;
5
6pub struct Header {
7    /// A function that causes an item to be dropped.
8    drop_fn: Option<fn(*mut u8)>,
9}
10
11/// A handle to an allocated object of a dynamic vector.
12pub struct Handle<T> {
13    ptr: *mut T,
14}
15
16impl<T> Clone for Handle<T> {
17    fn clone(&self) -> Self {
18        Self { ptr: self.ptr }
19    }
20}
21
22impl<T> Copy for Handle<T> {}
23
24impl<T> Handle<T> {
25    /// Turns this `Handle` into a `RawHandle`.
26    pub fn raw(self) -> RawHandle {
27        RawHandle {
28            ptr: self.ptr as *mut u8,
29        }
30    }
31}
32
33/// A handle to an allocated object of a dynamic vector that does
34/// not own a `T`.
35pub struct RawHandle {
36    ptr: *mut u8,
37}
38
39impl Clone for RawHandle {
40    fn clone(&self) -> Self {
41        Self { ptr: self.ptr }
42    }
43}
44
45impl Copy for RawHandle {}
46
47impl<T> From<Handle<T>> for RawHandle {
48    fn from(handle: Handle<T>) -> Self {
49        handle.raw()
50    }
51}
52
53impl RawHandle {
54    /// Turns this `RawHandle` into a normal one, given it a type.
55    ///
56    /// # Safety
57    /// The type `T` must be the one that created the raw handle.
58    pub unsafe fn trust_type<T>(self) -> Handle<T> {
59        Handle {
60            ptr: self.ptr as *mut T,
61        }
62    }
63}
64
65/// A dynamic vector, able to store any kind of data.
66#[derive(Default)]
67pub struct RawDynVec<R: Region<Header>> {
68    region: R,
69}
70
71impl<R: Region<Header>> Drop for RawDynVec<R> {
72    fn drop(&mut self) {
73        self.clear();
74    }
75}
76
77impl<R: Region<Header>, T> ops::Index<Handle<T>> for RawDynVec<R> {
78    type Output = T;
79
80    fn index(&self, index: Handle<T>) -> &Self::Output {
81        self.get(index)
82    }
83}
84
85impl<R: Region<Header>, T> ops::IndexMut<Handle<T>> for RawDynVec<R> {
86    fn index_mut(&mut self, index: Handle<T>) -> &mut Self::Output {
87        self.get_mut(index)
88    }
89}
90
91impl<R: Region<Header>> RawDynVec<R> {
92    /// Creates a new `RawDynVec` with the given region.
93    pub fn with_region(region: R) -> Self {
94        Self { region }
95    }
96
97    /// Returns the number of items this vector stores.
98    pub fn count(&self) -> usize {
99        self.region.count()
100    }
101
102    /// Tries to insert a `T` into the vector and returns a Handle
103    /// to this `T`. If the `T` cannot be allocated, it gets
104    /// returned as the error.
105    pub fn try_insert<T>(&mut self, item: T) -> Result<Handle<T>, T> {
106        let layout = Layout::new::<T>();
107        
108        let drop_fn: Option<fn(*mut u8)> = if std::mem::needs_drop::<T>() {
109            Some(|ptr: *mut u8| unsafe { std::ptr::drop_in_place(ptr as *mut T) })
110        } else {
111            None
112        };
113        
114        match unsafe { self.insert_raw(layout, drop_fn) } {
115            Ok(handle) => {
116                unsafe {
117                    handle.ptr.cast::<T>().write(item);
118                    Ok(handle.trust_type::<T>())
119                }
120            },
121
122            Err(()) => Err(item),
123        }
124    }
125
126    /// Clears the whole vector, leaving it empty.
127    pub fn clear(&mut self) {
128        for (ptr, header) in self.region.deallocate_all() {
129            if let Some(drop_fn) = header.drop_fn {
130                // the allocated item needed to be dropped
131                drop_fn(ptr)
132            }
133        }
134    }
135
136    /// Inserts a `T` into the vector and returns a Handle to this `T`.
137    ///
138    /// # Panics
139    /// This function panics if the `T` could not be allocated.
140    pub fn insert<T>(&mut self, item: T) -> Handle<T> {
141        match self.try_insert(item) {
142            Ok(handle) => handle,
143            Err(_) => {
144                panic!("Failed to allocate the item");
145            }
146        }
147    }
148
149    /// Allocates memory as described by the given layout. If the allocation
150    /// is a success, a raw handle to the allocation is returned. In this case,
151    /// it is up to the caller to initialize the allocated value because the
152    /// vector now assumes it is initialized.
153    /// 
154    /// # Safety
155    /// * The `drop_fn` function must cause the object to be dropped.
156    /// * The allocated data must get initialized before it being dropped.
157    pub unsafe fn insert_raw(
158        &mut self,
159        layout: Layout,
160        drop_fn: Option<fn(*mut u8)>,
161    ) -> Result<RawHandle, ()> {
162        let header = Header {
163            drop_fn,
164        };
165
166        match self.region.allocate(layout, header) {
167            Ok(ptr) => {
168                Ok(RawHandle { ptr, })
169            }
170
171            Err(_) => Err(()),
172        }
173    }
174
175    /// Tries to remove the `T` located by the given handle. If the handle
176    /// was invalid, `Err(())` is returned.
177    pub fn remove<T>(&mut self, handle: Handle<T>) -> Result<T, ()> {
178        if let Some(_) = self.region.deallocate(handle.ptr as *mut u8) {
179            // the region successfuly deallocated the object
180            // this means that we were able to initialize it before
181            let item = unsafe { handle.ptr.read() };
182
183            // we don't need to drop the item
184            // this will be up to the caller
185            Ok(item)
186        } else {
187            Err(())
188        }
189    }
190
191    /// Tries to remove an item out of the vector. If the handle was
192    /// invalid `Err(())` is returned.
193    ///
194    /// As the handle is raw, the item cannot be returned. But it is
195    /// still dropped properly.
196    pub fn remove_raw(&mut self, handle: RawHandle) -> Result<(), ()> {
197        if let Some(header) = self.region.deallocate(handle.ptr) {
198            if let Some(drop_fn) = header.drop_fn {
199                // the item needed to be dropped
200                drop_fn(handle.ptr);
201            }
202
203            Ok(())
204        } else {
205            Err(())
206        }
207    }
208
209    /// Gets a pointer to the data located by the given handle.
210    ///
211    /// # Safety
212    /// If the null pointer is returned, the handle was invalid.
213    pub fn get_ptr<T>(&self, handle: Handle<T>) -> *const T {
214        if self.region.has_allocated(handle.ptr as *mut u8) {
215            handle.ptr
216        } else {
217            std::ptr::null()
218        }
219    }
220
221    /// Gets a pointer to the data located by the given handle.
222    ///
223    /// # Safety
224    /// If the null pointer is returned, the handle was invalid.
225    pub fn get_mut_ptr<T>(&self, handle: Handle<T>) -> *mut T {
226        if self.region.has_allocated(handle.ptr as *mut u8) {
227            handle.ptr
228        } else {
229            std::ptr::null_mut()
230        }
231    }
232
233    /// Gets a pointer to the data located by the given handle.
234    ///
235    /// # Safety
236    /// If the null pointer is returned, the handle was invalid.
237    pub fn get_ptr_raw(&mut self, handle: RawHandle) -> *const u8 {
238        if self.region.has_allocated(handle.ptr) {
239            handle.ptr
240        } else {
241            std::ptr::null()
242        }
243    }
244
245    /// Gets a pointer to the data located by the given handle.
246    ///
247    /// # Safety
248    /// If the null pointer is returned, the handle was invalid.
249    pub fn get_mut_ptr_raw(&mut self, handle: RawHandle) -> *mut u8 {
250        if self.region.has_allocated(handle.ptr) {
251            handle.ptr
252        } else {
253            std::ptr::null_mut()
254        }
255    }
256
257    /// Tries to get a reference to the data located by the given handle.
258    pub fn try_get<T>(&self, handle: Handle<T>) -> Option<&T> {
259        // if the handle is invalid, the null pointer is returned
260        // this will transmute into `None`
261        unsafe { std::mem::transmute(self.get_ptr(handle)) }
262    }
263
264    /// Tries to get a reference to the data located by the given handle.
265    pub fn try_get_mut<T>(&mut self, handle: Handle<T>) -> Option<&mut T> {
266        unsafe { std::mem::transmute(self.get_mut_ptr(handle)) }
267    }
268
269    /// Gets a reference to the data located by the given handle.
270    ///
271    /// # Panics
272    /// If the handle is valid, this function panics.
273    pub fn get<T>(&self, handle: Handle<T>) -> &T {
274        self.try_get(handle).expect("Invalid handle")
275    }
276
277    /// Gets a reference to the data located by the given handle.
278    ///
279    /// # Panics
280    /// If the handle is valid, this function panics.
281    pub fn get_mut<T>(&mut self, handle: Handle<T>) -> &mut T {
282        self.try_get_mut(handle).expect("Invalid handle")
283    }
284}
285
286#[cfg(test)]
287#[test]
288fn properly_dropped() {
289    use std::cell::Cell;
290    use std::rc::Rc;
291
292    use crate::region::block::Block;
293
294    let drop_count = Rc::new(Cell::new(0u16));
295    struct DropCheck(Rc<Cell<u16>>);
296    impl Drop for DropCheck {
297        fn drop(&mut self) {
298            self.0.set(self.0.get() + 1);
299        }
300    }
301
302    {
303        let mut vec = RawDynVec::with_region(Block::new(2048));
304
305        for _ in 0..100 {
306            vec.insert(DropCheck(Rc::clone(&drop_count)));
307        }
308
309        // vec should be dropped now
310    }
311
312    assert_eq!(drop_count.get(), 100);
313}
314
315#[cfg(test)]
316#[test]
317fn normal_use() {
318    use crate::region::block::Block;
319
320    let mut vec = RawDynVec::with_region(Block::new(2048));
321
322    let h_i32 = vec.insert(5i32);
323    let h_vec = vec.insert(vec![1u8, 2, 3]);
324
325    assert_eq!(vec[h_i32], 5i32);
326    assert_eq!(vec[h_vec][1], 2u8);
327
328    vec[h_vec].push(8);
329
330    assert_eq!(vec.get(h_vec).last(), Some(&8));
331
332    let other_vec = vec.remove(h_vec).unwrap();
333
334    assert_eq!(&other_vec[..], &[1, 2, 3, 8][..]);
335
336    assert_eq!(vec.try_get(h_vec), None);
337}