summaryrefslogtreecommitdiff
path: root/src/managed_slice.rs
blob: e00c9c80cd4ef6db1b86df49694962b1389301e7 (plain)
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
use crate::{AcpiError, AcpiResult};
use core::{
    alloc::{Allocator, Layout},
    mem,
    ptr::NonNull,
};

/// Thin wrapper around a regular slice, taking a reference to an allocator for automatic
/// deallocation when the slice is dropped out of scope.
#[derive(Debug)]
pub struct ManagedSlice<'a, T, A>
where
    A: Allocator,
{
    slice: &'a mut [T],
    allocator: A,
}

impl<'a, T, A> ManagedSlice<'a, T, A>
where
    A: Allocator,
{
    /// Attempt to allocate a new `ManagedSlice` that holds `len` `T`s.
    pub fn new_in(len: usize, allocator: A) -> AcpiResult<Self> {
        let layout = Layout::array::<T>(len).map_err(|_| AcpiError::AllocError)?;
        match allocator.allocate(layout) {
            Ok(mut ptr) => {
                let slice = unsafe { core::slice::from_raw_parts_mut(ptr.as_mut().as_mut_ptr().cast(), len) };
                Ok(ManagedSlice { slice, allocator })
            }
            Err(_) => Err(AcpiError::AllocError),
        }
    }
}

#[cfg(feature = "alloc")]
impl<'a, T> ManagedSlice<'a, T, alloc::alloc::Global> {
    pub fn new(len: usize) -> AcpiResult<Self> {
        Self::new_in(len, alloc::alloc::Global)
    }
}

impl<'a, T, A> Drop for ManagedSlice<'a, T, A>
where
    A: Allocator,
{
    fn drop(&mut self) {
        unsafe {
            let slice_ptr = NonNull::new_unchecked(self.slice.as_ptr().cast_mut().cast::<u8>());
            let slice_layout =
                Layout::from_size_align_unchecked(mem::size_of_val(self.slice), mem::align_of_val(self.slice));
            self.allocator.deallocate(slice_ptr, slice_layout);
        }
    }
}

impl<'a, T, A> core::ops::Deref for ManagedSlice<'a, T, A>
where
    A: Allocator,
{
    type Target = [T];

    fn deref(&self) -> &Self::Target {
        self.slice
    }
}

impl<'a, T, A> core::ops::DerefMut for ManagedSlice<'a, T, A>
where
    A: Allocator,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.slice
    }
}