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, 'shape, 'src, 'dst, T: Facet<'a>>(
13 src_ptr: PtrConst<'src>,
14 src_shape: &'shape Shape<'shape>,
15 dst: PtrUninit<'dst>,
16 ) -> Result<PtrMut<'dst>, TryFromError<'shape>> {
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 vtable.debug = || {
62 if T::SHAPE.is_debug() {
63 Some(|this, f| {
64 let this = unsafe { this.get::<Self>() };
65 if let Some(value) = &this {
66 write!(f, "Some(")?;
67 (<VTableView<T>>::of().debug().unwrap())(value, f)?;
68 write!(f, ")")?;
69 } else {
70 write!(f, "None")?;
71 }
72 Ok(())
73 })
74 } else {
75 None
76 }
77 };
78
79 vtable.parse = || {
80 if T::SHAPE.is_from_str() {
81 Some(|str, target| {
82 let mut t = MaybeUninit::<T>::uninit();
83 let parse = <VTableView<T>>::of().parse().unwrap();
84 let _res = (parse)(str, TypedPtrUninit::new(t.as_mut_ptr()))?;
85 unsafe {
87 target.put(Some(t.assume_init()));
88 Ok(target.assume_init())
89 }
90 })
91 } else {
92 None
93 }
94 };
95
96 vtable.try_from = || Some(try_from::<T>);
97 vtable.try_into_inner = || Some(try_into_inner::<T>);
98 vtable.try_borrow_inner = || Some(try_borrow_inner::<T>);
99
100 vtable
101 };
102
103 const SHAPE: &'static Shape<'static> = &const {
104 fn inner_shape<'a, T: Facet<'a>>() -> &'static Shape<'static> {
106 T::SHAPE
107 }
108
109 Shape::builder_for_sized::<Self>()
110 .type_identifier("Option")
111 .type_params(&[crate::TypeParam {
112 name: "T",
113 shape: || T::SHAPE,
114 }])
115 .ty(Type::User(
116 if core::mem::size_of::<T>() == core::mem::size_of::<Option<T>>()
121 && core::mem::size_of::<T>() <= core::mem::size_of::<usize>()
122 {
123 UserType::Enum(EnumType {
124 repr: Repr::default(),
125 enum_repr: EnumRepr::RustNPO,
126 variants: &const {
127 [
128 Variant::builder()
129 .name("None")
130 .discriminant(0)
131 .data(
132 StructType::builder()
133 .repr(Repr::default())
134 .kind(StructKind::Unit)
135 .build(),
136 )
137 .build(),
138 Variant::builder()
139 .name("Some")
140 .discriminant(0)
141 .data(
142 StructType::builder()
143 .repr(Repr::default())
144 .kind(StructKind::TupleStruct)
145 .fields(
146 &const {
147 [Field::builder()
148 .name("0")
149 .shape(T::SHAPE)
150 .offset(0)
151 .flags(FieldFlags::EMPTY)
152 .build()]
153 },
154 )
155 .build(),
156 )
157 .build(),
158 ]
159 },
160 })
161 } else {
162 UserType::Opaque
163 },
164 ))
165 .def(Def::Option(
166 OptionDef::builder()
167 .t(T::SHAPE)
168 .vtable(
169 const {
170 &OptionVTable::builder()
171 .is_some(|option| unsafe { option.get::<Option<T>>().is_some() })
172 .get_value(|option| unsafe {
173 option
174 .get::<Option<T>>()
175 .as_ref()
176 .map(|t| PtrConst::new(t as *const T))
177 })
178 .init_some(|option, value| unsafe {
179 option.put(Option::Some(value.read::<T>()))
180 })
181 .init_none(|option| unsafe { option.put(<Option<T>>::None) })
182 .replace_with(|option, value| unsafe {
183 let option = option.as_mut::<Option<T>>();
184 match value {
185 Some(value) => option.replace(value.read::<T>()),
186 None => option.take(),
187 };
188 })
189 .build()
190 },
191 )
192 .build(),
193 ))
194 .inner(inner_shape::<T>)
195 .build()
196 };
197}