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