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