Skip to main content

ctutils/
ct_option.rs

1use crate::{Choice, CtAssign, CtAssignSlice, CtEq, CtEqSlice, CtSelect};
2use core::ops::{Deref, DerefMut};
3
4/// Helper macro for providing behavior like the [`CtOption::map`] combinator that works in
5/// `const fn` contexts.
6///
7/// Requires a provided `$mapper` function to convert from one type to another, e.g.
8///
9/// ```ignore
10/// const fn mapper(value: T) -> U
11/// ```
12#[macro_export]
13macro_rules! map {
14    ($opt:expr, $mapper:path) => {{ $crate::CtOption::new($mapper($opt.to_inner_unchecked()), $opt.is_some()) }};
15}
16
17/// Helper macro for providing behavior like the [`CtOption::unwrap_or`] combinator that works in
18/// `const fn` contexts.
19///
20/// Requires a provided selector function `$select` to perform constant-time selection which takes
21/// two `T` values by reference along with a [`Choice`], returning the first `T` for
22/// [`Choice::FALSE`], and the second for [`Choice::TRUE`], e.g.:
23///
24/// ```ignore
25/// const fn ct_select(a: &T, b: &T, condition: Choice) -> T
26/// ```
27#[macro_export]
28macro_rules! unwrap_or {
29    ($opt:expr, $default:expr, $select:path) => {
30        $select(&$default, $opt.as_inner_unchecked(), $opt.is_some())
31    };
32}
33
34/// Equivalent of [`Option`] but predicated on a [`Choice`] with combinators that allow for
35/// constant-time operations which always perform the same sequence of instructions regardless of
36/// the value of `is_some`.
37///
38/// Unlike [`Option`], [`CtOption`] always contains a value, and will use the contained value when
39/// e.g. evaluating the callbacks of combinator methods, which unlike `core` it does unconditionally
40/// in order to ensure constant-time operation. This approach stands in contrast to the lazy
41/// evaluation similar methods on [`Option`] provide.
42#[derive(Clone, Copy, Debug)]
43pub struct CtOption<T> {
44    value: T,
45    is_some: Choice,
46}
47
48impl<T> CtOption<T> {
49    /// Construct a new [`CtOption`], with a [`Choice`] parameter `is_some` as a stand-in for
50    /// `Some` or `None` enum variants of a typical [`Option`] type.
51    #[inline]
52    #[must_use]
53    pub const fn new(value: T, is_some: Choice) -> CtOption<T> {
54        Self { value, is_some }
55    }
56
57    /// Construct a new [`CtOption`] where `self.is_some()` is [`Choice::TRUE`].
58    #[inline]
59    #[must_use]
60    pub const fn some(value: T) -> CtOption<T> {
61        Self::new(value, Choice::TRUE)
62    }
63
64    /// Construct a new [`CtOption`] with the [`Default`] value, and where `self.is_some()` is
65    /// [`Choice::FALSE`].
66    #[inline]
67    #[must_use]
68    pub fn none() -> CtOption<T>
69    where
70        T: Default,
71    {
72        Self::new(Default::default(), Choice::FALSE)
73    }
74
75    /// Convert from a `&mut CtOption<T>` to `CtOption<&mut T>`.
76    #[inline]
77    #[must_use]
78    pub const fn as_mut(&mut self) -> CtOption<&mut T> {
79        CtOption {
80            value: &mut self.value,
81            is_some: self.is_some,
82        }
83    }
84
85    /// Convert from a `&CtOption<T>` to `CtOption<&T>`.
86    #[inline]
87    #[must_use]
88    pub const fn as_ref(&self) -> CtOption<&T> {
89        CtOption {
90            value: &self.value,
91            is_some: self.is_some,
92        }
93    }
94
95    /// Convert from `CtOption<T>` (or `&CtOption<T>`) to `CtOption<&T::Target>`, for types which
96    /// impl the [`Deref`] trait.
97    #[inline]
98    #[must_use]
99    pub fn as_deref(&self) -> CtOption<&T::Target>
100    where
101        T: Deref,
102    {
103        self.as_ref().map(Deref::deref)
104    }
105
106    /// Convert from `CtOption<T>` (or `&mut CtOption<T>`) to `CtOption<&mut T::Target>`, for types
107    /// which impl the [`DerefMut`] trait.
108    #[inline]
109    #[must_use]
110    pub fn as_deref_mut(&mut self) -> CtOption<&mut T::Target>
111    where
112        T: DerefMut,
113    {
114        self.as_mut().map(DerefMut::deref_mut)
115    }
116
117    /// Return the contained value, consuming the `self` value.
118    ///
119    /// # Panics
120    /// In the event `self.is_some()` is [`Choice::FALSE`], panics with a custom panic message
121    /// provided as the `msg` argument.
122    #[inline]
123    #[must_use]
124    #[track_caller]
125    pub fn expect(self, msg: &str) -> T {
126        assert!(self.is_some().to_bool(), "{}", msg);
127        self.value
128    }
129
130    /// Return the contained value, consuming the `self` value, with `const fn` support.
131    ///
132    /// Relies on a `Copy` bound which implies `!Drop` which is needed to be able to move out of
133    /// `self` in a `const fn` without `feature(const_precise_live_drops)`.
134    ///
135    /// # Panics
136    /// In the event `self.is_some()` is [`Choice::FALSE`], panics with a custom panic message
137    /// provided as the `msg` argument.
138    // TODO(tarcieri): get rid of this when we can make `expect` a `const fn`
139    // (needs `const_precise_live_drops`)
140    #[inline]
141    #[must_use]
142    #[track_caller]
143    pub const fn expect_copied(self, msg: &str) -> T
144    where
145        T: Copy,
146    {
147        *self.expect_ref(msg)
148    }
149
150    /// Borrow the contained value.
151    ///
152    /// # Panics
153    /// In the event `self.is_some()` is [`Choice::FALSE`], panics with a custom panic message
154    /// provided as the `msg` argument.
155    // TODO(tarcieri): get rid of this when we can make `expect` a `const fn`
156    // (needs `const_precise_live_drops`)
157    #[inline]
158    #[must_use]
159    #[track_caller]
160    pub const fn expect_ref(&self, msg: &str) -> &T {
161        // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
162        assert!(self.is_some.to_bool_vartime(), "{}", msg);
163        self.as_inner_unchecked()
164    }
165
166    /// Inserts `value` into the [`CtOption`], then returns a mutable reference to it.
167    ///
168    /// If the option already contains a value, the old value is dropped.
169    pub fn insert(&mut self, value: T) -> &mut T {
170        self.value = value;
171        self.is_some = Choice::TRUE;
172        &mut self.value
173    }
174
175    /// Conditionally inserts `value` into the [`CtOption`] if the given condition holds.
176    pub fn insert_if(&mut self, value: &T, condition: Choice)
177    where
178        T: CtAssign,
179    {
180        self.value.ct_assign(value, condition);
181        self.is_some.ct_assign(&Choice::TRUE, condition);
182    }
183
184    /// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
185    /// [`CtOption::is_some`] is a truthy or falsy [`Choice`].
186    ///
187    /// This function exists to avoid ending up with ugly, verbose and/or bad handled conversions
188    /// from the [`CtOption`] wraps to an [`Option`] or [`Result`].
189    ///
190    /// It's equivalent to the corresponding [`From`] impl, however this version is friendlier for
191    /// type inference.
192    ///
193    /// <div class="warning">
194    /// <b>Warning: variable-time!</b>
195    ///
196    /// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
197    /// `T` value since the [`Option`] will do it anyway.
198    /// </div>
199    #[inline]
200    pub fn into_option(self) -> Option<T> {
201        if self.is_some.to_bool() {
202            Some(self.value)
203        } else {
204            None
205        }
206    }
207
208    /// Convert the [`CtOption`] wrapper into an [`Option`] in a `const fn`-friendly manner.
209    ///
210    /// This is the equivalent of [`CtOption::into_option`] but is `const fn`-friendly by only
211    /// allowing `Copy` types which are implicitly `!Drop` and don't run into problems with
212    /// `const fn` and destructors.
213    ///
214    /// <div class="warning">
215    /// <b>Warning: variable-time!</b>
216    ///
217    /// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
218    /// `T` value since the [`Option`] will do it anyway.
219    /// </div>
220    #[inline]
221    pub const fn into_option_copied(self) -> Option<T>
222    where
223        T: Copy,
224    {
225        // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
226        if self.is_some.to_bool_vartime() {
227            Some(self.value)
228        } else {
229            None
230        }
231    }
232
233    /// Returns [`Choice::TRUE`] if the option is the equivalent of a `Some`.
234    #[inline]
235    #[must_use]
236    pub const fn is_some(&self) -> Choice {
237        self.is_some
238    }
239
240    /// Returns [`Choice::TRUE`] if the option is the equivalent of a `None`.
241    #[inline]
242    #[must_use]
243    pub const fn is_none(&self) -> Choice {
244        self.is_some.not()
245    }
246
247    /// Returns `optb` if `self.is_some()` is [`Choice::TRUE`], otherwise returns a [`CtOption`]
248    /// where `self.is_some()` is [`Choice::FALSE`].
249    #[inline]
250    #[must_use]
251    pub fn and<U>(self, mut optb: CtOption<U>) -> CtOption<U> {
252        optb.is_some &= self.is_some;
253        optb
254    }
255
256    /// Calls the provided callback with the wrapped inner value, returning the resulting
257    /// [`CtOption`] value in the event that `self.is_some()` is [`Choice::TRUE`], or if not
258    /// returns a [`CtOption`] with `self.is_none()`.
259    ///
260    /// Unlike [`Option`], the provided callback `f` is unconditionally evaluated to ensure
261    /// constant-time operation. This requires evaluating the function with "dummy" value of `T`
262    /// (e.g. if the [`CtOption`] was constructed with a supplied placeholder value and
263    /// [`Choice::FALSE`], the placeholder value will be provided).
264    #[inline]
265    #[must_use]
266    pub fn and_then<U, F>(self, f: F) -> CtOption<U>
267    where
268        F: FnOnce(T) -> CtOption<U>,
269    {
270        let mut ret = f(self.value);
271        ret.is_some &= self.is_some;
272        ret
273    }
274
275    /// Obtain a reference to the inner value without first checking that `self.is_some()` is
276    /// [`Choice::TRUE`].
277    ///
278    /// This method is primarily intended for use in `const fn` scenarios where it's not yet
279    /// possible to use the safe combinator methods, and returns a reference to avoid issues with
280    /// `const fn` destructors.
281    ///
282    /// <div class="warning">
283    /// <b>Use with care!</b>
284    ///
285    /// This method does not ensure the `value` is actually valid. Callers of this method should
286    /// take great care to ensure that `self.is_some()` is checked elsewhere.
287    /// </div>
288    #[inline]
289    #[must_use]
290    pub const fn as_inner_unchecked(&self) -> &T {
291        &self.value
292    }
293
294    /// Calls the provided callback with the wrapped inner value, which computes a [`Choice`],
295    /// and updates `self.is_some()`.
296    ///
297    /// It updates it to be [`Choice::FALSE`] in the event the returned choice is also false.
298    /// If it was [`Choice::FALSE`] to begin with, it will unconditionally remain that way.
299    #[inline]
300    #[must_use]
301    pub fn filter<P>(mut self, predicate: P) -> Self
302    where
303        P: FnOnce(&T) -> Choice,
304    {
305        self.is_some &= predicate(&self.value);
306        self
307    }
308
309    /// Apply an additional [`Choice`] requirement to `is_some`.
310    #[inline]
311    #[must_use]
312    pub const fn filter_by(mut self, is_some: Choice) -> Self {
313        self.is_some = self.is_some.and(is_some);
314        self
315    }
316
317    /// Maps a `CtOption<T>` to a `CtOption<U>` by unconditionally applying a function to the
318    /// contained `value`, but returning a new option value which inherits `self.is_some()`.
319    #[inline]
320    #[must_use]
321    pub fn map<U, F>(self, f: F) -> CtOption<U>
322    where
323        F: FnOnce(T) -> U,
324    {
325        CtOption::new(f(self.value), self.is_some)
326    }
327
328    /// Maps a `CtOption<T>` to a `U` value, eagerly evaluating the provided function, and returning
329    /// the supplied `default` in the event `self.is_some()` is [`Choice::FALSE`].
330    #[inline]
331    #[must_use = "if you don't need the returned value, use `if let` instead"]
332    pub fn map_or<U, F>(self, default: U, f: F) -> U
333    where
334        U: CtSelect,
335        F: FnOnce(T) -> U,
336    {
337        self.map(f).unwrap_or(default)
338    }
339
340    /// Maps a `CtOption<T>` to a `U` value, eagerly evaluating the provided function, precomputing
341    /// `U::default()` using the [`Default`] trait, and returning it in the event `self.is_some()`
342    /// is [`Choice::FALSE`].
343    #[inline]
344    #[must_use]
345    pub fn map_or_default<U, F>(self, f: F) -> U
346    where
347        U: CtSelect + Default,
348        F: FnOnce(T) -> U,
349    {
350        self.map_or(U::default(), f)
351    }
352
353    /// Transforms a `CtOption<T>` into a `Result<T, E>`, mapping to `Ok(T)` if `self.is_some()` is
354    /// [`Choice::TRUE`], or mapping to the provided `err` in the event `self.is_some()` is
355    /// [`Choice::FALSE`].
356    ///
357    /// <div class="warning">
358    /// <b>Warning: variable-time!</b>
359    ///
360    /// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
361    /// `T` value since the [`Result`] will do it anyway.
362    /// </div>
363    ///
364    /// # Errors
365    /// - Returns `err` in the event `self.is_some()` is [`Choice::FALSE`].
366    #[inline]
367    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
368        self.into_option().ok_or(err)
369    }
370
371    /// Transforms a `CtOption<T>` into a `Result<T, E>` by unconditionally calling the provided
372    /// callback value and using its result in the event `self.is_some()` is [`Choice::FALSE`].
373    ///
374    /// <div class="warning">
375    /// <b>Warning: variable-time!</b>
376    ///
377    /// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
378    /// `T` value since the [`Result`] will do it anyway.
379    /// </div>
380    ///
381    /// # Errors
382    /// - Returns `err` in the event `self.is_some()` is [`Choice::FALSE`].
383    #[inline]
384    #[allow(clippy::missing_errors_doc)]
385    pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
386    where
387        F: FnOnce() -> E,
388    {
389        self.ok_or(err())
390    }
391
392    /// Returns `self` if `self.is_some()` is [`Choice::TRUE`], otherwise returns `optb`.
393    #[inline]
394    #[must_use]
395    pub fn or(self, optb: CtOption<T>) -> CtOption<T>
396    where
397        T: CtSelect,
398    {
399        CtOption {
400            value: self.value.ct_select(&optb.value, self.is_none()),
401            is_some: self.is_some | optb.is_some,
402        }
403    }
404
405    /// Obtain a copy of the inner value without first checking that `self.is_some()` is
406    /// [`Choice::TRUE`].
407    ///
408    /// This method is primarily intended for use in `const fn` scenarios where it's not yet
409    /// possible to use the safe combinator methods, and uses a `Copy` bound to avoid issues with
410    /// `const fn` destructors.
411    ///
412    /// <div class="warning">
413    /// <b>Use with care!</b>
414    ///
415    /// This method does not ensure the `value` is actually valid. Callers of this method should
416    /// take great care to ensure that `self.is_some()` is checked elsewhere.
417    /// </div>
418    #[inline]
419    #[must_use]
420    pub const fn to_inner_unchecked(self) -> T
421    where
422        T: Copy,
423    {
424        self.value
425    }
426
427    /// Return the contained value, consuming the `self` value.
428    ///
429    /// Use of this function is discouraged due to panic potential. Instead, prefer non-panicking
430    /// alternatives such as `unwrap_or` or `unwrap_or_default` which operate in constant-time.
431    ///
432    /// As the final step of a sequence of constant-time operations, or in the event you are dealing
433    /// with a [`CtOption`] in a non-secret context where constant-time does not matter, you can
434    /// also convert to [`Option`] using `into_option` or the [`From`] impl on [`Option`]. Note
435    /// this introduces a branch and with it a small amount of timing variability. If possible try
436    /// to avoid this branch when writing constant-time code (e.g. use implicit rejection instead
437    /// of `Option`/`Result` to handle errors)
438    ///
439    /// # Panics
440    /// In the event `self.is_some()` is [`Choice::FALSE`].
441    #[inline]
442    #[must_use]
443    #[track_caller]
444    pub fn unwrap(self) -> T {
445        assert!(
446            self.is_some.to_bool(),
447            "called `CtOption::unwrap()` on a value with `is_some` set to `Choice::FALSE`"
448        );
449        self.value
450    }
451
452    /// Return the contained value in the event `self.is_some()` is [`Choice::TRUE`], or if not,
453    /// uses a provided default.
454    #[inline]
455    #[must_use]
456    pub fn unwrap_or(self, default: T) -> T
457    where
458        T: CtSelect,
459    {
460        default.ct_select(&self.value, self.is_some)
461    }
462
463    /// Unconditionally computes `T::default()` using the [`Default`] trait, then returns either
464    /// the contained value if `self.is_some()` is [`Choice::TRUE`], or if it's [`Choice::FALSE`]
465    /// returns the previously computed default.
466    #[inline]
467    #[must_use]
468    pub fn unwrap_or_default(self) -> T
469    where
470        T: CtSelect + Default,
471    {
472        self.unwrap_or(T::default())
473    }
474
475    /// Returns an "is some" [`CtOption`] with the contained value from either `self` or `optb` in
476    /// the event exactly one of them has `self.is_some()` set to [`Choice::TRUE`], or else returns
477    /// a [`CtOption`] with `self.is_some()` set to [`Choice::FALSE`].
478    #[inline]
479    #[must_use]
480    pub fn xor(self, optb: CtOption<T>) -> CtOption<T>
481    where
482        T: CtSelect,
483    {
484        CtOption {
485            value: self.value.ct_select(&optb.value, self.is_none()),
486            is_some: self.is_some ^ optb.is_some,
487        }
488    }
489
490    /// Zips `self` with another [`CtOption`].
491    ///
492    /// If `self.is_some() && other.is_some()`, this method returns a new [`CtOption`] for a 2-tuple
493    /// of their contents where `is_some()` is [`Choice::TRUE`].
494    ///
495    /// Otherwise, a [`CtOption`] where `is_some()` is [`Choice::FALSE`] is returned.
496    pub fn zip<U>(self, other: CtOption<U>) -> CtOption<(T, U)> {
497        CtOption {
498            value: (self.value, other.value),
499            is_some: self.is_some & other.is_some,
500        }
501    }
502
503    /// Zips `self` and another `CtOption` with function `f`.
504    ///
505    /// If `self.is_some() && other.is_some()`, this method returns a new [`CtOption`] for
506    /// the result of `f` applied to their inner values where `is_some()` is [`Choice::TRUE`].
507    ///
508    /// Otherwise, a [`CtOption`] where `is_some()` is [`Choice::FALSE`] is returned.
509    pub fn zip_with<U, F, R>(self, other: CtOption<U>, f: F) -> CtOption<R>
510    where
511        F: FnOnce(T, U) -> R,
512    {
513        self.zip(other).map(|(a, b)| f(a, b))
514    }
515}
516
517impl<T> CtOption<&T> {
518    /// Maps a `CtOption<&T>` to `CtOption<T>` by copying the contents of the option.
519    #[must_use = "`self` will be dropped if the result is not used"]
520    pub const fn copied(self) -> CtOption<T>
521    where
522        T: Copy,
523    {
524        CtOption {
525            value: *self.value,
526            is_some: self.is_some,
527        }
528    }
529
530    /// Maps a `CtOption<&T>` to `CtOption<T>` by cloning the contents of the option.
531    #[must_use = "`self` will be dropped if the result is not used"]
532    pub fn cloned(self) -> CtOption<T>
533    where
534        T: Clone,
535    {
536        CtOption {
537            value: self.value.clone(),
538            is_some: self.is_some,
539        }
540    }
541}
542
543impl<T> CtOption<&mut T> {
544    /// Maps a `CtOption<&mut T>` to `CtOption<T>` by copying the contents of the option.
545    #[must_use = "`self` will be dropped if the result is not used"]
546    pub const fn copied(self) -> CtOption<T>
547    where
548        T: Copy,
549    {
550        CtOption {
551            value: *self.value,
552            is_some: self.is_some,
553        }
554    }
555
556    /// Maps a `CtOption<&mut T>` to `CtOption<T>` by cloning the contents of the option.
557    #[must_use = "`self` will be dropped if the result is not used"]
558    pub fn cloned(self) -> CtOption<T>
559    where
560        T: Clone,
561    {
562        CtOption {
563            value: self.value.clone(),
564            is_some: self.is_some,
565        }
566    }
567}
568
569impl<T: CtAssign> CtAssign for CtOption<T> {
570    fn ct_assign(&mut self, other: &Self, choice: Choice) {
571        self.value.ct_assign(&other.value, choice);
572        self.is_some.ct_assign(&other.is_some, choice);
573    }
574}
575impl<T: CtAssign> CtAssignSlice for CtOption<T> {}
576
577impl<T: CtEq> CtEq for CtOption<T> {
578    #[inline]
579    fn ct_eq(&self, other: &CtOption<T>) -> Choice {
580        (self.is_some & other.is_some & self.value.ct_eq(&other.value))
581            | (self.is_none() & other.is_none())
582    }
583}
584
585impl<T: CtEq> CtEqSlice for CtOption<T> {}
586
587impl<T: CtSelect> CtSelect for CtOption<T> {
588    fn ct_select(&self, other: &Self, choice: Choice) -> Self {
589        Self {
590            value: self.value.ct_select(&other.value, choice),
591            is_some: self.is_some.ct_select(&other.is_some, choice),
592        }
593    }
594}
595
596impl<T: Default> Default for CtOption<T> {
597    fn default() -> Self {
598        Self::none()
599    }
600}
601
602/// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
603/// [`CtOption::is_some`] is a truthy or falsy [`Choice`].
604///
605/// <div class="warning">
606/// <b>Warning: variable-time!</b>
607///
608/// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
609/// `T` value since the `Option` will do it anyway.
610/// </div>
611impl<T> From<CtOption<T>> for Option<T> {
612    fn from(src: CtOption<T>) -> Option<T> {
613        src.into_option()
614    }
615}
616
617/// NOTE: in order to be able to unwrap the `subtle::CtOption` we rely on a `Default` bound in
618/// order to have a placeholder value, and `ConditionallySelectable` to be able to use `unwrap_or`.
619#[cfg(feature = "subtle")]
620impl<T> From<subtle::CtOption<T>> for CtOption<T>
621where
622    T: subtle::ConditionallySelectable + Default,
623{
624    #[inline]
625    fn from(src: subtle::CtOption<T>) -> CtOption<T> {
626        let is_some = src.is_some();
627        CtOption {
628            value: src.unwrap_or(Default::default()),
629            is_some: is_some.into(),
630        }
631    }
632}
633
634#[cfg(feature = "subtle")]
635impl<T> From<CtOption<T>> for subtle::CtOption<T> {
636    #[inline]
637    fn from(src: CtOption<T>) -> subtle::CtOption<T> {
638        subtle::CtOption::new(src.value, src.is_some.into())
639    }
640}
641
642#[cfg(feature = "subtle")]
643impl<T> subtle::ConditionallySelectable for CtOption<T>
644where
645    T: Copy, // `ConditionallySelectable` supertrait bound
646    Self: CtSelect,
647{
648    #[inline]
649    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
650        CtSelect::ct_select(a, b, choice.into())
651    }
652}
653
654#[cfg(feature = "subtle")]
655impl<T> subtle::ConstantTimeEq for CtOption<T>
656where
657    Self: CtEq,
658{
659    #[inline]
660    fn ct_eq(&self, other: &Self) -> subtle::Choice {
661        CtEq::ct_eq(self, other).into()
662    }
663}
664
665#[cfg(test)]
666mod tests {
667    use crate::{Choice, CtEq, CtOption, CtSelect};
668
669    /// Example wrapped value for testing
670    const VALUE: u8 = 42;
671
672    /// Example option which is like `Option::Some`
673    const SOME: CtOption<u8> = CtOption::new(VALUE, Choice::TRUE);
674
675    /// Example option which is like `Option::None`
676    const NONE: CtOption<u8> = CtOption::new(VALUE, Choice::FALSE);
677
678    /// Another option containing a different value
679    const OTHER: CtOption<u8> = CtOption::new(VALUE + 1, Choice::TRUE);
680
681    /// Dummy error type
682    #[derive(Debug, Eq, PartialEq)]
683    struct Error;
684
685    #[test]
686    fn map_macro() {
687        assert!(map!(NONE, u16::from).is_none().to_bool());
688        assert_eq!(map!(SOME, u16::from).unwrap(), u16::from(VALUE));
689    }
690
691    #[test]
692    fn unwrap_or_macro() {
693        // Don't actually use this! It's just a test function implemented in variable-time
694        #[allow(clippy::trivially_copy_pass_by_ref)]
695        const fn select_vartime(a: &u8, b: &u8, choice: Choice) -> u8 {
696            if choice.to_bool_vartime() { *b } else { *a }
697        }
698
699        assert_eq!(
700            unwrap_or!(NONE, OTHER.unwrap(), select_vartime),
701            OTHER.unwrap()
702        );
703        assert_eq!(unwrap_or!(SOME, OTHER.unwrap(), select_vartime), VALUE);
704    }
705
706    #[test]
707    fn ct_eq() {
708        assert!(NONE.ct_eq(&NONE).to_bool());
709        assert!(NONE.ct_ne(&SOME).to_bool());
710        assert!(SOME.ct_ne(&NONE).to_bool());
711        assert!(SOME.ct_eq(&SOME).to_bool());
712        assert!(SOME.ct_ne(&OTHER).to_bool());
713    }
714
715    #[test]
716    fn ct_select() {
717        assert!(NONE.ct_select(&SOME, Choice::FALSE).is_none().to_bool());
718        assert!(NONE.ct_select(&SOME, Choice::TRUE).ct_eq(&SOME).to_bool());
719        assert!(SOME.ct_select(&NONE, Choice::FALSE).ct_eq(&SOME).to_bool());
720        assert!(SOME.ct_select(&NONE, Choice::TRUE).is_none().to_bool());
721    }
722
723    #[test]
724    fn default() {
725        assert!(NONE.ct_eq(&CtOption::default()).to_bool());
726    }
727
728    #[test]
729    fn expect_some() {
730        assert_eq!(SOME.expect("should succeed"), VALUE);
731    }
732
733    #[test]
734    #[should_panic]
735    fn expect_none() {
736        let _ = NONE.expect("should panic");
737    }
738
739    #[test]
740    fn into_option() {
741        assert_eq!(SOME.into_option(), Some(VALUE));
742        assert_eq!(NONE.into_option(), None);
743    }
744
745    #[test]
746    fn into_option_copied() {
747        assert_eq!(SOME.into_option_copied(), Some(VALUE));
748        assert_eq!(NONE.into_option_copied(), None);
749    }
750
751    #[test]
752    fn is_some() {
753        assert!(SOME.is_some().to_bool());
754        assert!(!NONE.is_some().to_bool());
755    }
756
757    #[test]
758    fn is_none() {
759        assert!(!SOME.is_none().to_bool());
760        assert!(NONE.is_none().to_bool());
761    }
762
763    #[test]
764    fn and() {
765        assert!(SOME.and(NONE).is_none().to_bool());
766        assert_eq!(SOME.and(OTHER).unwrap(), OTHER.unwrap());
767    }
768
769    #[test]
770    fn and_then() {
771        assert!(NONE.and_then(|_| NONE).is_none().to_bool());
772        assert!(NONE.and_then(|_| SOME).is_none().to_bool());
773
774        let ret = SOME.and_then(|value| {
775            assert_eq!(VALUE, value);
776            OTHER
777        });
778        assert!(ret.ct_eq(&OTHER).to_bool());
779    }
780
781    #[test]
782    fn filter() {
783        assert!(NONE.filter(|_| Choice::TRUE).ct_eq(&NONE).to_bool());
784        assert!(NONE.filter(|_| Choice::FALSE).ct_eq(&NONE).to_bool());
785        assert!(SOME.filter(|_| Choice::FALSE).ct_eq(&NONE).to_bool());
786
787        let ret = SOME.filter(|&value| {
788            assert_eq!(VALUE, value);
789            Choice::TRUE
790        });
791        assert_eq!(ret.unwrap(), VALUE);
792    }
793
794    #[test]
795    fn filter_by() {
796        assert!(NONE.filter_by(Choice::FALSE).is_none().to_bool());
797        assert!(NONE.filter_by(Choice::TRUE).is_none().to_bool());
798        assert!(SOME.filter_by(Choice::FALSE).ct_eq(&NONE).to_bool());
799        assert_eq!(SOME.filter_by(Choice::TRUE).unwrap(), VALUE);
800    }
801
802    #[test]
803    fn insert() {
804        let mut example = NONE;
805        assert!(example.is_none().to_bool());
806
807        let ret = example.insert(42);
808        assert_eq!(ret, &42);
809        assert!(example.is_some().to_bool());
810    }
811
812    #[test]
813    fn insert_if() {
814        let mut example = NONE;
815        assert!(example.is_none().to_bool());
816
817        example.insert_if(&42, Choice::FALSE);
818        assert!(example.is_none().to_bool());
819
820        example.insert_if(&42, Choice::TRUE);
821        assert_eq!(example.unwrap(), 42);
822    }
823
824    #[test]
825    fn map() {
826        assert!(NONE.map(|value| value + 1).ct_eq(&NONE).to_bool());
827        assert!(SOME.map(|value| value + 1).ct_eq(&OTHER).to_bool());
828    }
829
830    #[test]
831    fn map_or() {
832        let example = 52;
833        assert_eq!(NONE.map_or(example, |value| value + 1), example);
834        assert_eq!(SOME.map_or(example, |value| value + 1), VALUE + 1);
835    }
836
837    #[test]
838    fn map_or_default() {
839        assert_eq!(NONE.map_or_default(|value| value + 1), Default::default());
840        assert_eq!(SOME.map_or_default(|value| value + 1), VALUE + 1);
841    }
842
843    #[test]
844    fn ok_or() {
845        assert_eq!(NONE.ok_or(Error), Err(Error));
846        assert_eq!(SOME.ok_or(Error), Ok(VALUE));
847    }
848
849    #[test]
850    fn ok_or_else() {
851        assert_eq!(NONE.ok_or_else(|| Error), Err(Error));
852        assert_eq!(SOME.ok_or_else(|| Error), Ok(VALUE));
853    }
854
855    #[test]
856    fn or() {
857        assert!(NONE.or(NONE).is_none().to_bool());
858        assert!(SOME.or(NONE).ct_eq(&SOME).to_bool());
859        assert!(NONE.or(SOME).ct_eq(&SOME).to_bool());
860        assert!(SOME.or(OTHER).ct_eq(&SOME).to_bool());
861    }
862
863    #[test]
864    fn some() {
865        assert!(CtOption::some(VALUE).ct_eq(&SOME).to_bool());
866    }
867
868    #[test]
869    fn unwrap_some() {
870        assert_eq!(SOME.unwrap(), VALUE);
871    }
872
873    #[test]
874    #[should_panic]
875    fn unwrap_none() {
876        let _ = NONE.unwrap();
877    }
878
879    #[test]
880    fn unwrap_or() {
881        let example = 52;
882        assert_eq!(NONE.unwrap_or(example), example);
883        assert_eq!(SOME.unwrap_or(example), VALUE);
884    }
885
886    #[test]
887    fn unwrap_or_default() {
888        assert_eq!(NONE.unwrap_or_default(), Default::default());
889        assert_eq!(SOME.unwrap_or_default(), VALUE);
890    }
891
892    #[test]
893    fn xor() {
894        assert!(NONE.xor(NONE).is_none().to_bool());
895        assert!(SOME.xor(NONE).ct_eq(&SOME).to_bool());
896        assert!(NONE.xor(SOME).ct_eq(&SOME).to_bool());
897        assert!(SOME.xor(OTHER).is_none().to_bool());
898    }
899
900    #[test]
901    fn zip() {
902        assert!(NONE.zip(NONE).is_none().to_bool());
903        assert!(NONE.zip(SOME).is_none().to_bool());
904        assert!(SOME.zip(NONE).is_none().to_bool());
905        assert_eq!(SOME.zip(OTHER).unwrap(), (SOME.unwrap(), OTHER.unwrap()));
906    }
907
908    #[test]
909    fn zip_with() {
910        assert!(NONE.zip_with(NONE, |a, b| a + b).is_none().to_bool());
911        assert!(NONE.zip_with(SOME, |a, b| a + b).is_none().to_bool());
912        assert!(SOME.zip_with(NONE, |a, b| a + b).is_none().to_bool());
913        assert_eq!(
914            SOME.zip_with(OTHER, |a, b| a + b).unwrap(),
915            SOME.unwrap() + OTHER.unwrap()
916        );
917    }
918}