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}