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}