182 lines
5.5 KiB
Rust
182 lines
5.5 KiB
Rust
macro_rules! signed_impls {
|
|
($sname: ident, $name: ident) => {
|
|
#[derive(Clone, PartialEq, Eq)]
|
|
pub struct $sname {
|
|
negative: bool,
|
|
value: $name
|
|
}
|
|
|
|
impl $sname {
|
|
/// Generate a new signed number from an unsigned number and a
|
|
/// boolean describing whether or not the new number is negative.
|
|
/// Note that if the value is zero, the value of the negative flag
|
|
/// will be ignored.
|
|
pub fn new(negative: bool, value: $name) -> $sname {
|
|
if value.is_zero() {
|
|
$sname{ negative: false, value: value }
|
|
} else {
|
|
$sname{ negative: negative, value: value }
|
|
}
|
|
}
|
|
|
|
/// Return a new number that is the negated version of this number.
|
|
pub fn negate(&self) -> $sname {
|
|
if self.value.is_zero() {
|
|
self.clone()
|
|
} else {
|
|
$sname{ negative: !self.negative, value: self.value.clone() }
|
|
}
|
|
}
|
|
|
|
/// Return the absolute value of the number.
|
|
pub fn abs(&self) -> $sname {
|
|
$sname{ negative: false, value: self.value.clone() }
|
|
}
|
|
|
|
/// Return true iff the value is negative and not zero.
|
|
pub fn is_negative(&self) -> bool {
|
|
self.negative
|
|
}
|
|
}
|
|
|
|
impl From<$sname> for $name {
|
|
fn from(x: $sname) -> $name {
|
|
x.value
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a $sname> for $name {
|
|
fn from(x: &$sname) -> $name {
|
|
x.value.clone()
|
|
}
|
|
}
|
|
|
|
impl From<$name> for $sname {
|
|
fn from(x: $name) -> $sname {
|
|
$sname{ negative: false, value: x }
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a $name> for $sname {
|
|
fn from(x: &$name) -> $sname {
|
|
$sname{ negative: false, value: x.clone() }
|
|
}
|
|
}
|
|
|
|
impl CryptoNum for $sname {
|
|
fn zero() -> $sname {
|
|
$sname{ negative: false, value: $name::zero() }
|
|
}
|
|
|
|
fn bit_length() -> usize {
|
|
$name::bit_length()
|
|
}
|
|
|
|
fn is_zero(&self) -> bool {
|
|
self.value.is_zero()
|
|
}
|
|
|
|
fn is_even(&self) -> bool {
|
|
self.value.is_even()
|
|
}
|
|
|
|
fn is_odd(&self) -> bool {
|
|
self.value.is_odd()
|
|
}
|
|
|
|
fn mask(&mut self, len: usize) {
|
|
self.value.mask(len);
|
|
}
|
|
|
|
fn testbit(&self, bit: usize) -> bool {
|
|
self.value.testbit(bit)
|
|
}
|
|
}
|
|
|
|
impl Arbitrary for $sname {
|
|
fn arbitrary<G>(g: &mut G) -> $sname
|
|
where G: Gen
|
|
{
|
|
let neg = bool::arbitrary(g);
|
|
let val = $name::arbitrary(g);
|
|
let neg2 = if val.is_zero() { false } else { neg };
|
|
$sname{ negative: neg2, value: val }
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for $sname {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
if self.negative {
|
|
f.write_str("-")?;
|
|
}
|
|
self.value.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl fmt::UpperHex for $sname {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
if self.negative {
|
|
write!(f, "-{:X}", self.value)
|
|
} else {
|
|
if f.sign_plus() {
|
|
write!(f, "+{:X}", self.value)
|
|
} else {
|
|
write!(f, "{:X}", self.value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::LowerHex for $sname {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
if self.negative {
|
|
write!(f, "-{:x}", self.value)
|
|
} else {
|
|
if f.sign_plus() {
|
|
write!(f, "+{:x}", self.value)
|
|
} else {
|
|
write!(f, "{:x}", self.value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
generate_base_conversions!($sname, $name);
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
macro_rules! generate_signed_tests
|
|
{
|
|
($sname: ident, $name: ident, $lname: ident) => {
|
|
#[test]
|
|
fn $lname() {
|
|
generate_signed_tests!(body $sname, $name, $lname);
|
|
}
|
|
};
|
|
(ignore $sname: ident, $name: ident, $lname: ident) => {
|
|
#[test]
|
|
#[ignore]
|
|
fn $lname() {
|
|
generate_signed_tests!(body $sname, $name, $lname);
|
|
}
|
|
};
|
|
(body $sname: ident, $name: ident, $lname: ident) => {
|
|
let fname = build_test_path("signed", stringify!($sname));
|
|
run_test(fname.to_string(), 4, |case| {
|
|
let (negx, xbytes) = case.get("x").unwrap();
|
|
let (neg0, zbytes) = case.get("z").unwrap();
|
|
let (neg1, ebytes) = case.get("e").unwrap();
|
|
let (neg2, obytes) = case.get("o").unwrap();
|
|
|
|
assert!(!neg0 && !neg1 && !neg2);
|
|
let x = $sname::new(*negx, $name::from_bytes(xbytes));
|
|
let z = 1 == zbytes[0];
|
|
let e = 1 == ebytes[0];
|
|
let o = 1 == obytes[0];
|
|
assert_eq!(x.is_zero(), z);
|
|
assert_eq!(x.is_even(), e);
|
|
assert_eq!(x.is_odd(), o);
|
|
});
|
|
}
|
|
} |