From 28ba2633690be43d6df73c5e76c2c2fbc784a372 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 17 Jan 2026 22:25:20 -0700 Subject: [PATCH] ctutils: add `CtSelectUsingCtAssign` Adds a marker trait bounded on `Clone + CtAssign` which writes a blanket impl of `CtSelect` by cloning `self` and then performing `CtAssign`. The blanket impl is used to replace all of the repeat occurrences in this crate alone, including the `impl_ct_select_with_ct_assign!` macro. --- ctutils/src/lib.rs | 2 +- ctutils/src/traits/ct_assign.rs | 4 -- ctutils/src/traits/ct_select.rs | 73 ++++++++++----------------------- 3 files changed, 23 insertions(+), 56 deletions(-) diff --git a/ctutils/src/lib.rs b/ctutils/src/lib.rs index 8170e40c..3c11a82a 100644 --- a/ctutils/src/lib.rs +++ b/ctutils/src/lib.rs @@ -110,5 +110,5 @@ pub use traits::{ ct_lookup::CtLookup, ct_lt::CtLt, ct_neg::CtNeg, - ct_select::{CtSelect, CtSelectArray}, + ct_select::{CtSelect, CtSelectArray, CtSelectUsingCtAssign}, }; diff --git a/ctutils/src/traits/ct_assign.rs b/ctutils/src/traits/ct_assign.rs index 96f14e62..d315c476 100644 --- a/ctutils/src/traits/ct_assign.rs +++ b/ctutils/src/traits/ct_assign.rs @@ -95,10 +95,6 @@ impl CtAssignSlice for isize {} impl CtAssignSlice for usize {} /// Impl `CtAssign` using the `CtSelect` trait. -/// -/// In cases where `CtSelect` is more straightforward to implement, but you want to use a provided -/// implementation of `CtAssign` based on it, you can use this macro to write it for you. -#[macro_export] macro_rules! impl_ct_assign_with_ct_select { ( $($ty:ty),+ ) => { $( diff --git a/ctutils/src/traits/ct_select.rs b/ctutils/src/traits/ct_select.rs index 55b2e045..46375683 100644 --- a/ctutils/src/traits/ct_select.rs +++ b/ctutils/src/traits/ct_select.rs @@ -10,10 +10,10 @@ use core::{ #[cfg(feature = "subtle")] use crate::CtOption; #[cfg(feature = "alloc")] -use alloc::{boxed::Box, vec::Vec}; - -#[cfg(doc)] -use crate::CtAssignSlice; +use { + crate::CtAssignSlice, + alloc::{boxed::Box, vec::Vec}, +}; /// Constant-time selection: choose between two values based on a given [`Choice`]. /// @@ -79,26 +79,22 @@ where } } -/// Impl `CtSelect` using the `CtAssign` trait. -/// -/// In cases where `CtAssign` is more straightforward to implement, but you want to use a provided -/// implementation of `CtSelect` based on it, you can use this macro to write it for you. -/// -/// Requires the provided type(s) impl `Clone`. -#[macro_export] +/// Marker trait which enables a blanket impl of [`CtSelect`] for types which also impl +/// [`Clone`] + [`CtAssign`]. +pub trait CtSelectUsingCtAssign: Clone + CtAssign {} + +impl CtSelect for T { + #[inline] + fn ct_select(&self, other: &Self, choice: Choice) -> Self { + let mut ret = self.clone(); + ret.ct_assign(other, choice); + ret + } +} + +/// Macro to write impls of `CtSelectUsingCtAssign`. macro_rules! impl_ct_select_with_ct_assign { - ( $($ty:ty),+ ) => { - $( - impl CtSelect for $ty { - #[inline] - fn ct_select(&self, other: &Self, choice: Choice) -> Self { - let mut ret = self.clone(); - ret.ct_assign(other, choice); - ret - } - } - )+ - }; + ( $($ty:ty),+ ) => { $(impl CtSelectUsingCtAssign for $ty {})+ }; } impl_ct_select_with_ct_assign!( @@ -159,43 +155,18 @@ impl CtSelect for cmp::Ordering { } #[cfg(feature = "alloc")] -impl CtSelect for Box -where - T: CtSelect, -{ - #[inline] - fn ct_select(&self, other: &Self, choice: Choice) -> Self { - Box::new(T::ct_select(&**self, &**other, choice)) - } -} +impl CtSelectUsingCtAssign for Box {} #[cfg(feature = "alloc")] -impl CtSelect for Box<[T]> +impl CtSelectUsingCtAssign for Box<[T]> where T: Clone, [T]: CtAssign, { - #[inline] - fn ct_select(&self, other: &Self, choice: Choice) -> Self { - let mut ret = self.clone(); - ret.ct_assign(other, choice); - ret - } } #[cfg(feature = "alloc")] -impl CtSelect for Vec -where - T: Clone, - [T]: CtAssign, -{ - #[inline] - fn ct_select(&self, other: &Self, choice: Choice) -> Self { - let mut ret = self.clone(); - ret.ct_assign(other, choice); - ret - } -} +impl CtSelectUsingCtAssign for Vec {} #[cfg(feature = "subtle")] impl CtSelect for subtle::Choice {