Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 160 additions & 3 deletions ctutils/src/choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ impl Choice {

/// Create a new [`Choice`] from the given `u8` value, which MUST be either `0` or `1`.
///
/// <div class="warning">
/// <b>Potential panics and other misbehavior!</b>
///
/// This constructor panics in debug builds if the given value is not 0 or 1.
///
/// It mainly exists as a convenience for migrating code which previously used `subtle`, but
/// we may deprecate it in future releases.
///
/// Consider using a more specific non-panicking constructor, like [`Choice::from_u8_lsb`].
/// </div>
///
/// # Panics
/// - in `debug` builds, panics if the value is anything other than `0` or `1`.
// TODO(tarcieri): deprecate this in favor of non-panicking constructors?
Expand Down Expand Up @@ -160,12 +171,80 @@ impl Choice {
// `const fn` constructor methods
//

// i64

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub const fn from_i64_eq(x: i64, y: i64) -> Self {
Self::from_u64_nz(x as u64 ^ y as u64).not()
}

// u8

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub const fn from_u8_eq(x: u8, y: u8) -> Self {
Self::from_u8_nz(x ^ y).not()
}

/// Returns the truthy value if `x <= y` and the falsy value otherwise.
#[inline]
pub const fn from_u8_le(x: u8, y: u8) -> Self {
Self::from_u8_lsb(bitle!(x, y, u8::BITS))
}

/// Initialize from the least significant bit of a `u8`.
#[inline]
pub const fn from_u8_lsb(value: u8) -> Self {
Self(value & 0x1)
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
#[inline]
pub const fn from_u8_lt(x: u8, y: u8) -> Self {
Self::from_u8_lsb(bitlt!(x, y, u8::BITS))
}

/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
#[inline]
pub const fn from_u8_nz(value: u8) -> Self {
Self::from_u8_lsb(bitnz!(value, u8::BITS))
}

// u16

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub const fn from_u16_eq(x: u16, y: u16) -> Self {
Self::from_u16_nz(x ^ y).not()
}

/// Returns the truthy value if `x <= y` and the falsy value otherwise.
#[inline]
pub const fn from_u16_le(x: u16, y: u16) -> Self {
Self::from_u16_lsb(bitle!(x, y, u16::BITS))
}

/// Initialize from the least significant bit of a `u16`.
#[inline]
pub const fn from_u16_lsb(value: u16) -> Self {
Self((value & 0x1) as u8)
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
#[inline]
pub const fn from_u16_lt(x: u16, y: u16) -> Self {
Self::from_u16_lsb(bitlt!(x, y, u16::BITS))
}

/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
#[inline]
pub const fn from_u16_nz(value: u16) -> Self {
Self::from_u16_lsb(bitnz!(value, u16::BITS))
}

// u32

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub const fn from_u32_eq(x: u32, y: u32) -> Self {
Expand All @@ -181,7 +260,7 @@ impl Choice {
/// Initialize from the least significant bit of a `u32`.
#[inline]
pub const fn from_u32_lsb(value: u32) -> Self {
Self::new((value & 0x1) as u8)
Self((value & 0x1) as u8)
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
Expand All @@ -196,6 +275,8 @@ impl Choice {
Self::from_u32_lsb(bitnz!(value, u32::BITS))
}

// u64

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub const fn from_u64_eq(x: u64, y: u64) -> Self {
Expand All @@ -211,7 +292,7 @@ impl Choice {
/// Initialize from the least significant bit of a `u64`.
#[inline]
pub const fn from_u64_lsb(value: u64) -> Self {
Self::new((value & 0x1) as u8)
Self((value & 0x1) as u8)
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
Expand All @@ -226,6 +307,8 @@ impl Choice {
Self::from_u64_lsb(bitnz!(value, u64::BITS))
}

// u128

/// Returns the truthy value if `x == y`, and the falsy value otherwise.
#[inline]
pub const fn from_u128_eq(x: u128, y: u128) -> Self {
Expand All @@ -241,7 +324,7 @@ impl Choice {
/// Initialize from the least significant bit of a `u128`.
#[inline]
pub const fn from_u128_lsb(value: u128) -> Self {
Self::new((value & 1) as u8)
Self((value & 1) as u8)
}

/// Returns the truthy value if `x < y`, and the falsy value otherwise.
Expand Down Expand Up @@ -539,6 +622,80 @@ mod tests {
assert_eq!(Choice::from_i64_eq(1, 1), Choice::TRUE);
}

#[test]
fn from_u8_eq() {
assert_eq!(Choice::from_u8_eq(0, 1), Choice::FALSE);
assert_eq!(Choice::from_u8_eq(1, 1), Choice::TRUE);
}

#[test]
fn from_u8_le() {
assert_eq!(Choice::from_u8_le(0, 0), Choice::TRUE);
assert_eq!(Choice::from_u8_le(1, 0), Choice::FALSE);
assert_eq!(Choice::from_u8_le(1, 1), Choice::TRUE);
assert_eq!(Choice::from_u8_le(1, 2), Choice::TRUE);
}

#[test]
fn from_u8_lsb() {
assert_eq!(Choice::from_u8_lsb(0), Choice::FALSE);
assert_eq!(Choice::from_u8_lsb(1), Choice::TRUE);
assert_eq!(Choice::from_u8_lsb(2), Choice::FALSE);
assert_eq!(Choice::from_u8_lsb(3), Choice::TRUE);
}

#[test]
fn from_u8_lt() {
assert_eq!(Choice::from_u8_lt(0, 0), Choice::FALSE);
assert_eq!(Choice::from_u8_lt(1, 0), Choice::FALSE);
assert_eq!(Choice::from_u8_lt(1, 1), Choice::FALSE);
assert_eq!(Choice::from_u8_lt(1, 2), Choice::TRUE);
}

#[test]
fn from_u8_nz() {
assert_eq!(Choice::from_u8_nz(0), Choice::FALSE);
assert_eq!(Choice::from_u8_nz(1), Choice::TRUE);
assert_eq!(Choice::from_u8_nz(2), Choice::TRUE);
}

#[test]
fn from_u16_eq() {
assert_eq!(Choice::from_u16_eq(0, 1), Choice::FALSE);
assert_eq!(Choice::from_u16_eq(1, 1), Choice::TRUE);
}

#[test]
fn from_u16_le() {
assert_eq!(Choice::from_u16_le(0, 0), Choice::TRUE);
assert_eq!(Choice::from_u16_le(1, 0), Choice::FALSE);
assert_eq!(Choice::from_u16_le(1, 1), Choice::TRUE);
assert_eq!(Choice::from_u16_le(1, 2), Choice::TRUE);
}

#[test]
fn from_u16_lsb() {
assert_eq!(Choice::from_u16_lsb(0), Choice::FALSE);
assert_eq!(Choice::from_u16_lsb(1), Choice::TRUE);
assert_eq!(Choice::from_u16_lsb(2), Choice::FALSE);
assert_eq!(Choice::from_u16_lsb(3), Choice::TRUE);
}

#[test]
fn from_u16_lt() {
assert_eq!(Choice::from_u16_lt(0, 0), Choice::FALSE);
assert_eq!(Choice::from_u16_lt(1, 0), Choice::FALSE);
assert_eq!(Choice::from_u16_lt(1, 1), Choice::FALSE);
assert_eq!(Choice::from_u16_lt(1, 2), Choice::TRUE);
}

#[test]
fn from_u16_nz() {
assert_eq!(Choice::from_u16_nz(0), Choice::FALSE);
assert_eq!(Choice::from_u16_nz(1), Choice::TRUE);
assert_eq!(Choice::from_u16_nz(2), Choice::TRUE);
}

#[test]
fn from_u32_eq() {
assert_eq!(Choice::from_u32_eq(0, 1), Choice::FALSE);
Expand Down