facet_core/types/def/
option.rs

1use super::Shape;
2use crate::ptr::{PtrConst, PtrMut, PtrUninit};
3
4/// Describes an Option — including a vtable to query and alter its state,
5/// and the inner shape (the `T` in `Option<T>`).
6#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
7#[repr(C)]
8#[non_exhaustive]
9pub struct OptionDef<'shape> {
10    /// vtable for interacting with the option
11    pub vtable: &'shape OptionVTable,
12
13    /// shape of the inner type of the option
14    pub t: &'shape Shape<'shape>,
15}
16
17impl<'shape> OptionDef<'shape> {
18    /// Returns a builder for OptionDef
19    pub const fn builder() -> OptionDefBuilder<'shape> {
20        OptionDefBuilder::new()
21    }
22
23    /// Returns the inner type shape of the option
24    pub const fn t(&self) -> &'shape Shape<'shape> {
25        self.t
26    }
27}
28
29/// Builder for OptionDef
30pub struct OptionDefBuilder<'shape> {
31    vtable: Option<&'shape OptionVTable>,
32    t: Option<&'shape Shape<'shape>>,
33}
34
35impl<'shape> OptionDefBuilder<'shape> {
36    /// Creates a new OptionDefBuilder
37    #[allow(clippy::new_without_default)]
38    pub const fn new() -> Self {
39        Self {
40            vtable: None,
41            t: None,
42        }
43    }
44
45    /// Sets the vtable for the OptionDef
46    pub const fn vtable(mut self, vtable: &'shape OptionVTable) -> Self {
47        self.vtable = Some(vtable);
48        self
49    }
50
51    /// Sets the inner type shape for the OptionDef
52    pub const fn t(mut self, t: &'shape Shape<'shape>) -> Self {
53        self.t = Some(t);
54        self
55    }
56
57    /// Builds the OptionDef
58    pub const fn build(self) -> OptionDef<'shape> {
59        OptionDef {
60            vtable: self.vtable.unwrap(),
61            t: self.t.unwrap(),
62        }
63    }
64}
65
66/// Check if an option contains a value
67///
68/// # Safety
69///
70/// The `option` parameter must point to aligned, initialized memory of the correct type.
71pub type OptionIsSomeFn = for<'option> unsafe fn(option: PtrConst<'option>) -> bool;
72
73/// Get the value contained in an option, if present
74///
75/// # Safety
76///
77/// The `option` parameter must point to aligned, initialized memory of the correct type.
78pub type OptionGetValueFn =
79    for<'option> unsafe fn(option: PtrConst<'option>) -> Option<PtrConst<'option>>;
80
81/// Initialize an option with Some(value)
82///
83/// # Safety
84///
85/// The `option` parameter must point to uninitialized memory of sufficient size.
86/// The function must properly initialize the memory.
87/// `value` is moved out of (with [`core::ptr::read`]) — it should be deallocated afterwards (e.g.
88/// with [`core::mem::forget`]) but NOT dropped.
89pub type OptionInitSomeFn =
90    for<'option> unsafe fn(option: PtrUninit<'option>, value: PtrConst<'_>) -> PtrMut<'option>;
91
92/// Initialize an option with None
93///
94/// # Safety
95///
96/// The `option` parameter must point to uninitialized memory of sufficient size.
97/// The function must properly initialize the memory.
98pub type OptionInitNoneFn = unsafe fn(option: PtrUninit) -> PtrMut;
99
100/// Replace an existing option with a new value
101///
102/// # Safety
103///
104/// The `option` parameter must point to aligned, initialized memory of the correct type.
105/// The old value will be dropped.
106/// If replacing with Some, `value` is moved out of (with [`core::ptr::read`]) —
107/// it should be deallocated afterwards but NOT dropped.
108pub type OptionReplaceWithFn =
109    for<'option> unsafe fn(option: PtrMut<'option>, value: Option<PtrConst<'_>>);
110
111/// Virtual table for `Option<T>`
112#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
113#[non_exhaustive]
114#[repr(C)]
115pub struct OptionVTable {
116    /// cf. [`OptionIsSomeFn`]
117    pub is_some_fn: OptionIsSomeFn,
118
119    /// cf. [`OptionGetValueFn`]
120    pub get_value_fn: OptionGetValueFn,
121
122    /// cf. [`OptionInitSomeFn`]
123    pub init_some_fn: OptionInitSomeFn,
124
125    /// cf. [`OptionInitNoneFn`]
126    pub init_none_fn: OptionInitNoneFn,
127
128    /// cf. [`OptionReplaceWithFn`]
129    pub replace_with_fn: OptionReplaceWithFn,
130}
131
132impl OptionVTable {
133    /// Returns a builder for OptionVTable
134    pub const fn builder() -> OptionVTableBuilder {
135        OptionVTableBuilder::new()
136    }
137}
138
139/// Builds an [`OptionVTable`]
140pub struct OptionVTableBuilder {
141    is_some_fn: Option<OptionIsSomeFn>,
142    get_value_fn: Option<OptionGetValueFn>,
143    init_some_fn: Option<OptionInitSomeFn>,
144    init_none_fn: Option<OptionInitNoneFn>,
145    replace_with_fn: Option<OptionReplaceWithFn>,
146}
147
148impl OptionVTableBuilder {
149    /// Creates a new [`OptionVTableBuilder`] with all fields set to `None`.
150    #[allow(clippy::new_without_default)]
151    pub const fn new() -> Self {
152        Self {
153            is_some_fn: None,
154            get_value_fn: None,
155            init_some_fn: None,
156            init_none_fn: None,
157            replace_with_fn: None,
158        }
159    }
160
161    /// Sets the is_some_fn field
162    pub const fn is_some(mut self, f: OptionIsSomeFn) -> Self {
163        self.is_some_fn = Some(f);
164        self
165    }
166
167    /// Sets the get_value_fn field
168    pub const fn get_value(mut self, f: OptionGetValueFn) -> Self {
169        self.get_value_fn = Some(f);
170        self
171    }
172
173    /// Sets the init_some_fn field
174    pub const fn init_some(mut self, f: OptionInitSomeFn) -> Self {
175        self.init_some_fn = Some(f);
176        self
177    }
178
179    /// Sets the init_none_fn field
180    pub const fn init_none(mut self, f: OptionInitNoneFn) -> Self {
181        self.init_none_fn = Some(f);
182        self
183    }
184
185    /// Sets the replace_with_fn field
186    pub const fn replace_with(mut self, f: OptionReplaceWithFn) -> Self {
187        self.replace_with_fn = Some(f);
188        self
189    }
190
191    /// Builds the [`OptionVTable`] from the current state of the builder.
192    ///
193    /// # Panics
194    ///
195    /// This method will panic if any of the required fields are `None`.
196    pub const fn build(self) -> OptionVTable {
197        OptionVTable {
198            is_some_fn: self.is_some_fn.unwrap(),
199            get_value_fn: self.get_value_fn.unwrap(),
200            init_some_fn: self.init_some_fn.unwrap(),
201            init_none_fn: self.init_none_fn.unwrap(),
202            replace_with_fn: self.replace_with_fn.unwrap(),
203        }
204    }
205}