11use crate :: { Choice , CtEq , CtSelect } ;
22use core:: ops:: { Deref , DerefMut } ;
33
4+ /// Helper macro for providing behavior like the [`CtOption::map`] combinator that works in
5+ /// `const fn` contexts.
6+ ///
7+ /// Requires a provided mapping function to convert from one type to another.
8+ #[ macro_export]
9+ macro_rules! map {
10+ ( $opt: expr, $mapper: path) => { { $crate:: CtOption :: new( $mapper( $opt. to_inner_unchecked( ) ) , $opt. is_some( ) ) } } ;
11+ }
12+
13+ /// Helper macro for providing behavior like the [`CtOption::`unwrap_or`] combinator that works in
14+ /// `const fn` contexts.
15+ ///
16+ /// Requires a provided selector function to do the constant-time selection.
17+ #[ macro_export]
18+ macro_rules! unwrap_or {
19+ ( $opt: expr, $default: expr, $select: path) => {
20+ $select( & $default, $opt. as_inner_unchecked( ) , $opt. is_some( ) )
21+ } ;
22+ }
23+
424/// Equivalent of [`Option`] but predicated on a [`Choice`] with combinators that allow for
525/// constant-time operations which always perform the same sequence of instructions regardless of
626/// the value of `is_some`.
@@ -23,6 +43,21 @@ impl<T> CtOption<T> {
2343 Self { value, is_some }
2444 }
2545
46+ /// Construct a new [`CtOption`] where `self.is_some()` is [`Choice::TRUE`].
47+ #[ inline]
48+ pub const fn some ( value : T ) -> CtOption < T > {
49+ Self :: new ( value, Choice :: TRUE )
50+ }
51+
52+ /// Construct a new [`CtOption`] with the [`Default`] value, and where `self.is_some()` is
53+ /// [`Choice::FALSE`].
54+ pub fn none ( ) -> CtOption < T >
55+ where
56+ T : Default ,
57+ {
58+ Self :: new ( Default :: default ( ) , Choice :: FALSE )
59+ }
60+
2661 /// Convert from a `&mut CtOption<T>` to `CtOption<&mut T>`.
2762 #[ inline]
2863 pub const fn as_mut ( & mut self ) -> CtOption < & mut T > {
@@ -80,7 +115,7 @@ impl<T> CtOption<T> {
80115 // (needs `const_precise_live_drops`)
81116 #[ inline]
82117 #[ track_caller]
83- pub const fn expect_copied ( & self , msg : & str ) -> T
118+ pub const fn expect_copied ( self , msg : & str ) -> T
84119 where
85120 T : Copy ,
86121 {
@@ -99,7 +134,7 @@ impl<T> CtOption<T> {
99134 pub const fn expect_ref ( & self , msg : & str ) -> & T {
100135 // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
101136 assert ! ( self . is_some. to_bool_vartime( ) , "{}" , msg) ;
102- & self . value
137+ self . as_inner_unchecked ( )
103138 }
104139
105140 /// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
@@ -124,6 +159,29 @@ impl<T> CtOption<T> {
124159 }
125160 }
126161
162+ /// Convert the [`CtOption`] wrapper into an [`Option`] in a `const fn`-friendly manner.
163+ ///
164+ /// This is the equivalent of [`CtOption::into_option`] but is `const fn`-friendly by only
165+ /// allowing `Copy` types which are implicitly `!Drop` and don't run into problems with
166+ /// `const fn` and destructors.
167+ ///
168+ /// <div class="warning">
169+ /// This implementation doesn't intend to be constant-time nor try to protect the leakage of the
170+ /// `T` value since the [`Option`] will do it anyway.
171+ /// </div>
172+ #[ inline]
173+ pub const fn into_option_copied ( self ) -> Option < T >
174+ where
175+ T : Copy ,
176+ {
177+ // TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
178+ if self . is_some . to_bool_vartime ( ) {
179+ Some ( self . value )
180+ } else {
181+ None
182+ }
183+ }
184+
127185 /// Returns [`Choice::TRUE`] if the option is the equivalent of a `Some`.
128186 #[ inline]
129187 #[ must_use]
@@ -146,6 +204,13 @@ impl<T> CtOption<T> {
146204 optb
147205 }
148206
207+ /// Apply an additional [`Choice`] requirement to `is_some`.
208+ #[ inline]
209+ pub const fn and_choice ( mut self , is_some : Choice ) -> Self {
210+ self . is_some = self . is_some . and ( is_some) ;
211+ self
212+ }
213+
149214 /// Calls the provided callback with the wrapped inner value, returning the resulting
150215 /// [`CtOption`] value in the event that `self.is_some()` is [`Choice::TRUE`], or if not
151216 /// returns a [`CtOption`] with `self.is_none()`.
@@ -164,6 +229,24 @@ impl<T> CtOption<T> {
164229 ret
165230 }
166231
232+ /// Obtain a reference to the inner value without first checking that `self.is_some()` is
233+ /// [`Choice::TRUE`].
234+ ///
235+ /// This method is primarily intended for use in `const fn` scenarios where it's not yet
236+ /// possible to use the safe combinator methods, and returns a reference to avoid issues with
237+ /// `const fn` destructors.
238+ ///
239+ /// <div class="warning">
240+ /// <b>Use with care!</b>
241+ ///
242+ /// This method does not ensure the `value` is actually valid. Callers of this method should
243+ /// take great care to ensure that `self.is_some()` is checked elsewhere.
244+ /// </div>
245+ #[ inline]
246+ pub const fn as_inner_unchecked ( & self ) -> & T {
247+ & self . value
248+ }
249+
167250 /// Calls the provided callback with the wrapped inner value, which computes a [`Choice`],
168251 /// and updates `self.is_some()`.
169252 ///
@@ -247,6 +330,27 @@ impl<T> CtOption<T> {
247330 }
248331 }
249332
333+ /// Obtain a copy of the inner value without first checking that `self.is_some()` is
334+ /// [`Choice::TRUE`].
335+ ///
336+ /// This method is primarily intended for use in `const fn` scenarios where it's not yet
337+ /// possible to use the safe combinator methods, and uses a `Copy` bound to avoid issues with
338+ /// `const fn` destructors.
339+ ///
340+ /// <div class="warning">
341+ /// <b>Use with care!</b>
342+ ///
343+ /// This method does not ensure the `value` is actually valid. Callers of this method should
344+ /// take great care to ensure that `self.is_some()` is checked elsewhere.
345+ /// </div>
346+ #[ inline]
347+ pub const fn to_inner_unchecked ( self ) -> T
348+ where
349+ T : Copy ,
350+ {
351+ self . value
352+ }
353+
250354 /// Return the contained value, consuming the `self` value.
251355 ///
252356 /// Use of this function is discouraged due to panic potential. Instead, prefer non-panicking
@@ -400,6 +504,12 @@ impl<T: CtSelect> CtSelect for CtOption<T> {
400504 }
401505}
402506
507+ impl < T : Default > Default for CtOption < T > {
508+ fn default ( ) -> Self {
509+ Self :: none ( )
510+ }
511+ }
512+
403513/// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
404514/// [`CtOption::is_some`] is a truthy or falsy [`Choice`].
405515///
@@ -460,6 +570,26 @@ mod tests {
460570 #[ derive( Debug , Eq , PartialEq ) ]
461571 struct Error ;
462572
573+ #[ test]
574+ fn map_macro ( ) {
575+ assert ! ( map!( NONE , u16 :: from) . is_none( ) . to_bool( ) ) ;
576+ assert_eq ! ( map!( SOME , u16 :: from) . unwrap( ) , VALUE as u16 ) ;
577+ }
578+
579+ #[ test]
580+ fn unwrap_or_macro ( ) {
581+ // Don't actually use this! It's just a test function implemented in variable-time
582+ const fn select_vartime ( a : & u8 , b : & u8 , choice : Choice ) -> u8 {
583+ if choice. to_bool_vartime ( ) { * b } else { * a }
584+ }
585+
586+ assert_eq ! (
587+ unwrap_or!( NONE , OTHER . unwrap( ) , select_vartime) ,
588+ OTHER . unwrap( )
589+ ) ;
590+ assert_eq ! ( unwrap_or!( SOME , OTHER . unwrap( ) , select_vartime) , VALUE ) ;
591+ }
592+
463593 #[ test]
464594 fn ct_eq ( ) {
465595 assert ! ( NONE . ct_eq( & NONE ) . to_bool( ) ) ;
0 commit comments