facet_core/impls_core/option.rs
1use core::{alloc::Layout, mem::MaybeUninit};
2
3use crate::{
4 ConstTypeId, Def, Facet, OptionDef, OptionVTable, PtrConst, PtrUninit, Shape,
5 value_vtable_inner,
6};
7
8unsafe impl<T: Facet> Facet for Option<T> {
9 const SHAPE: &'static Shape = &const {
10 Shape::builder()
11 .id(ConstTypeId::of::<Self>())
12 .layout(Layout::new::<Self>())
13 .def(Def::Option(
14 OptionDef::builder()
15 .t(|| T::SHAPE)
16 .vtable(
17 const {
18 &OptionVTable::builder()
19 .is_some(|option| unsafe { option.get::<Option<T>>().is_some() })
20 .get_value(|option| unsafe {
21 option
22 .get::<Option<T>>()
23 .as_ref()
24 .map(|t| PtrConst::new(t as *const T))
25 })
26 .init_some(|option, value| unsafe {
27 option.put(Option::Some(value.read::<T>()))
28 })
29 .init_none(|option| unsafe { option.put(<Option<T>>::None) })
30 .replace_with(|option, value| unsafe {
31 let option = option.as_mut::<Option<T>>();
32 match value {
33 Some(value) => option.replace(value.read::<T>()),
34 None => option.take(),
35 };
36 })
37 .build()
38 },
39 )
40 .build(),
41 ))
42 .vtable(
43 &const {
44 let mut vtable = value_vtable_inner!(core::option::Option<T>, |f, opts| {
45 write!(f, "Option")?;
46 if let Some(opts) = opts.for_children() {
47 write!(f, "<")?;
48 (T::SHAPE.vtable.type_name)(f, opts)?;
49 write!(f, ">")?;
50 } else {
51 write!(f, "<…>")?;
52 }
53 Ok(())
54 });
55
56 if T::SHAPE.is_debug() {
57 vtable.debug = Some(|this, f| {
58 let this = unsafe { this.get::<Self>() };
59 if let Some(value) = &this {
60 write!(f, "Some(")?;
61 unsafe {
62 (T::SHAPE.vtable.debug.unwrap_unchecked())(
63 PtrConst::new(value),
64 f,
65 )?;
66 }
67 write!(f, ")")?;
68 } else {
69 write!(f, "None")?;
70 }
71 Ok(())
72 });
73 }
74
75 if T::SHAPE.is_from_str() {
76 vtable.parse = Some(|str, target| {
77 let mut t = MaybeUninit::<T>::uninit();
78 let parse = unsafe { T::SHAPE.vtable.parse.unwrap_unchecked() };
79 let _res = unsafe { (parse)(str, PtrUninit::new(t.as_mut_ptr()))? };
80 // res points to t so we can't drop it yet. the option is not initialized though
81 unsafe {
82 target.put(Some(t.assume_init()));
83 Ok(target.assume_init())
84 }
85 });
86 }
87
88 vtable
89 },
90 )
91 .build()
92 };
93}