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