facet_reflect/poke/
list.rs

1use crate::PokeValueUninit;
2use facet_core::{ListDef, ListVTable, Opaque, OpaqueConst, OpaqueUninit, Shape};
3
4/// Allows initializing an uninitialized list
5pub struct PokeListUninit<'mem> {
6    data: OpaqueUninit<'mem>,
7    shape: &'static Shape,
8    def: ListDef,
9}
10
11impl<'mem> PokeListUninit<'mem> {
12    #[inline(always)]
13    /// Coerce back into a `PokeValue`
14    pub fn into_value(self) -> PokeValueUninit<'mem> {
15        unsafe { PokeValueUninit::new(self.data, self.shape) }
16    }
17
18    #[inline(always)]
19    /// Shape getter
20    pub fn shape(&self) -> &'static Shape {
21        self.shape
22    }
23    /// Creates a new uninitialized list write-proxy
24    ///
25    /// # Safety
26    ///
27    /// The data buffer must match the size and alignment of the shape.
28    pub(crate) unsafe fn new(
29        data: OpaqueUninit<'mem>,
30        shape: &'static Shape,
31        def: ListDef,
32    ) -> Self {
33        Self { data, shape, def }
34    }
35
36    /// Initializes the list with an optional size hint
37    pub fn init(self, size_hint: Option<usize>) -> Result<PokeList<'mem>, OpaqueUninit<'mem>> {
38        let res = if let Some(capacity) = size_hint {
39            let init_in_place_with_capacity = self.def.vtable.init_in_place_with_capacity;
40            unsafe { init_in_place_with_capacity(self.data, capacity) }
41        } else {
42            let pv = unsafe { PokeValueUninit::new(self.data, self.shape) };
43            pv.default_in_place().map_err(|_| ())
44        };
45        let data = res.map_err(|_| self.data)?;
46        Ok(unsafe { PokeList::new(data, self.shape, self.def) })
47    }
48}
49
50/// Allows poking a list (appending, etc.)
51pub struct PokeList<'mem> {
52    data: Opaque<'mem>,
53    #[allow(dead_code)]
54    shape: &'static Shape,
55    def: ListDef,
56}
57
58impl<'mem> PokeList<'mem> {
59    /// Creates a new list write-proxy
60    ///
61    /// # Safety
62    ///
63    /// The data buffer must match the size and alignment of the shape.
64    pub(crate) unsafe fn new(data: Opaque<'mem>, shape: &'static Shape, def: ListDef) -> Self {
65        Self { data, shape, def }
66    }
67
68    #[inline(always)]
69    /// Shape getter
70    pub fn shape(&self) -> &'static Shape {
71        self.shape
72    }
73
74    /// Gets the vtable for the list
75    #[inline(always)]
76    fn list_vtable(&self) -> &'static ListVTable {
77        self.def.vtable
78    }
79
80    /// Pushes an item to the list
81    ///
82    /// # Safety
83    ///
84    /// `item` is moved out of (with [`core::ptr::read`]) — it should be deallocated
85    /// afterwards but NOT dropped.
86    pub unsafe fn push(&mut self, item: Opaque<'_>) {
87        unsafe { (self.list_vtable().push)(self.data, item) }
88    }
89
90    /// Gets the number of items in the list
91    pub fn len(&self) -> usize {
92        unsafe { (self.list_vtable().len)(self.data.as_const()) }
93    }
94
95    /// Returns true if the list is empty
96    pub fn is_empty(&self) -> bool {
97        self.len() == 0
98    }
99
100    /// Gets a pointer to the item at the given index
101    ///
102    /// # Panics
103    ///
104    /// Panics if the index is out of bounds.
105    pub fn get_item_ptr(&self, index: usize) -> OpaqueConst {
106        unsafe { (self.list_vtable().get_item_ptr)(self.data.as_const(), index) }
107    }
108
109    /// Takes ownership of this `PokeList` and returns the underlying data.
110    pub fn build_in_place(self) -> Opaque<'mem> {
111        self.data
112    }
113
114    /// Gets the def for that list
115    pub fn def(&self) -> &ListDef {
116        &self.def
117    }
118}