stabby_abi/
result.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   Pierre Avital, <pierre.avital@me.com>
13//
14
15//! Stable results!
16
17use stabby_macros::tyeval;
18
19pub use crate::enums::IDeterminant;
20use crate::enums::IDeterminantProvider;
21use crate::istable::IBitMask;
22use crate::report::FieldReport;
23use crate::str::Str;
24use crate::unsigned::IUnsignedBase;
25use crate::{self as stabby, unreachable_unchecked, Bit, IStable, B0};
26use crate::{Alignment, Tuple, Unsigned};
27
28#[repr(transparent)]
29/// An ABI-stable, niche optimizing equivalent of [`core::result::Result`]
30pub struct Result<Ok, Err>
31where
32    Ok: IDeterminantProvider<Err>,
33    Err: IStable,
34{
35    storage: Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
36}
37impl<Ok: Unpin, Err: Unpin> Unpin for Result<Ok, Err>
38where
39    Ok: IDeterminantProvider<Err>,
40    Err: IStable,
41{
42}
43type Determinant<Ok, Err> = <Ok as IDeterminantProvider<Err>>::Determinant;
44// SAFETY: See fields
45unsafe impl<Ok, Err> IStable for Result<Ok, Err>
46where
47    Ok: IDeterminantProvider<Err>,
48    Err: IStable,
49{
50    /// The size is the max of the variants' sizes, plus the size of the determinant upgraded to a multiple of the alignment.
51    type Size = tyeval!(<<Determinant<Ok, Err> as IStable>::Size as Unsigned>::NextMultipleOf<Self::Align> + <Ok::Size as Unsigned>::Max<Err::Size>);
52    /// The alignment is the max of the variants' alignments.
53    type Align = <Ok::Align as Alignment>::Max<Err::Align>;
54    // If either variant may contain an indirection, so may their sum-type.
55    type ContainsIndirections = <Ok::ContainsIndirections as Bit>::Or<Err::ContainsIndirections>;
56    // We trust the DeterminantProvider with this computation, it usually just discards the values for safety.
57    type ForbiddenValues =
58        <<Ok as IDeterminantProvider<Err>>::NicheExporter as IStable>::ForbiddenValues;
59    // OH NO! But we have lots of testing.
60    type UnusedBits = <<Tuple<Determinant<Ok, Err>, <Self::Align as Alignment>::AsUint> as IStable>::UnusedBits as IBitMask>::BitOr<<<<Ok as IDeterminantProvider<Err>>::NicheExporter as IStable>::UnusedBits as IBitMask>::Shift<<<Determinant<Ok, Err> as IStable>::Size as Unsigned>::NextMultipleOf<Self::Align>>>;
61    // Rust doesn't know `stabby` Results may have niches.
62    type HasExactlyOneNiche = B0;
63    #[cfg(feature = "experimental-ctypes")]
64    type CType = <Storage<<Self as IStable>::Size, <Self as IStable>::Align> as IStable>::CType;
65    const REPORT: &'static crate::report::TypeReport = &crate::report::TypeReport {
66        name: Str::new("Result"),
67        module: Str::new("stabby_abi::result"),
68        tyty: crate::report::TyTy::Enum(Str::new("stabby")),
69        version: 1,
70        fields: crate::StableLike::new(Some(&FieldReport {
71            name: Str::new("Ok"),
72            ty: Ok::REPORT,
73            next_field: crate::StableLike::new(Some(&FieldReport {
74                name: Str::new("Err"),
75                ty: Err::REPORT,
76                next_field: crate::StableLike::new(None),
77            })),
78        })),
79    };
80    const ID: u64 = crate::report::gen_id(Self::REPORT);
81}
82use seal::Storage;
83mod seal {
84    use super::*;
85    #[stabby::stabby]
86    pub struct Storage<Size: Unsigned, Align: Alignment + Alignment> {
87        inner: <Align::Divide<Size> as IUnsignedBase>::Array<Align::AsUint>,
88    }
89}
90
91impl<Size: Unsigned, Align: Alignment + Alignment> Storage<Size, Align> {
92    const fn as_ptr(&self) -> *const u8 {
93        self as *const Self as *const _
94    }
95    fn as_mut_ptr(&mut self) -> *mut u8 {
96        self as *mut Self as *mut _
97    }
98}
99
100impl<Ok: Clone, Err: Clone> Clone for Result<Ok, Err>
101where
102    Ok: IDeterminantProvider<Err>,
103    Err: IStable,
104{
105    fn clone(&self) -> Self {
106        self.match_ref(|ok| Self::Ok(ok.clone()), |err| Self::Err(err.clone()))
107    }
108}
109impl<Ok, Err> core::fmt::Debug for Result<Ok, Err>
110where
111    Ok: IDeterminantProvider<Err>,
112    Err: IStable,
113    Ok: core::fmt::Debug,
114    Err: core::fmt::Debug,
115{
116    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117        self.as_ref().fmt(f)
118    }
119}
120impl<Ok, Err> core::hash::Hash for Result<Ok, Err>
121where
122    Ok: IDeterminantProvider<Err>,
123    Err: IStable,
124    Ok: core::hash::Hash,
125    Err: core::hash::Hash,
126{
127    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
128        if self.is_ok() {
129            true.hash(state);
130            unsafe { self.ok_unchecked() }.hash(state);
131        } else {
132            false.hash(state);
133            unsafe { self.err_unchecked() }.hash(state);
134        }
135    }
136}
137impl<Ok, Err> core::cmp::PartialEq for Result<Ok, Err>
138where
139    Ok: IDeterminantProvider<Err>,
140    Err: IStable,
141    Ok: core::cmp::PartialEq,
142    Err: core::cmp::PartialEq,
143{
144    fn eq(&self, other: &Self) -> bool {
145        match (self.is_ok(), other.is_ok()) {
146            (true, true) => unsafe { self.ok_unchecked().eq(other.ok_unchecked()) },
147            (false, false) => unsafe { self.err_unchecked().eq(other.err_unchecked()) },
148            _ => false,
149        }
150    }
151}
152impl<Ok, Err> core::cmp::Eq for Result<Ok, Err>
153where
154    Ok: IDeterminantProvider<Err>,
155    Err: IStable,
156    Ok: core::cmp::Eq,
157    Err: core::cmp::Eq,
158{
159}
160impl<Ok, Err> From<core::result::Result<Ok, Err>> for Result<Ok, Err>
161where
162    Ok: IDeterminantProvider<Err>,
163    Err: IStable,
164{
165    fn from(value: core::result::Result<Ok, Err>) -> Self {
166        match value {
167            Ok(value) => Self::Ok(value),
168            Err(value) => Self::Err(value),
169        }
170    }
171}
172impl<Ok, Err> From<Result<Ok, Err>> for core::result::Result<Ok, Err>
173where
174    Ok: IDeterminantProvider<Err>,
175    Err: IStable,
176{
177    fn from(value: Result<Ok, Err>) -> Self {
178        value.match_owned(Ok, Err)
179    }
180}
181impl<Ok, Err> Drop for Result<Ok, Err>
182where
183    Ok: IDeterminantProvider<Err>,
184    Err: IStable,
185{
186    fn drop(&mut self) {
187        unsafe {
188            self.match_mut(
189                |mut ok| core::ptr::drop_in_place::<Ok>(&mut *ok),
190                |mut err| core::ptr::drop_in_place::<Err>(&mut *err),
191            )
192        }
193    }
194}
195impl<Ok, Err> Result<Ok, Err>
196where
197    Ok: IDeterminantProvider<Err>,
198    Err: IStable,
199{
200    const DET_SIZE: usize = <<<Determinant<Ok, Err> as IStable>::Size as Unsigned>::NextMultipleOf<
201        <Self as IStable>::Align,
202    > as Unsigned>::USIZE;
203    const OK_OFFSET: usize =
204        <<Ok as IDeterminantProvider<Err>>::OkShift as Unsigned>::USIZE + Self::DET_SIZE;
205    const ERR_OFFSET: usize =
206        <<Ok as IDeterminantProvider<Err>>::ErrShift as Unsigned>::USIZE + Self::DET_SIZE;
207    const fn ok_ptr(
208        storage: *const Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
209    ) -> *const Ok {
210        unsafe { storage.cast::<u8>().add(Self::OK_OFFSET).cast() }
211    }
212    const fn ok_ptr_mut(
213        storage: *mut Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
214    ) -> *mut Ok {
215        unsafe { storage.cast::<u8>().add(Self::OK_OFFSET).cast() }
216    }
217    const fn err_ptr(
218        storage: *const Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
219    ) -> *const Err {
220        unsafe { storage.cast::<u8>().add(Self::ERR_OFFSET).cast() }
221    }
222    const fn err_ptr_mut(
223        storage: *mut Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
224    ) -> *mut Err {
225        unsafe { storage.cast::<u8>().add(Self::ERR_OFFSET).cast() }
226    }
227    const fn det_ptr(
228        storage: *const Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
229    ) -> *const Determinant<Ok, Err> {
230        storage.cast()
231    }
232    const fn det_ptr_mut(
233        storage: *mut Storage<<Self as IStable>::Size, <Self as IStable>::Align>,
234    ) -> *mut Determinant<Ok, Err> {
235        storage.cast()
236    }
237    /// Construct the `Ok` variant.
238    #[allow(non_snake_case)]
239    pub fn Ok(value: Ok) -> Self {
240        let mut storage = core::mem::MaybeUninit::zeroed();
241        unsafe {
242            let storage_ptr = storage.as_mut_ptr();
243            Self::ok_ptr_mut(storage_ptr).write(value);
244            Self::det_ptr_mut(storage_ptr).write(Determinant::<Ok, Err>::ok(storage_ptr.cast()));
245            Self {
246                storage: storage.assume_init(),
247            }
248        }
249    }
250    /// Construct the `Err` variant.
251    #[allow(non_snake_case)]
252    pub fn Err(value: Err) -> Self {
253        let mut storage = core::mem::MaybeUninit::zeroed();
254        unsafe {
255            let storage_ptr = storage.as_mut_ptr();
256            Self::err_ptr_mut(storage_ptr).write(value);
257            Self::det_ptr_mut(storage_ptr).write(Determinant::<Ok, Err>::err(storage_ptr.cast()));
258            Self {
259                storage: storage.assume_init(),
260            }
261        }
262    }
263    /// Converts to a standard [`Result`](core::result::Result) of immutable references to the variants.
264    #[allow(clippy::missing_errors_doc)]
265    pub fn as_ref(&self) -> core::result::Result<&Ok, &Err> {
266        self.match_ref(Ok, Err)
267    }
268
269    /// Equivalent to `match &self`. If you need multiple branches to obtain mutable access or ownership
270    /// of a local, use [`Self::match_ref_ctx`] instead.
271    pub fn match_ref<'a, U, FnOk: FnOnce(&'a Ok) -> U, FnErr: FnOnce(&'a Err) -> U>(
272        &'a self,
273        ok: FnOk,
274        err: FnErr,
275    ) -> U {
276        if self.is_ok() {
277            unsafe { ok(self.ok_unchecked()) }
278        } else {
279            unsafe { err(self.err_unchecked()) }
280        }
281    }
282    /// Equivalent to `match &self`.
283    pub fn match_ref_ctx<'a, T, U, FnOk: FnOnce(T, &'a Ok) -> U, FnErr: FnOnce(T, &'a Err) -> U>(
284        &'a self,
285        ctx: T,
286        ok: FnOk,
287        err: FnErr,
288    ) -> U {
289        if self.is_ok() {
290            unsafe { ok(ctx, self.ok_unchecked()) }
291        } else {
292            unsafe { err(ctx, self.err_unchecked()) }
293        }
294    }
295    /// Equivalent to `match &mut self`. If you need multiple branches to obtain mutable access or ownership
296    /// of a local, use [`Self::match_mut_ctx`] instead.
297    pub fn match_mut<
298        'a,
299        U,
300        FnOk: FnOnce(OkGuard<'a, Ok, Err>) -> U,
301        FnErr: FnOnce(ErrGuard<'a, Ok, Err>) -> U,
302    >(
303        &'a mut self,
304        ok: FnOk,
305        err: FnErr,
306    ) -> U {
307        let r;
308        if Self::is_ok(self) {
309            unsafe {
310                r = ok(self.ok_mut_unchecked());
311            }
312        } else {
313            unsafe {
314                r = err(self.err_mut_unchecked());
315            }
316        }
317        r
318    }
319    /// Equivalent to `match &mut self`.
320    pub fn match_mut_ctx<
321        'a,
322        T,
323        U,
324        FnOk: FnOnce(T, OkGuard<'a, Ok, Err>) -> U,
325        FnErr: FnOnce(T, ErrGuard<'_, Ok, Err>) -> U,
326    >(
327        &'a mut self,
328        ctx: T,
329        ok: FnOk,
330        err: FnErr,
331    ) -> U {
332        let r;
333        if Self::is_ok(self) {
334            unsafe {
335                r = ok(ctx, self.ok_mut_unchecked());
336            }
337        } else {
338            unsafe {
339                r = err(ctx, self.err_mut_unchecked());
340            }
341        }
342        r
343    }
344    /// Equivalent to `match self`. If you need multiple branches to obtain mutable access or ownership
345    /// of a local, use [`Self::match_owned_ctx`] instead.
346    pub fn match_owned<U, FnOk: FnOnce(Ok) -> U, FnErr: FnOnce(Err) -> U>(
347        self,
348        ok: FnOk,
349        err: FnErr,
350    ) -> U {
351        let is_ok = self.is_ok();
352        let storage = &self.storage;
353        if is_ok {
354            let t = unsafe { core::ptr::read(Self::ok_ptr(storage)) };
355            core::mem::forget(self);
356            ok(t)
357        } else {
358            let t = unsafe { core::ptr::read(Self::err_ptr(storage)) };
359            core::mem::forget(self);
360            err(t)
361        }
362    }
363    /// Equivalent to `match self`.
364    pub fn match_owned_ctx<U, T, FnOk: FnOnce(T, Ok) -> U, FnErr: FnOnce(T, Err) -> U>(
365        self,
366        ctx: T,
367        ok: FnOk,
368        err: FnErr,
369    ) -> U {
370        let is_ok = self.is_ok();
371        let storage = &self.storage;
372        if is_ok {
373            let t = unsafe { core::ptr::read(Self::ok_ptr(storage)) };
374            core::mem::forget(self);
375            ok(ctx, t)
376        } else {
377            let t = unsafe { core::ptr::read(Self::err_ptr(storage)) };
378            core::mem::forget(self);
379            err(ctx, t)
380        }
381    }
382    /// Returns `true` if in the `Ok` variant.
383    pub fn is_ok(&self) -> bool {
384        unsafe { &*Self::det_ptr(&self.storage) }.is_det_ok(self.storage.as_ptr())
385    }
386    /// Returns `true` if in the `Err` variant.
387    pub fn is_err(&self) -> bool {
388        !self.is_ok()
389    }
390    /// Returns the `Ok` variant if it exists, `None` otherwise.
391    pub fn ok(self) -> Option<Ok> {
392        self.match_owned(Some, |_| None)
393    }
394    /// Returns the `Err` variant if it exists, `None` otherwise.
395    pub fn err(self) -> Option<Err> {
396        self.match_owned(|_| None, Some)
397    }
398    /// Returns the `Ok` variant by reference if it exists, `None` otherwise.
399    pub fn ok_ref(&self) -> Option<&Ok> {
400        self.match_ref(Some, |_| None)
401    }
402    /// Returns the `Err` variant by reference if it exists, `None` otherwise.
403    pub fn err_ref(&self) -> Option<&Err> {
404        self.match_ref(|_| None, Some)
405    }
406    /// Returns the `Ok` variant by mutable reference if it exists, `None` otherwise.
407    pub fn ok_mut(&mut self) -> Option<OkGuard<'_, Ok, Err>> {
408        self.match_mut(Some, |_| None)
409    }
410    /// Returns the `Err` variant by mutable reference if it exists, `None` otherwise.
411    pub fn err_mut(&mut self) -> Option<ErrGuard<'_, Ok, Err>> {
412        self.match_mut(|_| None, Some)
413    }
414    /// Applies a computation to the `Ok` variant.
415    pub fn map<F: FnOnce(Ok) -> U, U>(self, f: F) -> Result<U, Err>
416    where
417        U: IDeterminantProvider<Err>,
418    {
419        self.match_owned(move |x| Result::Ok(f(x)), |x| Result::Err(x))
420    }
421    /// Applies a fallible computation to the `Err` variant.
422    pub fn and_then<F: FnOnce(Ok) -> Result<U, Err>, U>(self, f: F) -> Result<U, Err>
423    where
424        U: IDeterminantProvider<Err>,
425    {
426        self.match_owned(f, |x| Result::Err(x))
427    }
428    /// Returns the `Ok` variant if applicable, calling `f` on the `Err` otherwise.
429    pub fn unwrap_or_else<F: FnOnce(Err) -> Ok>(self, f: F) -> Ok {
430        self.match_owned(|x| x, f)
431    }
432    /// # Safety
433    /// Called on an `Err`, this triggers Undefined Behaviour.
434    pub unsafe fn unwrap_unchecked(self) -> Ok {
435        self.unwrap_or_else(|_| unsafe { unreachable_unchecked!() })
436    }
437    /// # Panics
438    /// If `!self.is_ok()`
439    pub fn unwrap(self) -> Ok
440    where
441        Err: core::fmt::Debug,
442    {
443        self.unwrap_or_else(|e| panic!("Result::unwrap called on Err variant: {e:?}"))
444    }
445    /// Returns the `Err` variant if applicable, calling `f` on the `Ok` otherwise.
446    pub fn unwrap_err_or_else<F: FnOnce(Ok) -> Err>(self, f: F) -> Err {
447        self.match_owned(f, |x| x)
448    }
449    /// # Safety
450    /// Called on an `Ok`, this triggers Undefined Behaviour.
451    pub unsafe fn unwrap_err_unchecked(self) -> Err {
452        self.unwrap_err_or_else(|_| unsafe { unreachable_unchecked!() })
453    }
454    /// # Panics
455    /// If `!self.is_err()`
456    pub fn unwrap_err(self) -> Err
457    where
458        Ok: core::fmt::Debug,
459    {
460        self.unwrap_err_or_else(|e| panic!("Result::unwrap_err called on Ok variant: {e:?}"))
461    }
462    const unsafe fn ok_unchecked(&self) -> &Ok {
463        &*Self::ok_ptr(&self.storage)
464    }
465    const unsafe fn err_unchecked(&self) -> &Err {
466        &*Self::err_ptr(&self.storage)
467    }
468    unsafe fn ok_mut_unchecked(&mut self) -> OkGuard<'_, Ok, Err> {
469        OkGuard { inner: self }
470    }
471    unsafe fn err_mut_unchecked(&mut self) -> ErrGuard<Ok, Err> {
472        ErrGuard { inner: self }
473    }
474}
475
476/// A guard that ensures that niche determinants are reinserted if the `Ok` variant of an [`Result`] is re-established after it may have been mutated.
477///
478/// When dropped, this guard ensures that the result's determinant is properly set.
479/// Failing to drop this guard may result in undefined behaviour.
480pub struct OkGuard<'a, Ok, Err>
481where
482    Ok: IDeterminantProvider<Err>,
483    Err: IStable,
484{
485    inner: &'a mut Result<Ok, Err>,
486}
487impl<Ok, Err> core::ops::Deref for OkGuard<'_, Ok, Err>
488where
489    Ok: IDeterminantProvider<Err>,
490    Err: IStable,
491{
492    type Target = Ok;
493    fn deref(&self) -> &Self::Target {
494        unsafe { self.inner.ok_unchecked() }
495    }
496}
497impl<Ok, Err> core::ops::DerefMut for OkGuard<'_, Ok, Err>
498where
499    Ok: IDeterminantProvider<Err>,
500    Err: IStable,
501{
502    fn deref_mut(&mut self) -> &mut Self::Target {
503        unsafe { &mut *Result::<Ok, Err>::ok_ptr_mut(&mut self.inner.storage) }
504    }
505}
506impl<Ok, Err> Drop for OkGuard<'_, Ok, Err>
507where
508    Ok: IDeterminantProvider<Err>,
509    Err: IStable,
510{
511    fn drop(&mut self) {
512        if <<Determinant<Ok, Err> as IDeterminant>::IsNicheTrick as Bit>::BOOL {
513            unsafe { Determinant::<Ok, Err>::ok(self.inner.storage.as_mut_ptr()) };
514        }
515    }
516}
517
518/// A guard that ensures that niche determinants are reinserted if the `Err` variant of an [`Option`] is re-established after it may have been mutated.
519///
520/// When dropped, this guard ensures that the result's determinant is properly set.
521/// Failing to drop this guard may result in undefined behaviour.
522pub struct ErrGuard<'a, Ok, Err>
523where
524    Ok: IDeterminantProvider<Err>,
525    Err: IStable,
526{
527    inner: &'a mut Result<Ok, Err>,
528}
529
530impl<Ok, Err> core::ops::Deref for ErrGuard<'_, Ok, Err>
531where
532    Ok: IDeterminantProvider<Err>,
533    Err: IStable,
534{
535    type Target = Err;
536    fn deref(&self) -> &Self::Target {
537        unsafe { self.inner.err_unchecked() }
538    }
539}
540impl<Ok, Err> core::ops::DerefMut for ErrGuard<'_, Ok, Err>
541where
542    Ok: IDeterminantProvider<Err>,
543    Err: IStable,
544{
545    fn deref_mut(&mut self) -> &mut Self::Target {
546        unsafe { &mut *Result::<Ok, Err>::err_ptr_mut(&mut self.inner.storage) }
547    }
548}
549impl<Ok, Err> Drop for ErrGuard<'_, Ok, Err>
550where
551    Ok: IDeterminantProvider<Err>,
552    Err: IStable,
553{
554    fn drop(&mut self) {
555        if <<Determinant<Ok, Err> as IDeterminant>::IsNicheTrick as Bit>::BOOL {
556            unsafe { Determinant::<Ok, Err>::err(self.inner.storage.as_mut_ptr()) };
557        }
558    }
559}
560
561#[cfg(feature = "serde")]
562mod serde_impl {
563    use super::*;
564    use serde::{Deserialize, Serialize};
565    impl<Ok: Serialize, Err: Serialize> Serialize for Result<Ok, Err>
566    where
567        Ok: IDeterminantProvider<Err>,
568        Err: IStable,
569    {
570        fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
571        where
572            S: serde::Serializer,
573        {
574            let this: core::result::Result<_, _> = self.as_ref();
575            this.serialize(serializer)
576        }
577    }
578    impl<'a, Ok: IDeterminantProvider<Err>, Err: IStable> Deserialize<'a> for Result<Ok, Err>
579    where
580        core::result::Result<Ok, Err>: Deserialize<'a>,
581    {
582        fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
583        where
584            D: serde::Deserializer<'a>,
585        {
586            Ok(core::result::Result::<Ok, Err>::deserialize(deserializer)?.into())
587        }
588    }
589}