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