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 parse_bytes: None,
168 try_from: None,
169 try_into_inner: None,
170 try_borrow_inner: None,
171 partial_eq: Some(result_partial_eq),
172 partial_cmp: Some(result_partial_cmp),
173 cmp: Some(result_cmp),
174};
175
176static RESULT_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
178 drop_in_place: result_drop,
179 default_in_place: None,
180 clone_into: None,
181 is_truthy: None,
182};
183
184unsafe fn result_is_ok<T, E>(result: PtrConst) -> bool {
186 unsafe { result.get::<Result<T, E>>().is_ok() }
187}
188
189unsafe fn result_get_ok<T, E>(result: PtrConst) -> Option<PtrConst> {
191 unsafe {
192 result
193 .get::<Result<T, E>>()
194 .as_ref()
195 .ok()
196 .map(|t| PtrConst::new(t as *const T))
197 }
198}
199
200unsafe fn result_get_err<T, E>(result: PtrConst) -> Option<PtrConst> {
202 unsafe {
203 result
204 .get::<Result<T, E>>()
205 .as_ref()
206 .err()
207 .map(|e| PtrConst::new(e as *const E))
208 }
209}
210
211unsafe fn result_init_ok<T, E>(result: crate::PtrUninit, value: PtrConst) -> PtrMut {
213 unsafe { result.put(Result::<T, E>::Ok(value.read::<T>())) }
214}
215
216unsafe fn result_init_err<T, E>(result: crate::PtrUninit, value: PtrConst) -> PtrMut {
218 unsafe { result.put(Result::<T, E>::Err(value.read::<E>())) }
219}
220
221unsafe impl<'a, T: Facet<'a>, E: Facet<'a>> Facet<'a> for Result<T, E> {
222 const SHAPE: &'static Shape = &const {
223 const fn build_result_vtable<T, E>() -> ResultVTable {
224 ResultVTable::builder()
225 .is_ok(result_is_ok::<T, E>)
226 .get_ok(result_get_ok::<T, E>)
227 .get_err(result_get_err::<T, E>)
228 .init_ok(result_init_ok::<T, E>)
229 .init_err(result_init_err::<T, E>)
230 .build()
231 }
232
233 ShapeBuilder::for_sized::<Result<T, E>>("Result")
234 .ty(Type::User(UserType::Opaque))
235 .def(Def::Result(ResultDef::new(
236 &const { build_result_vtable::<T, E>() },
237 T::SHAPE,
238 E::SHAPE,
239 )))
240 .type_params(&[
241 TypeParam {
242 name: "T",
243 shape: T::SHAPE,
244 },
245 TypeParam {
246 name: "E",
247 shape: E::SHAPE,
248 },
249 ])
250 .vtable_indirect(&RESULT_VTABLE)
251 .type_ops_indirect(&RESULT_TYPE_OPS)
252 .build()
253 };
254}