1use core::cmp::Ordering;
4
5use crate::{
6 Def, Facet, HashProxy, OxPtrConst, OxPtrMut, OxRef, PtrConst, PtrMut, ResultDef, ResultVTable,
7 Shape, ShapeBuilder, Type, TypeOpsIndirect, TypeParam, UserType, VTableIndirect,
8};
9
10#[inline]
12fn get_result_def(shape: &'static Shape) -> Option<&'static ResultDef> {
13 match shape.def {
14 Def::Result(ref def) => Some(def),
15 _ => None,
16 }
17}
18
19unsafe fn result_debug(
21 ox: OxPtrConst,
22 f: &mut core::fmt::Formatter<'_>,
23) -> Option<core::fmt::Result> {
24 let shape = ox.shape();
25 let def = get_result_def(shape)?;
26 let ptr = ox.ptr();
27
28 if unsafe { (def.vtable.is_ok)(ptr) } {
29 let ok_ptr = unsafe { (def.vtable.get_ok)(ptr)? };
32 let ok_ox = unsafe { OxRef::new(ok_ptr, def.t) };
33 Some(f.debug_tuple("Ok").field(&ok_ox).finish())
34 } else {
35 let err_ptr = unsafe { (def.vtable.get_err)(ptr)? };
37 let err_ox = unsafe { OxRef::new(err_ptr, def.e) };
38 Some(f.debug_tuple("Err").field(&err_ox).finish())
39 }
40}
41
42unsafe fn result_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
44 let shape = ox.shape();
45 let def = get_result_def(shape)?;
46 let ptr = ox.ptr();
47
48 use core::hash::Hash;
49 if unsafe { (def.vtable.is_ok)(ptr) } {
50 0u8.hash(hasher);
51 let ok_ptr = unsafe { (def.vtable.get_ok)(ptr)? };
52 unsafe { def.t.call_hash(ok_ptr, hasher)? };
53 } else {
54 1u8.hash(hasher);
55 let err_ptr = unsafe { (def.vtable.get_err)(ptr)? };
56 unsafe { def.e.call_hash(err_ptr, hasher)? };
57 }
58 Some(())
59}
60
61unsafe fn result_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
63 let shape = a.shape();
64 let def = get_result_def(shape)?;
65
66 let a_ptr = a.ptr();
67 let b_ptr = b.ptr();
68 let a_is_ok = unsafe { (def.vtable.is_ok)(a_ptr) };
69 let b_is_ok = unsafe { (def.vtable.is_ok)(b_ptr) };
70
71 Some(match (a_is_ok, b_is_ok) {
72 (true, true) => {
73 let a_ok = unsafe { (def.vtable.get_ok)(a_ptr)? };
74 let b_ok = unsafe { (def.vtable.get_ok)(b_ptr)? };
75 unsafe { def.t.call_partial_eq(a_ok, b_ok)? }
76 }
77 (false, false) => {
78 let a_err = unsafe { (def.vtable.get_err)(a_ptr)? };
79 let b_err = unsafe { (def.vtable.get_err)(b_ptr)? };
80 unsafe { def.e.call_partial_eq(a_err, b_err)? }
81 }
82 _ => false,
83 })
84}
85
86unsafe fn result_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
88 let shape = a.shape();
89 let def = get_result_def(shape)?;
90
91 let a_ptr = a.ptr();
92 let b_ptr = b.ptr();
93 let a_is_ok = unsafe { (def.vtable.is_ok)(a_ptr) };
94 let b_is_ok = unsafe { (def.vtable.is_ok)(b_ptr) };
95
96 Some(match (a_is_ok, b_is_ok) {
97 (true, true) => {
98 let a_ok = unsafe { (def.vtable.get_ok)(a_ptr)? };
99 let b_ok = unsafe { (def.vtable.get_ok)(b_ptr)? };
100 unsafe { def.t.call_partial_cmp(a_ok, b_ok)? }
101 }
102 (false, false) => {
103 let a_err = unsafe { (def.vtable.get_err)(a_ptr)? };
104 let b_err = unsafe { (def.vtable.get_err)(b_ptr)? };
105 unsafe { def.e.call_partial_cmp(a_err, b_err)? }
106 }
107 (true, false) => Some(Ordering::Greater),
109 (false, true) => Some(Ordering::Less),
110 })
111}
112
113unsafe fn result_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
115 let shape = a.shape();
116 let def = get_result_def(shape)?;
117
118 let a_ptr = a.ptr();
119 let b_ptr = b.ptr();
120 let a_is_ok = unsafe { (def.vtable.is_ok)(a_ptr) };
121 let b_is_ok = unsafe { (def.vtable.is_ok)(b_ptr) };
122
123 Some(match (a_is_ok, b_is_ok) {
124 (true, true) => {
125 let a_ok = unsafe { (def.vtable.get_ok)(a_ptr)? };
126 let b_ok = unsafe { (def.vtable.get_ok)(b_ptr)? };
127 unsafe { def.t.call_cmp(a_ok, b_ok)? }
128 }
129 (false, false) => {
130 let a_err = unsafe { (def.vtable.get_err)(a_ptr)? };
131 let b_err = unsafe { (def.vtable.get_err)(b_ptr)? };
132 unsafe { def.e.call_cmp(a_err, b_err)? }
133 }
134 (true, false) => Ordering::Greater,
136 (false, true) => Ordering::Less,
137 })
138}
139
140unsafe fn result_drop(ox: OxPtrMut) {
142 let shape = ox.shape();
143 let Some(def) = get_result_def(shape) else {
144 return;
145 };
146 let ptr = ox.ptr();
147
148 if unsafe { (def.vtable.is_ok)(ptr.as_const()) } {
149 let Some(ok_ptr) = (unsafe { (def.vtable.get_ok)(ptr.as_const()) }) else {
150 return;
151 };
152 let ok_ptr_mut = PtrMut::new(ok_ptr.as_byte_ptr() as *mut u8);
153 unsafe { def.t.call_drop_in_place(ok_ptr_mut) };
154 } else {
155 let Some(err_ptr) = (unsafe { (def.vtable.get_err)(ptr.as_const()) }) else {
156 return;
157 };
158 let err_ptr_mut = PtrMut::new(err_ptr.as_byte_ptr() as *mut u8);
159 unsafe { def.e.call_drop_in_place(err_ptr_mut) };
160 }
161}
162
163const RESULT_VTABLE: VTableIndirect = VTableIndirect {
165 display: None,
166 debug: Some(result_debug),
167 hash: Some(result_hash),
168 invariants: None,
169 parse: None,
170 parse_bytes: None,
171 try_from: None,
172 try_into_inner: None,
173 try_borrow_inner: None,
174 partial_eq: Some(result_partial_eq),
175 partial_cmp: Some(result_partial_cmp),
176 cmp: Some(result_cmp),
177};
178
179static RESULT_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
181 drop_in_place: result_drop,
182 default_in_place: None,
183 clone_into: None,
184 is_truthy: None,
185};
186
187unsafe fn result_is_ok<T, E>(result: PtrConst) -> bool {
189 unsafe { result.get::<Result<T, E>>().is_ok() }
190}
191
192unsafe fn result_get_ok<T, E>(result: PtrConst) -> Option<PtrConst> {
194 unsafe {
195 result
196 .get::<Result<T, E>>()
197 .as_ref()
198 .ok()
199 .map(|t| PtrConst::new(t as *const T))
200 }
201}
202
203unsafe fn result_get_err<T, E>(result: PtrConst) -> Option<PtrConst> {
205 unsafe {
206 result
207 .get::<Result<T, E>>()
208 .as_ref()
209 .err()
210 .map(|e| PtrConst::new(e as *const E))
211 }
212}
213
214unsafe fn result_init_ok<T, E>(result: crate::PtrUninit, value: PtrConst) -> PtrMut {
216 unsafe { result.put(Result::<T, E>::Ok(value.read::<T>())) }
217}
218
219unsafe fn result_init_err<T, E>(result: crate::PtrUninit, value: PtrConst) -> PtrMut {
221 unsafe { result.put(Result::<T, E>::Err(value.read::<E>())) }
222}
223
224unsafe impl<'a, T: Facet<'a>, E: Facet<'a>> Facet<'a> for Result<T, E> {
225 const SHAPE: &'static Shape = &const {
226 const fn build_result_vtable<T, E>() -> ResultVTable {
227 ResultVTable::builder()
228 .is_ok(result_is_ok::<T, E>)
229 .get_ok(result_get_ok::<T, E>)
230 .get_err(result_get_err::<T, E>)
231 .init_ok(result_init_ok::<T, E>)
232 .init_err(result_init_err::<T, E>)
233 .build()
234 }
235
236 ShapeBuilder::for_sized::<Result<T, E>>("Result")
237 .ty(Type::User(UserType::Opaque))
238 .def(Def::Result(ResultDef::new(
239 &const { build_result_vtable::<T, E>() },
240 T::SHAPE,
241 E::SHAPE,
242 )))
243 .type_params(&[
244 TypeParam {
245 name: "T",
246 shape: T::SHAPE,
247 },
248 TypeParam {
249 name: "E",
250 shape: E::SHAPE,
251 },
252 ])
253 .vtable_indirect(&RESULT_VTABLE)
254 .type_ops_indirect(&RESULT_TYPE_OPS)
255 .build()
256 };
257}