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
91
92
93
94
95
96
97
98
//! Memory management.
use std::marker::PhantomData;

/// A region of memory managed on behalf of the host.
///
/// The host is responsible for deallocating the region by calling `deallocate`.
#[repr(C)]
pub struct HostRegion {
    pub offset: u32,
    pub length: u32,
}

impl HostRegion {
    /// Creates a new host region from arguments.
    ///
    /// This does not yet transfer memory ownership from the host.
    pub fn from_arg((offset, length): (u32, u32)) -> Self {
        Self::from_args(offset, length)
    }

    /// Creates a new host region from arguments.
    ///
    /// This does not yet transfer memory ownership from the host.
    pub fn from_args(offset: u32, length: u32) -> Self {
        Self { offset, length }
    }

    /// Transfers ownership of memory to the host by constructing a host region.
    pub fn from_vec(data: Vec<u8>) -> Self {
        let data_ptr = data.as_ptr() as usize;
        let data_len = data.len();
        std::mem::forget(data);

        HostRegion {
            offset: data_ptr as u32,
            length: data_len as u32,
        }
    }

    /// Transfers ownership of memory from the host and returns the vector.
    ///
    /// # Safety
    ///
    /// This is safe as long as the region was constructed from valid arguments.
    pub fn into_vec(self) -> Vec<u8> {
        let ptr = self.offset as *mut u8;
        assert!(!ptr.is_null());

        unsafe { Vec::from_raw_parts(ptr, self.length as usize, self.length as usize) }
    }

    /// Returns a new region by dereferencing a pointer to the region.
    ///
    /// This does not yet transfer memory ownership from the host.
    ///
    /// # Safety
    ///
    /// This is safe as long as the pointer is a valid pointer to the region struct.
    pub unsafe fn deref(arg: *const HostRegion) -> Self {
        let hr = &*arg;
        HostRegion {
            offset: hr.offset,
            length: hr.length,
        }
    }
}

/// Reference to a host region.
pub struct HostRegionRef<'a> {
    pub offset: u32,
    pub length: u32,

    _lifetime: PhantomData<&'a [u8]>,
}

impl<'a> HostRegionRef<'a> {
    /// Creates a new host region from the given byte slice.
    pub fn from_slice(data: &'a [u8]) -> Self {
        Self {
            offset: data.as_ptr() as u32,
            length: data.len() as u32,
            _lifetime: PhantomData,
        }
    }
}

/// Allocate memory on host's behalf.
pub fn allocate_host(length: u32) -> u32 {
    let data: Vec<u8> = Vec::with_capacity(length as usize);
    let data_ptr = data.as_ptr() as usize;
    std::mem::forget(data);
    data_ptr as u32
}

/// Deallocate memory on host's behalf.
pub fn deallocate_host(offset: u32, length: u32) {
    HostRegion::from_args(offset, length).into_vec();
}