Skip to content

Commit

Permalink
Add const_assert_eq! and const_assert_ne! macros (#293)
Browse files Browse the repository at this point in the history
Leverages some idiosyncrasies of the Rust type system to define macros
which can be used to make compile-time assertions about const generic
parameters, working around the "can't use generic parameters from outer
item" error which would occur if one simply used `assert_eq`/`assert_ne`
  • Loading branch information
tarcieri authored Nov 17, 2023
1 parent a79b330 commit 4838fd9
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
extern crate alloc;

#[macro_use]
mod nlimbs;
mod macros;

#[cfg(feature = "generic-array")]
mod array;
Expand Down
79 changes: 79 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Macro definitions which are a part of the public API.
/// Internal implementation detail of [`const_assert_eq`] and [`const_assert_ne`].
#[doc(hidden)]
#[macro_export]
macro_rules! const_assert_n {
($n:expr, $($arg:tt)*) => {{
// TODO(tarcieri): gensym a name so it's unique per invocation of the macro?
mod __const_assert {
pub(super) struct Assert<const N: usize>;

impl<const N: usize> Assert<N> {
pub(super) const ASSERT: () = assert!($($arg)*);
}
}

__const_assert::Assert::<$n>::ASSERT
}};
}

/// Const-friendly assertion that two values are equal.
///
/// ```
/// const _: () = crypto_bigint::const_assert_eq!(0, 0, "zero equals zero");
/// ```
#[macro_export]
macro_rules! const_assert_eq {
($left:expr, $right:expr $(,)?) => (
$crate::const_assert_n!($left, $left == $right)
);
($left:expr, $right:expr, $($arg:tt)+) => (
$crate::const_assert_n!($left, $left == $right, $($arg)+)
);
}

/// Const-friendly assertion that two values are NOT equal.
///
/// ```
/// const _: () = crypto_bigint::const_assert_ne!(0, 1, "zero is NOT equal to one");
/// ```
#[macro_export]
macro_rules! const_assert_ne {
($left:expr, $right:expr $(,)?) => (
$crate::const_assert_n!($left, $left != $right)
);
($left:expr, $right:expr, $($arg:tt)+) => (
$crate::const_assert_n!($left, $left != $right, $($arg)+)
);
}

/// Calculate the number of limbs required to represent the given number of bits.
// TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable
#[macro_export]
macro_rules! nlimbs {
($bits:expr) => {
$bits / $crate::Limb::BITS
};
}

#[cfg(test)]
mod tests {
#[cfg(target_pointer_width = "32")]
#[test]
fn nlimbs_for_bits_macro() {
assert_eq!(nlimbs!(64), 2);
assert_eq!(nlimbs!(128), 4);
assert_eq!(nlimbs!(192), 6);
assert_eq!(nlimbs!(256), 8);
}

#[cfg(target_pointer_width = "64")]
#[test]
fn nlimbs_for_bits_macro() {
assert_eq!(nlimbs!(64), 1);
assert_eq!(nlimbs!(128), 2);
assert_eq!(nlimbs!(192), 3);
assert_eq!(nlimbs!(256), 4);
}
}
29 changes: 0 additions & 29 deletions src/nlimbs.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/uint/modular/runtime_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ impl<const LIMBS: usize> zeroize::Zeroize for DynResidue<LIMBS> {
#[cfg(test)]
mod test {
use super::*;
use crate::nlimbs;

const LIMBS: usize = nlimbs!(64);

Expand Down

0 comments on commit 4838fd9

Please sign in to comment.