stabby_abi/
option.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//! A stable option for when rust's `Option<T>` isn't!
16
17use crate::enums::IDeterminantProvider;
18use crate::result::OkGuard;
19use crate::{unreachable_unchecked, IStable};
20
21/// A niche optimizing equivalent of [`core::option::Option`] that's ABI-stable regardless of the inner type's niches.
22#[crate::stabby]
23#[derive(Clone, PartialEq, Eq, Hash)]
24pub struct Option<T: IStable + IDeterminantProvider<()>> {
25    inner: crate::result::Result<T, ()>,
26}
27impl<T: IStable> core::fmt::Debug for Option<T>
28where
29    T: IDeterminantProvider<()>,
30    T: core::fmt::Debug,
31{
32    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33        self.as_ref().fmt(f)
34    }
35}
36impl<T: IStable> From<core::option::Option<T>> for Option<T>
37where
38    T: IDeterminantProvider<()>,
39{
40    fn from(value: core::option::Option<T>) -> Self {
41        match value {
42            Some(value) => Self {
43                inner: crate::result::Result::Ok(value),
44            },
45            None => Self {
46                inner: crate::result::Result::Err(()),
47            },
48        }
49    }
50}
51impl<T: IStable> From<Option<T>> for core::option::Option<T>
52where
53    T: IDeterminantProvider<()>,
54{
55    fn from(value: Option<T>) -> Self {
56        value.inner.ok()
57    }
58}
59impl<T: IStable> Default for Option<T>
60where
61    T: IDeterminantProvider<()>,
62{
63    fn default() -> Self {
64        Self::None()
65    }
66}
67/// A guard that ensures that niche determinants are reinserted if the `Some` variant of an [`Option`] is re-established after it may have been mutated.
68///
69/// When dropped, this guard ensures that the result's determinant is properly set.
70/// Failing to drop this guard may result in undefined behaviour.
71pub type SomeGuard<'a, T> = OkGuard<'a, T, ()>;
72impl<T: IStable> Option<T>
73where
74    T: IDeterminantProvider<()>,
75{
76    /// Construct the `Some` variant.
77    #[allow(non_snake_case)]
78    pub fn Some(value: T) -> Self {
79        Self {
80            inner: crate::result::Result::Ok(value),
81        }
82    }
83    /// Construct the `None` variant.
84    #[allow(non_snake_case)]
85    pub fn None() -> Self {
86        Self {
87            inner: crate::result::Result::Err(()),
88        }
89    }
90    /// Returns a reference to the option's contents if they exist.
91    pub fn as_ref(&self) -> core::option::Option<&T> {
92        self.match_ref(Some, || None)
93    }
94    /// Returns a mutable reference to the option's contents if they exist.
95    pub fn as_mut(&mut self) -> core::option::Option<SomeGuard<T>> {
96        self.match_mut(Some, || None)
97    }
98    /// Equivalent to `match &self`. If you need multiple branches to obtain mutable access or ownership
99    /// of a local, use [`Self::match_ref_ctx`] instead.
100    pub fn match_ref<'a, U, FnSome: FnOnce(&'a T) -> U, FnNone: FnOnce() -> U>(
101        &'a self,
102        some: FnSome,
103        none: FnNone,
104    ) -> U {
105        self.inner.match_ref(some, |_| none())
106    }
107    /// Equivalent to `match &self`.
108    pub fn match_ref_ctx<'a, I, U, FnSome: FnOnce(I, &'a T) -> U, FnNone: FnOnce(I) -> U>(
109        &'a self,
110        ctx: I,
111        some: FnSome,
112        none: FnNone,
113    ) -> U {
114        self.inner.match_ref_ctx(ctx, some, move |ctx, _| none(ctx))
115    }
116    /// Equivalent to `match &mut self`. If you need multiple branches to obtain mutable access or ownership
117    /// of a local, use [`Self::match_mut_ctx`] instead.
118    pub fn match_mut<'a, U, FnSome: FnOnce(SomeGuard<'a, T>) -> U, FnNone: FnOnce() -> U>(
119        &'a mut self,
120        some: FnSome,
121        none: FnNone,
122    ) -> U {
123        self.inner.match_mut(some, |_| none())
124    }
125    /// Equivalent to `match &mut self`.
126    pub fn match_mut_ctx<
127        'a,
128        I,
129        U,
130        FnSome: FnOnce(I, SomeGuard<'a, T>) -> U,
131        FnNone: FnOnce(I) -> U,
132    >(
133        &'a mut self,
134        ctx: I,
135        some: FnSome,
136        none: FnNone,
137    ) -> U {
138        self.inner.match_mut_ctx(ctx, some, move |ctx, _| none(ctx))
139    }
140    /// Equivalent to `match self`. If you need multiple branches to obtain mutable access or ownership
141    /// of a local, use [`Self::match_owned_ctx`] instead.
142    pub fn match_owned<U, FnSome: FnOnce(T) -> U, FnNone: FnOnce() -> U>(
143        self,
144        some: FnSome,
145        none: FnNone,
146    ) -> U {
147        self.inner.match_owned(some, |_| none())
148    }
149    /// Equivalent to `match self`.
150    pub fn match_owned_ctx<I, U, FnSome: FnOnce(I, T) -> U, FnNone: FnOnce(I) -> U>(
151        self,
152        ctx: I,
153        some: FnSome,
154        none: FnNone,
155    ) -> U {
156        self.inner
157            .match_owned_ctx(ctx, some, move |ctx, _| none(ctx))
158    }
159    /// Returns `true` if `self` contains a value.
160    pub fn is_some(&self) -> bool {
161        self.inner.is_ok()
162    }
163    /// Returns `true` if `self` doesn't contain a value.
164    pub fn is_none(&self) -> bool {
165        !self.is_some()
166    }
167    /// Unwraps the option, or runs `f` if no value was in it.
168    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
169        self.match_owned(|x| x, f)
170    }
171    /// # Safety
172    /// Calling this on `Self::None()` is UB.
173    pub unsafe fn unwrap_unchecked(self) -> T {
174        // SAFETY: Caller-guaranteed
175        self.unwrap_or_else(|| unsafe { unreachable_unchecked!() })
176    }
177    /// # Panics
178    /// If `!self.is_some`
179    pub fn unwrap(self) -> T {
180        self.unwrap_or_else(|| panic!("Option::unwrap called on None"))
181    }
182}
183
184#[cfg(feature = "serde")]
185mod serde_impl {
186    use super::*;
187    use serde::{Deserialize, Serialize};
188    impl<Ok: Serialize> Serialize for Option<Ok>
189    where
190        Ok: IDeterminantProvider<()>,
191    {
192        fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
193        where
194            S: serde::Serializer,
195        {
196            let this = self.as_ref();
197            this.serialize(serializer)
198        }
199    }
200    impl<'a, Ok: IDeterminantProvider<()>> Deserialize<'a> for Option<Ok>
201    where
202        core::option::Option<Ok>: Deserialize<'a>,
203    {
204        fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
205        where
206            D: serde::Deserializer<'a>,
207        {
208            Ok(core::option::Option::<Ok>::deserialize(deserializer)?.into())
209        }
210    }
211}