facet_core/impls_core/
option.rs1use core::mem::MaybeUninit;
2
3use crate::{
4 Def, EnumRepr, EnumType, Facet, Field, FieldFlags, OptionDef, OptionVTable, PtrConst, PtrMut,
5 PtrUninit, Repr, Shape, StructKind, StructType, TryBorrowInnerError, TryFromError,
6 TryIntoInnerError, Type, TypedPtrUninit, UserType, VTableView, ValueVTable, Variant,
7 value_vtable,
8};
9unsafe impl<'a, T: Facet<'a>> Facet<'a> for Option<T> {
10 const VTABLE: &'static ValueVTable = &const {
11 unsafe fn try_from<'a, 'src, 'dst, T: Facet<'a>>(
13 src_ptr: PtrConst<'src>,
14 src_shape: &'static Shape,
15 dst: PtrUninit<'dst>,
16 ) -> Result<PtrMut<'dst>, TryFromError> {
17 if src_shape.id != T::SHAPE.id {
18 return Err(TryFromError::UnsupportedSourceShape {
19 src_shape,
20 expected: &[T::SHAPE],
21 });
22 }
23 let t = unsafe { src_ptr.read::<T>() };
24 let option = Some(t);
25 Ok(unsafe { dst.put(option) })
26 }
27
28 unsafe fn try_into_inner<'a, 'src, 'dst, T: Facet<'a>>(
29 src_ptr: PtrMut<'src>,
30 dst: PtrUninit<'dst>,
31 ) -> Result<PtrMut<'dst>, TryIntoInnerError> {
32 let option = unsafe { src_ptr.read::<Option<T>>() };
33 match option {
34 Some(t) => Ok(unsafe { dst.put(t) }),
35 None => Err(TryIntoInnerError::Unavailable),
36 }
37 }
38
39 unsafe fn try_borrow_inner<'a, 'src, T: Facet<'a>>(
40 src_ptr: PtrConst<'src>,
41 ) -> Result<PtrConst<'src>, TryBorrowInnerError> {
42 let option = unsafe { src_ptr.get::<Option<T>>() };
43 match option {
44 Some(t) => Ok(PtrConst::new(t)),
45 None => Err(TryBorrowInnerError::Unavailable),
46 }
47 }
48
49 let mut vtable = value_vtable!(core::option::Option<T>, |f, opts| {
50 write!(f, "{}", Self::SHAPE.type_identifier)?;
51 if let Some(opts) = opts.for_children() {
52 write!(f, "<")?;
53 (T::SHAPE.vtable.type_name())(f, opts)?;
54 write!(f, ">")?;
55 } else {
56 write!(f, "<…>")?;
57 }
58 Ok(())
59 });
60
61 {
62 let vtable_sized = vtable.sized_mut().unwrap();
63 vtable_sized.debug = || {
64 if T::SHAPE.is_debug() {
65 Some(|this, f| {
66 let this = unsafe { this.get::<Self>() };
67 if let Some(value) = &this {
68 write!(f, "Some(")?;
69 (<VTableView<T>>::of().debug().unwrap())(value, f)?;
70 write!(f, ")")?;
71 } else {
72 write!(f, "None")?;
73 }
74 Ok(())
75 })
76 } else {
77 None
78 }
79 };
80
81 vtable_sized.parse = || {
82 if T::SHAPE.is_from_str() {
83 Some(|str, target| {
84 let mut t = MaybeUninit::<T>::uninit();
85 let parse = <VTableView<T>>::of().parse().unwrap();
86 let _res = (parse)(str, TypedPtrUninit::new(t.as_mut_ptr()))?;
87 unsafe {
89 target.put(Some(t.assume_init()));
90 Ok(target.assume_init())
91 }
92 })
93 } else {
94 None
95 }
96 };
97
98 vtable_sized.try_from = || Some(try_from::<T>);
99 vtable_sized.try_into_inner = || Some(try_into_inner::<T>);
100 vtable_sized.try_borrow_inner = || Some(try_borrow_inner::<T>);
101 }
102
103 vtable
104 };
105
106 const SHAPE: &'static Shape = &const {
107 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape {
109 T::SHAPE
110 }
111
112 Shape::builder_for_sized::<Self>()
113 .type_identifier("Option")
114 .type_params(&[crate::TypeParam {
115 name: "T",
116 shape: || T::SHAPE,
117 }])
118 .ty(Type::User(
119 if core::mem::size_of::<T>() == core::mem::size_of::<Option<T>>()
124 && core::mem::size_of::<T>() <= core::mem::size_of::<usize>()
125 {
126 UserType::Enum(EnumType {
127 repr: Repr::default(),
128 enum_repr: EnumRepr::RustNPO,
129 variants: &const {
130 [
131 Variant::builder()
132 .name("None")
133 .discriminant(0)
134 .data(
135 StructType::builder()
136 .repr(Repr::default())
137 .kind(StructKind::Unit)
138 .build(),
139 )
140 .build(),
141 Variant::builder()
142 .name("Some")
143 .discriminant(0)
144 .data(
145 StructType::builder()
146 .repr(Repr::default())
147 .kind(StructKind::TupleStruct)
148 .fields(
149 &const {
150 [Field::builder()
151 .name("0")
152 .shape(T::SHAPE)
153 .offset(0)
154 .flags(FieldFlags::EMPTY)
155 .build()]
156 },
157 )
158 .build(),
159 )
160 .build(),
161 ]
162 },
163 })
164 } else {
165 UserType::Opaque
166 },
167 ))
168 .def(Def::Option(
169 OptionDef::builder()
170 .t(T::SHAPE)
171 .vtable(
172 const {
173 &OptionVTable::builder()
174 .is_some(|option| unsafe { option.get::<Option<T>>().is_some() })
175 .get_value(|option| unsafe {
176 option
177 .get::<Option<T>>()
178 .as_ref()
179 .map(|t| PtrConst::new(t as *const T))
180 })
181 .init_some(|option, value| unsafe {
182 option.put(Option::Some(value.read::<T>()))
183 })
184 .init_none(|option| unsafe { option.put(<Option<T>>::None) })
185 .replace_with(|option, value| unsafe {
186 let option = option.as_mut::<Option<T>>();
187 match value {
188 Some(value) => option.replace(value.read::<T>()),
189 None => option.take(),
190 };
191 })
192 .build()
193 },
194 )
195 .build(),
196 ))
197 .inner(inner_shape::<T>)
198 .build()
199 };
200}