summaryrefslogtreecommitdiff
path: root/src/util.rs
blob: ba60395b97d4849a32d089f985f422152c709754 (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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
use std::mem::MaybeUninit;
use std::ptr::NonNull;

pub trait MaybeUninitByteSlice
{
    unsafe fn cast<Item: 'static>(&self) -> &[Item];
}

impl MaybeUninitByteSlice for &[MaybeUninit<u8>]
{
    unsafe fn cast<Item: 'static>(&self) -> &[Item]
    {
        assert_eq!(self.len() % size_of::<Item>(), 0, "Invalid item size");

        assert_eq!(
            self.as_ptr().addr() % align_of::<Item>(),
            0,
            "Invalid item alignment"
        );

        let new_len = self.len() / size_of::<Item>();

        if new_len == 0 {
            return &[];
        }

        unsafe { std::slice::from_raw_parts(self.as_ptr().cast::<Item>(), new_len) }
    }
}

#[derive(Debug)]
pub struct AnonUnique
{
    ptr: NonNull<MaybeUninit<u8>>,
    layout: Layout,
}

impl AnonUnique
{
    pub fn new_uninit(layout: Layout) -> Self
    {
        if layout.size() == 0 {
            return Self { ptr: NonNull::dangling(), layout };
        }

        let Some(ptr) = NonNull::new(unsafe { alloc(layout) }) else {
            handle_alloc_error(layout);
        };

        Self {
            ptr: ptr.cast::<MaybeUninit<u8>>(),
            layout,
        }
    }

    pub fn layout(&self) -> &Layout
    {
        &self.layout
    }

    pub fn as_slice_mut(&mut self) -> &mut [MaybeUninit<u8>]
    {
        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.layout.size()) }
    }

    pub fn as_slice(&self) -> &[MaybeUninit<u8>]
    {
        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.layout.size()) }
    }

    pub fn as_ptr(&self) -> NonNull<MaybeUninit<u8>>
    {
        self.ptr
    }
}

impl Drop for AnonUnique
{
    fn drop(&mut self)
    {
        if self.layout.size() == 0 {
            return;
        }

        unsafe {
            dealloc(self.ptr.as_ptr().cast(), self.layout);
        }
    }
}