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