Skip to content
This repository has been archived by the owner on Nov 23, 2024. It is now read-only.

Commit

Permalink
feat: convenience: Implement PartialEq and PartialOrd between referen…
Browse files Browse the repository at this point in the history
…ces and non-references

The implementation just dereferences a reference, and calls another method.
  • Loading branch information
bgeron committed Apr 5, 2020
1 parent 514ad3b commit fbad1b6
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 27 deletions.
4 changes: 2 additions & 2 deletions examples/strange_prime_factorization/using_smallbigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn find_small_prime_factorization_str_works() {
}

fn find_small_prime_factorization(v: &Uint, small_prime_limit: &Uint) -> Option<Vec<Uint>> {
assert!(v >= &1);
assert!(v >= 1);
let mut current = v.clone();
let mut factors: Vec<Uint> = Vec::new();
while current != 1 {
Expand All @@ -59,7 +59,7 @@ fn find_small_prime_factor(v: &Uint, small_prime_limit: &Uint) -> Option<(Uint,
return Some((Uint::small(2), v / 2u8));
}
let mut cur_factor = Uint::small(3);
while cur_factor < *small_prime_limit {
while cur_factor < small_prime_limit {
if v % &cur_factor == 0 {
return Some((cur_factor.clone(), v / cur_factor));
}
Expand Down
107 changes: 82 additions & 25 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ impl Neg for &Int {
}
}

// -- Basic stuff between both same and different signedness --

impl Ord for Uint {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if let (Left(x), Left(y)) = (&self.0, &other.0) {
Expand Down Expand Up @@ -431,8 +433,6 @@ impl PartialOrd<Int> for Int {
}
}

// -- Basic stuff between both same and different signedness --

impl PartialOrd<Uint> for Int {
fn partial_cmp(&self, other: &Uint) -> Option<std::cmp::Ordering> {
self.partial_cmp(&Int::from(other.clone()))
Expand Down Expand Up @@ -493,6 +493,43 @@ impl PartialEq<Uint> for Int {
}
impl Eq for Int {}

macro_rules! impl_ref_variants {
// Here we implement stuff like
//
// - PartialEq<&i16> for Int
// - PartialEq<i16> for &Int
//
// so that you don't have to call the * operator yourself as much. But we
// don't implement PartialEq<&i16> for &Int because the generic implementation
// already takes care of that.
//
// These functions are very simple (a dereference and a function call), so it
// seems reasonable to suggest that they should be inlined.
($trait:tt, $method:tt, $selftype:ty, $othtype:ty, $resulttype:ty) => {
impl $trait<&$othtype> for $selftype {
#[inline]
fn $method(&self, other: &&$othtype) -> $resulttype {
self.$method(*other)
}
}
impl $trait<$othtype> for &$selftype {
#[inline]
fn $method(&self, other: &$othtype) -> $resulttype {
(*self).$method(other)
}
}
};
}

impl_ref_variants! { PartialEq, eq, Uint, Uint, bool }
impl_ref_variants! { PartialEq, eq, Int, Uint, bool }
impl_ref_variants! { PartialEq, eq, Uint, Int, bool }
impl_ref_variants! { PartialEq, eq, Int, Int, bool }
impl_ref_variants! { PartialOrd, partial_cmp, Uint, Uint, Option<Ordering> }
impl_ref_variants! { PartialOrd, partial_cmp, Int, Uint, Option<Ordering> }
impl_ref_variants! { PartialOrd, partial_cmp, Uint, Int, Option<Ordering> }
impl_ref_variants! { PartialOrd, partial_cmp, Int, Int, Option<Ordering> }

// -- Basic stuff between different signedness --

impl Uint {
Expand Down Expand Up @@ -1032,27 +1069,27 @@ macro_rules! call_with_all_unsigned_base_types {
// type = Int
// basetype = int (type alias for i32)
// bigtype = BigInt
macro_rules! call_with_ref_permutations {
macro_rules! call_with_cow_permutations {
($macroname_value:ident, $macroname_mut:ident, $type:tt, $basetype:tt, $bigtype:tt, both signed and unsigned) => {
call_with_ref_permutations!{$macroname_value, $macroname_mut, $type, $basetype, $bigtype, self case}
call_with_cow_permutations!{$macroname_value, $macroname_mut, $type, $basetype, $bigtype, self case}
call_with_all_signed_base_types!{
call_with_ref_permutations,
call_with_cow_permutations,
$macroname_value, $macroname_mut, $type, $basetype, $bigtype, base type
}
call_with_all_unsigned_base_types!{
call_with_ref_permutations,
call_with_cow_permutations,
$macroname_value, $macroname_mut, $type, $basetype, $bigtype, base type
}
};
($macroname_value:ident, $macroname_mut:ident, $type:tt, $basetype:tt, $bigtype:tt, only unsigned) => {
call_with_ref_permutations!{$macroname_value, $macroname_mut, $type, $basetype, $bigtype, self case}
call_with_cow_permutations!{$macroname_value, $macroname_mut, $type, $basetype, $bigtype, self case}
call_with_all_unsigned_base_types!{
call_with_ref_permutations,
call_with_cow_permutations,
$macroname_value, $macroname_mut, $type, $basetype, $bigtype, base type
}
};
($macroname_value:ident, $macroname_mut:ident, $type:tt, $basetype:tt, $bigtype:tt) => {
call_with_ref_permutations!{$macroname_value, $macroname_mut, $type, $basetype, $bigtype, self case}
call_with_cow_permutations!{$macroname_value, $macroname_mut, $type, $basetype, $bigtype, self case}
};

// Calls the implementing macros for a number of cases. For example for Add/AddAssign, this would
Expand Down Expand Up @@ -1157,8 +1194,8 @@ macro_rules! trait_add_mut {
};
}

call_with_ref_permutations! {trait_add_value, trait_add_mut, Int, int, BigInt, both signed and unsigned}
call_with_ref_permutations! {trait_add_value, trait_add_mut, Uint, uint, BigUint, only unsigned}
call_with_cow_permutations! {trait_add_value, trait_add_mut, Int, int, BigInt, both signed and unsigned}
call_with_cow_permutations! {trait_add_value, trait_add_mut, Uint, uint, BigUint, only unsigned}

macro_rules! trait_div_value {
($type:tt, $basetype:ty, $bigtype:ty, $selfvar:tt, $othvar:ident,
Expand Down Expand Up @@ -1191,8 +1228,8 @@ macro_rules! trait_div_mut {
};
}

call_with_ref_permutations! {trait_div_value, trait_div_mut, Int, int, BigInt, both signed and unsigned}
call_with_ref_permutations! {trait_div_value, trait_div_mut, Uint, uint, BigUint, only unsigned}
call_with_cow_permutations! {trait_div_value, trait_div_mut, Int, int, BigInt, both signed and unsigned}
call_with_cow_permutations! {trait_div_value, trait_div_mut, Uint, uint, BigUint, only unsigned}

macro_rules! trait_mul_value {
($type:tt, $basetype:ty, $bigtype:ty, $selfvar:tt, $othvar:ident,
Expand Down Expand Up @@ -1225,8 +1262,8 @@ macro_rules! trait_mul_mut {
};
}

call_with_ref_permutations! {trait_mul_value, trait_mul_mut, Int, int, BigInt, both signed and unsigned}
call_with_ref_permutations! {trait_mul_value, trait_mul_mut, Uint, uint, BigUint, only unsigned}
call_with_cow_permutations! {trait_mul_value, trait_mul_mut, Int, int, BigInt, both signed and unsigned}
call_with_cow_permutations! {trait_mul_value, trait_mul_mut, Uint, uint, BigUint, only unsigned}

macro_rules! trait_rem_value {
($type:tt, $basetype:ty, $bigtype:ty, $selfvar:tt, $othvar:ident,
Expand Down Expand Up @@ -1259,8 +1296,8 @@ macro_rules! trait_rem_mut {
};
}

call_with_ref_permutations! {trait_rem_value, trait_rem_mut, Int, int, BigInt, both signed and unsigned}
call_with_ref_permutations! {trait_rem_value, trait_rem_mut, Uint, uint, BigUint, only unsigned}
call_with_cow_permutations! {trait_rem_value, trait_rem_mut, Int, int, BigInt, both signed and unsigned}
call_with_cow_permutations! {trait_rem_value, trait_rem_mut, Uint, uint, BigUint, only unsigned}

macro_rules! trait_sub_value {
($type:tt, $basetype:ty, $bigtype:ty, $selfvar:tt, $othvar:ident,
Expand Down Expand Up @@ -1293,8 +1330,8 @@ macro_rules! trait_sub_mut {
};
}

call_with_ref_permutations! {trait_sub_value, trait_sub_mut, Int, int, BigInt, both signed and unsigned}
call_with_ref_permutations! {trait_sub_value, trait_sub_mut, Uint, uint, BigUint, only unsigned}
call_with_cow_permutations! {trait_sub_value, trait_sub_mut, Int, int, BigInt, both signed and unsigned}
call_with_cow_permutations! {trait_sub_value, trait_sub_mut, Uint, uint, BigUint, only unsigned}

// The checked traits are always a function from (&Self, &Self) to Option<Self>.
// We implement them by first trying them on the base type; if that works, falling
Expand Down Expand Up @@ -1353,7 +1390,7 @@ call_with_args! {checked_trait, {CheckedMul, checked_mul, }, [Uint, Int]}
call_with_args! {checked_trait, {CheckedSub, checked_sub, }, [Uint, Int]}

macro_rules! trait_partialeq {
($type:tt $basetype:ty) => {
(base, $type:tt, $basetype:ty) => {
// One way
impl PartialEq<$basetype> for $type {
fn eq(&self, other: &$basetype) -> bool {
Expand All @@ -1367,13 +1404,18 @@ macro_rules! trait_partialeq {
ToGeneric::<$basetype>::to_generic(other).map_or(false, |x| x.eq(self))
}
}

// These are just lazy variants so you don't have to do * yourself when
// one is a reference and one isn't.
impl_ref_variants! {PartialEq, eq, $type, $basetype, bool}
impl_ref_variants! {PartialEq, eq, $basetype, $type, bool}
};
}

call_with_all_unsigned_base_types!(trait_partialeq, Uint);
call_with_all_unsigned_base_types!(trait_partialeq, Int);
call_with_all_signed_base_types!(trait_partialeq, Uint);
call_with_all_signed_base_types!(trait_partialeq, Int);
call_with_all_unsigned_base_types!(trait_partialeq, base, Uint,);
call_with_all_unsigned_base_types!(trait_partialeq, base, Int,);
call_with_all_signed_base_types!(trait_partialeq, base, Uint,);
call_with_all_signed_base_types!(trait_partialeq, base, Int,);

macro_rules! trait_partialord_straight {
($type:tt $basetype:tt) => {
Expand Down Expand Up @@ -1405,6 +1447,9 @@ macro_rules! trait_partialord_straight {
other.partial_cmp(self).map(|ord| ord.reverse())
}
}

impl_ref_variants! {PartialOrd, partial_cmp, $type, $basetype, Option<Ordering>}
impl_ref_variants! {PartialOrd, partial_cmp, $basetype, $type, Option<Ordering>}
};
}

Expand All @@ -1415,12 +1460,14 @@ call_with_all_signed_base_types!(trait_partialord_straight, Int);

#[cfg(test)]
mod test {
#![allow(clippy::redundant_clone, clippy::cognitive_complexity)]
#![allow(clippy::redundant_clone, clippy::cognitive_complexity, clippy::op_ref)]
use super::*;
#[test]
fn test_unsigned() {
let eleven = Uint::small(11);
assert_eq!(eleven, 11u8);
assert_eq!(&eleven, 11u8);
assert_eq!(eleven, &11u8);
assert_ne!(eleven, 10u8);
assert_eq!(11u8, eleven);
assert_ne!(10u8, eleven);
Expand All @@ -1447,12 +1494,16 @@ mod test {
assert!(eleven_pow11.clone().0.is_right());
assert!(eleven_pow11.clone().normalize().0.is_right());
assert!(eleven < eleven_pow11);
assert!(&eleven < eleven_pow11);
assert!(eleven < &eleven_pow11);
assert!(11u8 < eleven_pow11);
assert!(11i8 < eleven_pow11);
let eleven_big = Uint::big(BigUint::from(11u8));
let eleven_big_norm = eleven_big.clone().normalize();
let eleven_big_norm_ref = eleven_big.normalize_ref();
assert_eq!(eleven, eleven_big);
assert_eq!(&eleven, eleven_big);
assert_eq!(eleven, &eleven_big);
assert_eq!(eleven, eleven_big_norm);
assert_eq!(eleven, *eleven_big_norm_ref);
assert_eq!(eleven_big.is_stored_as_big(), true);
Expand All @@ -1471,6 +1522,8 @@ mod test {
fn test_signed() {
let eleven = Int::small(11);
assert_eq!(eleven, 11u8);
assert_eq!(&eleven, 11u8);
assert_eq!(eleven, &11u8);
assert_ne!(eleven, 10u8);
assert_eq!(11u8, eleven);
assert_ne!(10u8, eleven);
Expand All @@ -1497,6 +1550,8 @@ mod test {
assert!(eleven_pow11.clone().0.is_right());
assert!(eleven_pow11.clone().normalize().0.is_right());
assert!(eleven < eleven_pow11);
assert!(&eleven < eleven_pow11);
assert!(eleven < &eleven_pow11);
assert!(-eleven.clone() < eleven_pow11);
assert!(-eleven_pow11.clone() < eleven);
assert!(-eleven_pow11.clone() < -eleven.clone());
Expand All @@ -1509,6 +1564,8 @@ mod test {
let eleven_big_norm = eleven_big.clone().normalize();
let eleven_big_norm_ref = eleven_big.normalize_ref();
assert_eq!(eleven, eleven_big);
assert_eq!(&eleven, eleven_big);
assert_eq!(eleven, &eleven_big);
assert_eq!(eleven, eleven_big_norm);
assert_eq!(eleven, *eleven_big_norm_ref);
assert_eq!(eleven_big.is_stored_as_big(), true);
Expand Down

0 comments on commit fbad1b6

Please sign in to comment.