facet_core/types/
list.rs

1use crate::ptr::{PtrConst, PtrMut, PtrUninit};
2
3use super::Shape;
4
5/// Fields for list types
6#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
7#[repr(C)]
8#[non_exhaustive]
9pub struct ListDef {
10    /// vtable for interacting with the list
11    pub vtable: &'static ListVTable,
12    /// shape of the items in the list
13    pub t: fn() -> &'static Shape,
14}
15
16impl ListDef {
17    /// Returns a builder for ListDef
18    pub const fn builder() -> ListDefBuilder {
19        ListDefBuilder::new()
20    }
21
22    /// Returns the shape of the items in the list
23    pub fn t(&self) -> &'static Shape {
24        (self.t)()
25    }
26}
27
28/// Builder for ListDef
29pub struct ListDefBuilder {
30    vtable: Option<&'static ListVTable>,
31    t: Option<fn() -> &'static Shape>,
32}
33
34impl ListDefBuilder {
35    /// Creates a new ListDefBuilder
36    #[allow(clippy::new_without_default)]
37    pub const fn new() -> Self {
38        Self {
39            vtable: None,
40            t: None,
41        }
42    }
43
44    /// Sets the vtable for the ListDef
45    pub const fn vtable(mut self, vtable: &'static ListVTable) -> Self {
46        self.vtable = Some(vtable);
47        self
48    }
49
50    /// Sets the item shape for the ListDef
51    pub const fn t(mut self, t: fn() -> &'static Shape) -> Self {
52        self.t = Some(t);
53        self
54    }
55
56    /// Builds the ListDef
57    pub const fn build(self) -> ListDef {
58        ListDef {
59            vtable: self.vtable.unwrap(),
60            t: self.t.unwrap(),
61        }
62    }
63}
64
65/// Initialize a list in place with a given capacity
66///
67/// # Safety
68///
69/// The `list` parameter must point to uninitialized memory of sufficient size.
70/// The function must properly initialize the memory.
71pub type ListInitInPlaceWithCapacityFn =
72    for<'mem> unsafe fn(list: PtrUninit<'mem>, capacity: usize) -> PtrMut<'mem>;
73
74/// Push an item to the list
75///
76/// # Safety
77///
78/// The `list` parameter must point to aligned, initialized memory of the correct type.
79/// `item` is moved out of (with [`core::ptr::read`]) — it should be deallocated
80/// afterwards but NOT dropped.
81pub type ListPushFn = unsafe fn(list: PtrMut, item: PtrMut);
82// FIXME: this forces allocating item separately, copying it, and then dropping it — it's not great.
83
84/// Get the number of items in the list
85///
86/// # Safety
87///
88/// The `list` parameter must point to aligned, initialized memory of the correct type.
89pub type ListLenFn = unsafe fn(list: PtrConst) -> usize;
90
91/// Get pointer to the item at the given index. Panics if out of bounds.
92///
93/// # Safety
94///
95/// The `list` parameter must point to aligned, initialized memory of the correct type.
96pub type ListGetItemPtrFn = unsafe fn(list: PtrConst, index: usize) -> PtrConst;
97
98/// Virtual table for a list-like type (like `Vec<T>`,
99/// but also `HashSet<T>`, etc.)
100#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
101#[repr(C)]
102#[non_exhaustive]
103pub struct ListVTable {
104    /// cf. [`ListInitInPlaceWithCapacityFn`].
105    /// Unbuildable lists exist, like arrays.
106    pub init_in_place_with_capacity: Option<ListInitInPlaceWithCapacityFn>,
107
108    /// cf. [`ListPushFn`]
109    pub push: ListPushFn,
110
111    /// cf. [`ListLenFn`]
112    pub len: ListLenFn,
113
114    /// cf. [`ListGetItemPtrFn`]
115    pub get_item_ptr: ListGetItemPtrFn,
116}
117
118impl ListVTable {
119    /// Returns a builder for ListVTable
120    pub const fn builder() -> ListVTableBuilder {
121        ListVTableBuilder::new()
122    }
123}
124
125/// Builds a [`ListVTable`]
126pub struct ListVTableBuilder {
127    init_in_place_with_capacity: Option<ListInitInPlaceWithCapacityFn>,
128    push: Option<ListPushFn>,
129    len: Option<ListLenFn>,
130    get_item_ptr: Option<ListGetItemPtrFn>,
131}
132
133impl ListVTableBuilder {
134    /// Creates a new [`ListVTableBuilder`] with all fields set to `None`.
135    #[allow(clippy::new_without_default)]
136    pub const fn new() -> Self {
137        Self {
138            init_in_place_with_capacity: None,
139            push: None,
140            len: None,
141            get_item_ptr: None,
142        }
143    }
144
145    /// Sets the init_in_place_with_capacity field
146    pub const fn init_in_place_with_capacity(mut self, f: ListInitInPlaceWithCapacityFn) -> Self {
147        self.init_in_place_with_capacity = Some(f);
148        self
149    }
150
151    /// Sets the push field
152    pub const fn push(mut self, f: ListPushFn) -> Self {
153        self.push = Some(f);
154        self
155    }
156
157    /// Sets the len field
158    pub const fn len(mut self, f: ListLenFn) -> Self {
159        self.len = Some(f);
160        self
161    }
162
163    /// Sets the get_item_ptr field
164    pub const fn get_item_ptr(mut self, f: ListGetItemPtrFn) -> Self {
165        self.get_item_ptr = Some(f);
166        self
167    }
168
169    /// Builds the [`ListVTable`] from the current state of the builder.
170    ///
171    /// # Panics
172    ///
173    /// This method will panic if any of the required fields are `None`.
174    pub const fn build(self) -> ListVTable {
175        ListVTable {
176            init_in_place_with_capacity: self.init_in_place_with_capacity,
177            push: self.push.unwrap(),
178            len: self.len.unwrap(),
179            get_item_ptr: self.get_item_ptr.unwrap(),
180        }
181    }
182}