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}