facet_types/
list.rs

1use facet_opaque::{Opaque, OpaqueConst, OpaqueUninit};
2
3/// Initialize a list in place with a given capacity
4///
5/// # Safety
6///
7/// The `list` parameter must point to uninitialized memory of sufficient size.
8/// The function must properly initialize the memory.
9pub type ListInitInPlaceWithCapacityFn =
10    unsafe fn(list: OpaqueUninit, capacity: usize) -> Result<Opaque, ()>;
11
12/// Push an item to the list
13///
14/// # Safety
15///
16/// The `list` parameter must point to aligned, initialized memory of the correct type.
17/// `item` is moved out of (with [`core::ptr::read`]) — it should be deallocated
18/// afterwards but NOT dropped.
19pub type ListPushFn = unsafe fn(list: Opaque, item: Opaque);
20// FIXME: this forces allocating item separately, copying it, and then dropping it — it's not great.
21
22/// Get the number of items in the list
23///
24/// # Safety
25///
26/// The `list` parameter must point to aligned, initialized memory of the correct type.
27pub type ListLenFn = unsafe fn(list: OpaqueConst) -> usize;
28
29/// Get pointer to the item at the given index. Panics if out of bounds.
30///
31/// # Safety
32///
33/// The `list` parameter must point to aligned, initialized memory of the correct type.
34pub type ListGetItemPtrFn = unsafe fn(list: OpaqueConst, index: usize) -> OpaqueConst;
35
36/// Virtual table for a list-like type (like `Vec<T>`,
37/// but also `HashSet<T>`, etc.)
38#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
39#[non_exhaustive]
40pub struct ListVTable {
41    /// cf. [`ListInitInPlaceWithCapacityFn`]
42    pub init_in_place_with_capacity: ListInitInPlaceWithCapacityFn,
43
44    /// cf. [`ListPushFn`]
45    pub push: ListPushFn,
46
47    /// cf. [`ListLenFn`]
48    pub len: ListLenFn,
49
50    /// cf. [`ListGetItemPtrFn`]
51    pub get_item_ptr: ListGetItemPtrFn,
52}
53
54impl ListVTable {
55    /// Returns a builder for ListVTable
56    pub const fn builder() -> ListVTableBuilder {
57        ListVTableBuilder::new()
58    }
59}
60
61/// Builds a [`ListVTable`]
62pub struct ListVTableBuilder {
63    init_in_place_with_capacity: Option<ListInitInPlaceWithCapacityFn>,
64    push: Option<ListPushFn>,
65    len: Option<ListLenFn>,
66    get_item_ptr: Option<ListGetItemPtrFn>,
67}
68
69impl ListVTableBuilder {
70    /// Creates a new [`ListVTableBuilder`] with all fields set to `None`.
71    #[allow(clippy::new_without_default)]
72    pub const fn new() -> Self {
73        Self {
74            init_in_place_with_capacity: None,
75            push: None,
76            len: None,
77            get_item_ptr: None,
78        }
79    }
80
81    /// Sets the init_in_place_with_capacity field
82    pub const fn init_in_place_with_capacity(mut self, f: ListInitInPlaceWithCapacityFn) -> Self {
83        self.init_in_place_with_capacity = Some(f);
84        self
85    }
86
87    /// Sets the push field
88    pub const fn push(mut self, f: ListPushFn) -> Self {
89        self.push = Some(f);
90        self
91    }
92
93    /// Sets the len field
94    pub const fn len(mut self, f: ListLenFn) -> Self {
95        self.len = Some(f);
96        self
97    }
98
99    /// Sets the get_item_ptr field
100    pub const fn get_item_ptr(mut self, f: ListGetItemPtrFn) -> Self {
101        self.get_item_ptr = Some(f);
102        self
103    }
104
105    /// Builds the [`ListVTable`] from the current state of the builder.
106    ///
107    /// # Panics
108    ///
109    /// This method will panic if any of the required fields are `None`.
110    pub const fn build(self) -> ListVTable {
111        ListVTable {
112            init_in_place_with_capacity: self.init_in_place_with_capacity.unwrap(),
113            push: self.push.unwrap(),
114            len: self.len.unwrap(),
115            get_item_ptr: self.get_item_ptr.unwrap(),
116        }
117    }
118}