11use crate :: { Choice , CtEq , CtSelect } ;
22use core:: ops:: { Deref , DerefMut } ;
33
4+ /// Helper macro for providing behavior like the `unwrap_or` combinator that works in a `const fn`
5+ /// context.
6+ ///
7+ /// Requires a provided selector function to do the constant-time selection.
8+ #[ macro_export]
9+ macro_rules! unwrap_or {
10+ ( $opt: expr, $default: expr, $select: path) => {
11+ $select( & $default, $opt. as_inner_unchecked( ) , $opt. is_some( ) )
12+ } ;
13+ }
14+
415/// Equivalent of [`Option`] but predicated on a [`Choice`] with combinators that allow for
516/// constant-time operations which always perform the same sequence of instructions regardless of
617/// the value of `is_some`.
@@ -23,6 +34,21 @@ impl<T> CtOption<T> {
2334 Self { value, is_some }
2435 }
2536
37+ /// Construct a new [`CtOption`] where `self.is_some()` is [`Choice::TRUE`].
38+ #[ inline]
39+ pub const fn some ( value : T ) -> CtOption < T > {
40+ Self :: new ( value, Choice :: TRUE )
41+ }
42+
43+ /// Construct a new [`CtOption`] with the [`Default`] value, and where `self.is_some()` is
44+ /// [`Choice::FALSE`].
45+ pub fn none ( ) -> CtOption < T >
46+ where
47+ T : Default ,
48+ {
49+ Self :: new ( Default :: default ( ) , Choice :: FALSE )
50+ }
51+
2652 /// Convert from a `&mut CtOption<T>` to `CtOption<&mut T>`.
2753 #[ inline]
2854 pub const fn as_mut ( & mut self ) -> CtOption < & mut T > {
@@ -80,7 +106,7 @@ impl<T> CtOption<T> {
80106 // (needs `const_precise_live_drops`)
81107 #[ inline]
82108 #[ track_caller]
83- pub const fn expect_copied ( & self , msg : & str ) -> T
109+ pub const fn expect_copied ( self , msg : & str ) -> T
84110 where
85111 T : Copy ,
86112 {
@@ -99,7 +125,7 @@ impl<T> CtOption<T> {
99125 pub const fn expect_ref ( & self , msg : & str ) -> & T {
100126 // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
101127 assert ! ( self . is_some. to_bool_vartime( ) , "{}" , msg) ;
102- & self . value
128+ self . as_inner_unchecked ( )
103129 }
104130
105131 /// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
@@ -124,6 +150,29 @@ impl<T> CtOption<T> {
124150 }
125151 }
126152
153+ /// Convert the [`CtOption`] wrapper into an [`Option`] in a `const fn`-friendly manner.
154+ ///
155+ /// This is the equivalent of [`CtOption::into_option`] but is `const fn`-friendly by only
156+ /// allowing `Copy` types which are implicitly `!Drop` and don't run into problems with
157+ /// `const fn` and destructors.
158+ ///
159+ /// <div class="warning">
160+ /// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
161+ /// `T` value since the [`Option`] will do it anyway.
162+ /// </div>
163+ #[ inline]
164+ pub const fn into_option_copied ( self ) -> Option < T >
165+ where
166+ T : Copy ,
167+ {
168+ // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
169+ if self . is_some . to_bool_vartime ( ) {
170+ Some ( self . value )
171+ } else {
172+ None
173+ }
174+ }
175+
127176 /// Returns [`Choice::TRUE`] if the option is the equivalent of a `Some`.
128177 #[ inline]
129178 #[ must_use]
@@ -146,6 +195,13 @@ impl<T> CtOption<T> {
146195 optb
147196 }
148197
198+ /// Apply an additional [`Choice`] requirement to `is_some`.
199+ #[ inline]
200+ pub const fn and_choice ( mut self , is_some : Choice ) -> Self {
201+ self . is_some = self . is_some . and ( is_some) ;
202+ self
203+ }
204+
149205 /// Calls the provided callback with the wrapped inner value, returning the resulting
150206 /// [`CtOption`] value in the event that `self.is_some()` is [`Choice::TRUE`], or if not
151207 /// returns a [`CtOption`] with `self.is_none()`.
@@ -164,6 +220,34 @@ impl<T> CtOption<T> {
164220 ret
165221 }
166222
223+ /// Obtain a reference to the inner value without first checking that `self.is_some()` is
224+ /// [`Choice::TRUE`].
225+ ///
226+ /// This method is primarily intended for use in `const fn` scenarios where it's not yet
227+ /// possible to use the safe combinator methods, and returns a reference to avoid issues with
228+ /// `const fn` destructors.
229+ ///
230+ /// <div class="warning">
231+ /// <b>Use with care!</b>
232+ ///
233+ /// This method does not ensure the `value` is actually valid. Callers of this method should
234+ /// take great care to ensure that `self.is_some()` is checked elsewhere.
235+ /// </div>
236+ #[ inline]
237+ pub const fn as_inner_unchecked ( & self ) -> & T {
238+ & self . value
239+ }
240+
241+ /// DEPRECATED: legacy compatibility method for `crypto-bigint`
242+ #[ inline]
243+ #[ deprecated( since = "0.1.1" , note = "use `as_inner_unchecked` instead" ) ]
244+ pub const fn components_ref ( & self ) -> ( & T , Choice ) {
245+ // Since Rust is not smart enough to tell that we would be moving the value,
246+ // and hence no destructors will be called, we have to return a reference instead.
247+ // See https://github.com/rust-lang/rust/issues/66753
248+ ( & self . value , self . is_some )
249+ }
250+
167251 /// Calls the provided callback with the wrapped inner value, which computes a [`Choice`],
168252 /// and updates `self.is_some()`.
169253 ///
@@ -247,6 +331,27 @@ impl<T> CtOption<T> {
247331 }
248332 }
249333
334+ /// Obtain a copy of the inner value without first checking that `self.is_some()` is
335+ /// [`Choice::TRUE`].
336+ ///
337+ /// This method is primarily intended for use in `const fn` scenarios where it's not yet
338+ /// possible to use the safe combinator methods, and uses a `Copy` bound to avoid issues with
339+ /// `const fn` destructors.
340+ ///
341+ /// <div class="warning">
342+ /// <b>Use with care!</b>
343+ ///
344+ /// This method does not ensure the `value` is actually valid. Callers of this method should
345+ /// take great care to ensure that `self.is_some()` is checked elsewhere.
346+ /// </div>
347+ #[ inline]
348+ pub const fn to_inner_unchecked ( self ) -> T
349+ where
350+ T : Copy ,
351+ {
352+ self . value
353+ }
354+
250355 /// Return the contained value, consuming the `self` value.
251356 ///
252357 /// Use of this function is discouraged due to panic potential. Instead, prefer non-panicking
@@ -400,6 +505,12 @@ impl<T: CtSelect> CtSelect for CtOption<T> {
400505 }
401506}
402507
508+ impl < T : Default > Default for CtOption < T > {
509+ fn default ( ) -> Self {
510+ Self :: none ( )
511+ }
512+ }
513+
403514/// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
404515/// [`CtOption::is_some`] is a truthy or falsy [`Choice`].
405516///
0 commit comments