facet_core/impls_core/
option.rs

1use core::mem::MaybeUninit;
2
3use crate::{
4    Def, Facet, OptionDef, OptionVTable, PtrConst, PtrMut, PtrUninit, Shape, TryBorrowInnerError,
5    TryFromError, TryIntoInnerError, TypedPtrUninit, VTableView, value_vtable,
6};
7unsafe impl<'a, T: Facet<'a>> Facet<'a> for Option<T> {
8    const SHAPE: &'static Shape = &const {
9        // Define the functions for transparent conversion between Option<T> and T
10        unsafe fn try_from<'a, 'src, 'dst, T: Facet<'a>>(
11            src_ptr: PtrConst<'src>,
12            src_shape: &'static Shape,
13            dst: PtrUninit<'dst>,
14        ) -> Result<PtrMut<'dst>, TryFromError> {
15            if src_shape.id != T::SHAPE.id {
16                return Err(TryFromError::UnsupportedSourceShape {
17                    src_shape,
18                    expected: &[T::SHAPE],
19                });
20            }
21            let t = unsafe { src_ptr.read::<T>() };
22            let option = Some(t);
23            Ok(unsafe { dst.put(option) })
24        }
25
26        unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
27            src_ptr: PtrConst<'src>,
28            dst: PtrUninit<'dst>,
29        ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
30            let option = unsafe { src_ptr.read::<Option<T>>() };
31            match option {
32                Some(t) => Ok(unsafe { dst.put(t) }),
33                None => Err(TryIntoInnerError::Unavailable),
34            }
35        }
36
37        unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
38            src_ptr: PtrConst<'src>,
39        ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
40            let option = unsafe { src_ptr.get::<Option<T>>() };
41            match option {
42                Some(t) => Ok(PtrConst::new(t)),
43                None => Err(TryBorrowInnerError::Unavailable),
44            }
45        }
46
47        // Function to return inner type's shape
48        fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
49            T::SHAPE
50        }
51
52        Shape::builder_for_sized::<Self>()
53            .type_params(&[crate::TypeParam {
54                name: "T",
55                shape: || T::SHAPE,
56            }])
57            .def(Def::Option(
58                OptionDef::builder()
59                    .t(|| T::SHAPE)
60                    .vtable(
61                        const {
62                            &OptionVTable::builder()
63                                .is_some(|option| unsafe { option.get::<Option<T>>().is_some() })
64                                .get_value(|option| unsafe {
65                                    option
66                                        .get::<Option<T>>()
67                                        .as_ref()
68                                        .map(|t| PtrConst::new(t as *const T))
69                                })
70                                .init_some(|option, value| unsafe {
71                                    option.put(Option::Some(value.read::<T>()))
72                                })
73                                .init_none(|option| unsafe { option.put(<Option<T>>::None) })
74                                .replace_with(|option, value| unsafe {
75                                    let option = option.as_mut::<Option<T>>();
76                                    match value {
77                                        Some(value) => option.replace(value.read::<T>()),
78                                        None => option.take(),
79                                    };
80                                })
81                                .build()
82                        },
83                    )
84                    .build(),
85            ))
86            .vtable(
87                &const {
88                    let mut vtable = value_vtable!(core::option::Option<T>, |f, opts| {
89                        write!(f, "Option")?;
90                        if let Some(opts) = opts.for_children() {
91                            write!(f, "<")?;
92                            (T::SHAPE.vtable.type_name)(f, opts)?;
93                            write!(f, ">")?;
94                        } else {
95                            write!(f, "<…>")?;
96                        }
97                        Ok(())
98                    });
99
100                    if T::SHAPE.is_debug() {
101                        vtable.debug = Some(|this, f| {
102                            let this = unsafe { this.get::<Self>() };
103                            if let Some(value) = &this {
104                                write!(f, "Some(")?;
105                                (<VTableView<T>>::of().debug().unwrap())(value, f)?;
106                                write!(f, ")")?;
107                            } else {
108                                write!(f, "None")?;
109                            }
110                            Ok(())
111                        });
112                    }
113
114                    if T::SHAPE.is_from_str() {
115                        vtable.parse = Some(|str, target| {
116                            let mut t = MaybeUninit::<T>::uninit();
117                            let parse = <VTableView<T>>::of().parse().unwrap();
118                            let _res = (parse)(str, TypedPtrUninit::new(t.as_mut_ptr()))?;
119                            // res points to t so we can't drop it yet. the option is not initialized though
120                            unsafe {
121                                target.put(Some(t.assume_init()));
122                                Ok(target.assume_init())
123                            }
124                        });
125                    }
126
127                    vtable.try_from = Some(try_from::<T>);
128                    vtable.try_into_inner = Some(try_into_inner::<T>);
129                    vtable.try_borrow_inner = Some(try_borrow_inner::<T>);
130
131                    vtable
132                },
133            )
134            .inner(inner_shape::<T>)
135            .build()
136    };
137}