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, Variance,
8 VarianceDep, VarianceDesc,
9};
10
11#[inline]
13const fn get_result_def(shape: &'static Shape) -> Option<&'static ResultDef> {
14 match shape.def {
15 Def::Result(ref def) => Some(def),
16 _ => None,
17 }
18}
19
20#[inline]
21unsafe fn result_get_ok_ptr(def: &ResultDef, ptr: PtrConst) -> Option<PtrConst> {
22 let raw = unsafe { (def.vtable.get_ok)(ptr) };
23 if raw.is_null() {
24 None
25 } else {
26 Some(PtrConst::new_sized(raw))
27 }
28}
29
30#[inline]
31unsafe fn result_get_err_ptr(def: &ResultDef, ptr: PtrConst) -> Option<PtrConst> {
32 let raw = unsafe { (def.vtable.get_err)(ptr) };
33 if raw.is_null() {
34 None
35 } else {
36 Some(PtrConst::new_sized(raw))
37 }
38}
39
40fn result_type_name(
41 shape: &'static Shape,
42 f: &mut core::fmt::Formatter<'_>,
43 opts: crate::TypeNameOpts,
44) -> core::fmt::Result {
45 write!(f, "Result")?;
46 if let Some(opts) = opts.for_children() {
47 write!(f, "<")?;
48 if let Some(t) = shape.type_params.first() {
49 t.shape.write_type_name(f, opts)?;
50 }
51 if let Some(e) = shape.type_params.get(1) {
52 write!(f, ", ")?;
53 e.shape.write_type_name(f, opts)?;
54 }
55 write!(f, ">")?;
56 } else {
57 write!(f, "<…>")?;
58 }
59 Ok(())
60}
61
62unsafe fn result_debug(
64 ox: OxPtrConst,
65 f: &mut core::fmt::Formatter<'_>,
66) -> Option<core::fmt::Result> {
67 let shape = ox.shape();
68 let def = get_result_def(shape)?;
69 let ptr = ox.ptr();
70
71 if unsafe { (def.vtable.is_ok)(ptr) } {
72 let ok_ptr = unsafe { result_get_ok_ptr(def, ptr)? };
75 let ok_ox = unsafe { OxRef::new(ok_ptr, def.t) };
76 Some(f.debug_tuple("Ok").field(&ok_ox).finish())
77 } else {
78 let err_ptr = unsafe { result_get_err_ptr(def, ptr)? };
80 let err_ox = unsafe { OxRef::new(err_ptr, def.e) };
81 Some(f.debug_tuple("Err").field(&err_ox).finish())
82 }
83}
84
85unsafe fn result_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
87 let shape = ox.shape();
88 let def = get_result_def(shape)?;
89 let ptr = ox.ptr();
90
91 use core::hash::Hash;
92 if unsafe { (def.vtable.is_ok)(ptr) } {
93 0u8.hash(hasher);
94 let ok_ptr = unsafe { result_get_ok_ptr(def, ptr)? };
95 unsafe { def.t.call_hash(ok_ptr, hasher)? };
96 } else {
97 1u8.hash(hasher);
98 let err_ptr = unsafe { result_get_err_ptr(def, ptr)? };
99 unsafe { def.e.call_hash(err_ptr, hasher)? };
100 }
101 Some(())
102}
103
104unsafe fn result_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
106 let shape = a.shape();
107 let def = get_result_def(shape)?;
108
109 let a_ptr = a.ptr();
110 let b_ptr = b.ptr();
111 let a_is_ok = unsafe { (def.vtable.is_ok)(a_ptr) };
112 let b_is_ok = unsafe { (def.vtable.is_ok)(b_ptr) };
113
114 Some(match (a_is_ok, b_is_ok) {
115 (true, true) => {
116 let a_ok = unsafe { result_get_ok_ptr(def, a_ptr)? };
117 let b_ok = unsafe { result_get_ok_ptr(def, b_ptr)? };
118 unsafe { def.t.call_partial_eq(a_ok, b_ok)? }
119 }
120 (false, false) => {
121 let a_err = unsafe { result_get_err_ptr(def, a_ptr)? };
122 let b_err = unsafe { result_get_err_ptr(def, b_ptr)? };
123 unsafe { def.e.call_partial_eq(a_err, b_err)? }
124 }
125 _ => false,
126 })
127}
128
129unsafe fn result_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
131 let shape = a.shape();
132 let def = get_result_def(shape)?;
133
134 let a_ptr = a.ptr();
135 let b_ptr = b.ptr();
136 let a_is_ok = unsafe { (def.vtable.is_ok)(a_ptr) };
137 let b_is_ok = unsafe { (def.vtable.is_ok)(b_ptr) };
138
139 Some(match (a_is_ok, b_is_ok) {
140 (true, true) => {
141 let a_ok = unsafe { result_get_ok_ptr(def, a_ptr)? };
142 let b_ok = unsafe { result_get_ok_ptr(def, b_ptr)? };
143 unsafe { def.t.call_partial_cmp(a_ok, b_ok)? }
144 }
145 (false, false) => {
146 let a_err = unsafe { result_get_err_ptr(def, a_ptr)? };
147 let b_err = unsafe { result_get_err_ptr(def, b_ptr)? };
148 unsafe { def.e.call_partial_cmp(a_err, b_err)? }
149 }
150 (true, false) => Some(Ordering::Greater),
152 (false, true) => Some(Ordering::Less),
153 })
154}
155
156unsafe fn result_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
158 let shape = a.shape();
159 let def = get_result_def(shape)?;
160
161 let a_ptr = a.ptr();
162 let b_ptr = b.ptr();
163 let a_is_ok = unsafe { (def.vtable.is_ok)(a_ptr) };
164 let b_is_ok = unsafe { (def.vtable.is_ok)(b_ptr) };
165
166 Some(match (a_is_ok, b_is_ok) {
167 (true, true) => {
168 let a_ok = unsafe { result_get_ok_ptr(def, a_ptr)? };
169 let b_ok = unsafe { result_get_ok_ptr(def, b_ptr)? };
170 unsafe { def.t.call_cmp(a_ok, b_ok)? }
171 }
172 (false, false) => {
173 let a_err = unsafe { result_get_err_ptr(def, a_ptr)? };
174 let b_err = unsafe { result_get_err_ptr(def, b_ptr)? };
175 unsafe { def.e.call_cmp(a_err, b_err)? }
176 }
177 (true, false) => Ordering::Greater,
179 (false, true) => Ordering::Less,
180 })
181}
182
183unsafe fn result_drop<T, E>(ox: OxPtrMut) {
191 unsafe { core::ptr::drop_in_place(ox.as_mut::<Result<T, E>>()) };
192}
193
194const RESULT_VTABLE: VTableIndirect = VTableIndirect {
196 display: None,
197 debug: Some(result_debug),
198 hash: Some(result_hash),
199 invariants: None,
200 parse: None,
201 parse_bytes: None,
202 try_from: None,
203 try_into_inner: None,
204 try_borrow_inner: None,
205 partial_eq: Some(result_partial_eq),
206 partial_cmp: Some(result_partial_cmp),
207 cmp: Some(result_cmp),
208};
209
210unsafe extern "C" fn result_is_ok<T, E>(result: PtrConst) -> bool {
212 unsafe { result.get::<Result<T, E>>().is_ok() }
213}
214
215unsafe extern "C" fn result_get_ok<T, E>(result: PtrConst) -> *const u8 {
217 unsafe {
218 result
219 .get::<Result<T, E>>()
220 .as_ref()
221 .ok()
222 .map_or(core::ptr::null(), |t| t as *const T as *const u8)
223 }
224}
225
226unsafe extern "C" fn result_get_err<T, E>(result: PtrConst) -> *const u8 {
228 unsafe {
229 result
230 .get::<Result<T, E>>()
231 .as_ref()
232 .err()
233 .map_or(core::ptr::null(), |e| e as *const E as *const u8)
234 }
235}
236
237unsafe extern "C" fn result_init_ok<T, E>(result: crate::PtrUninit, value: PtrMut) -> PtrMut {
239 unsafe { result.put(Result::<T, E>::Ok(value.read::<T>())) }
240}
241
242unsafe extern "C" fn result_init_err<T, E>(result: crate::PtrUninit, value: PtrMut) -> PtrMut {
244 unsafe { result.put(Result::<T, E>::Err(value.read::<E>())) }
245}
246
247unsafe impl<'a, T: Facet<'a>, E: Facet<'a>> Facet<'a> for Result<T, E> {
248 const SHAPE: &'static Shape = &const {
249 const fn build_result_vtable<T, E>() -> ResultVTable {
250 ResultVTable::builder()
251 .is_ok(result_is_ok::<T, E>)
252 .get_ok(result_get_ok::<T, E>)
253 .get_err(result_get_err::<T, E>)
254 .init_ok(result_init_ok::<T, E>)
255 .init_err(result_init_err::<T, E>)
256 .build()
257 }
258
259 const fn build_type_ops<T, E>() -> TypeOpsIndirect {
260 TypeOpsIndirect {
261 drop_in_place: result_drop::<T, E>,
262 default_in_place: None,
263 clone_into: None,
264 is_truthy: None,
265 }
266 }
267
268 ShapeBuilder::for_sized::<Result<T, E>>("Result")
269 .module_path("core::result")
270 .type_name(result_type_name)
271 .ty(Type::User(UserType::Opaque))
272 .def(Def::Result(ResultDef::new(
273 &const { build_result_vtable::<T, E>() },
274 T::SHAPE,
275 E::SHAPE,
276 )))
277 .type_params(&[
278 TypeParam {
279 name: "T",
280 shape: T::SHAPE,
281 },
282 TypeParam {
283 name: "E",
284 shape: E::SHAPE,
285 },
286 ])
287 .variance(VarianceDesc {
289 base: Variance::Bivariant,
290 deps: &const {
291 [
292 VarianceDep::covariant(T::SHAPE),
293 VarianceDep::covariant(E::SHAPE),
294 ]
295 },
296 })
297 .vtable_indirect(&RESULT_VTABLE)
298 .type_ops_indirect(&const { build_type_ops::<T, E>() })
299 .build()
300 };
301}