ctutils/
ct_option.rs

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