virtio_spec/virtq/
alloc.rs

1use ::alloc::alloc::handle_alloc_error;
2#[cfg(feature = "nightly")]
3use ::alloc::{
4    alloc::{AllocError, Allocator, Global},
5    boxed::Box,
6};
7#[cfg(not(feature = "nightly"))]
8use allocator_api2::{
9    alloc::{AllocError, Allocator, Global},
10    boxed::Box,
11};
12
13use super::*;
14
15impl Avail {
16    pub fn new(queue_size: u16, has_event_idx: bool) -> Box<Self> {
17        Self::new_in(queue_size, has_event_idx, Global)
18    }
19
20    pub fn try_new(queue_size: u16, has_event_idx: bool) -> Result<Box<Self>, AllocError> {
21        Self::try_new_in(queue_size, has_event_idx, Global)
22    }
23
24    pub fn new_in<A: Allocator>(queue_size: u16, has_event_idx: bool, alloc: A) -> Box<Self, A> {
25        Self::try_new_in(queue_size, has_event_idx, alloc)
26            .unwrap_or_else(|_| handle_alloc_error(Self::layout(queue_size, has_event_idx)))
27    }
28
29    pub fn try_new_in<A: Allocator>(
30        queue_size: u16,
31        has_event_idx: bool,
32        alloc: A,
33    ) -> Result<Box<Self, A>, AllocError> {
34        let layout = Self::layout(queue_size, has_event_idx);
35
36        let mem = alloc.allocate_zeroed(layout)?;
37        let mem = NonNull::slice_from_raw_parts(mem.cast(), layout.size());
38        let raw = Self::from_ptr(mem).unwrap();
39        let boxed = unsafe { Box::from_raw_in(raw.as_ptr(), alloc) };
40
41        debug_assert_eq!(Layout::for_value(&*boxed), layout);
42        debug_assert_eq!(boxed.ring(has_event_idx).len(), queue_size.into());
43        debug_assert_eq!(boxed.used_event(has_event_idx).is_some(), has_event_idx);
44
45        Ok(boxed)
46    }
47}
48
49impl Used {
50    pub fn new(queue_size: u16, has_event_idx: bool) -> Box<Self> {
51        Self::new_in(queue_size, has_event_idx, Global)
52    }
53
54    pub fn try_new(queue_size: u16, has_event_idx: bool) -> Result<Box<Self>, AllocError> {
55        Self::try_new_in(queue_size, has_event_idx, Global)
56    }
57
58    pub fn new_in<A: Allocator>(queue_size: u16, has_event_idx: bool, alloc: A) -> Box<Self, A> {
59        Self::try_new_in(queue_size, has_event_idx, alloc)
60            .unwrap_or_else(|_| handle_alloc_error(Self::layout(queue_size, has_event_idx)))
61    }
62
63    pub fn try_new_in<A: Allocator>(
64        queue_size: u16,
65        has_event_idx: bool,
66        alloc: A,
67    ) -> Result<Box<Self, A>, AllocError> {
68        let layout = Self::layout(queue_size, has_event_idx);
69
70        let mem = alloc.allocate_zeroed(layout)?;
71        let mem = NonNull::slice_from_raw_parts(mem.cast(), layout.size());
72        let raw = Self::from_ptr(mem, has_event_idx).unwrap();
73        let boxed = unsafe { Box::from_raw_in(raw.as_ptr(), alloc) };
74
75        debug_assert_eq!(Layout::for_value(&*boxed), layout);
76        debug_assert_eq!(boxed.ring().len(), queue_size.into());
77        debug_assert_eq!(boxed.avail_event().is_some(), has_event_idx);
78
79        Ok(boxed)
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn avail_layout() {
89        for queue_size in [255, 256, 257] {
90            for has_event_idx in [false, true] {
91                Avail::new(queue_size, has_event_idx);
92            }
93        }
94    }
95
96    #[test]
97    fn used_layout() {
98        for queue_size in [255, 256, 257] {
99            for has_event_idx in [false, true] {
100                Used::new(queue_size, has_event_idx);
101            }
102        }
103    }
104}