From 414e63a6dcaf3a3be51a483a565dc8dc07cec3ab Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Sun, 11 Aug 2019 11:23:15 +0200 Subject: [PATCH] make it difficult to accidently leak supertraits in sealed traits --- src/display.rs | 2 +- src/sealed.rs | 6 +++--- src/sealed_fixed.rs | 15 ++++++++++++--- src/sealed_float.rs | 13 +++++++++++-- src/sealed_int.rs | 15 ++++++++++++--- src/wrapping.rs | 22 +++++++++++----------- 6 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/display.rs b/src/display.rs index f87cb26..cc65483 100644 --- a/src/display.rs +++ b/src/display.rs @@ -357,7 +357,7 @@ fn fmt_dec_helper( *r = b'0' + frac.take_frac_digit(); } // check for rounding up - let round_up = match frac.cmp(&F::MSB) { + let round_up = match frac.traits().cmp(&F::MSB.traits()) { Ordering::Less => false, Ordering::Greater => true, Ordering::Equal => { diff --git a/src/sealed.rs b/src/sealed.rs index 1c4c2df..4808cb7 100644 --- a/src/sealed.rs +++ b/src/sealed.rs @@ -49,7 +49,7 @@ use half::f16; /// [`u64`]: https://doc.rust-lang.org/nightly/std/primitive.u64.html /// [`u8`]: https://doc.rust-lang.org/nightly/std/primitive.u8.html /// [`usize`]: https://doc.rust-lang.org/nightly/std/primitive.usize.html -pub trait Int: SealedInt {} +pub trait Int: Copy + SealedInt {} /// This trait is implemented for the primitive floating-point types, /// and for [`f16`] if the [`f16` feature] is enabled. @@ -62,7 +62,7 @@ pub trait Int: SealedInt {} /// [`f32`]: https://doc.rust-lang.org/nightly/std/primitive.f32.html /// [`f64`]: https://doc.rust-lang.org/nightly/std/primitive.f64.html /// [`f16` feature]: ../index.html#optional-features -pub trait Float: SealedFloat {} +pub trait Float: Copy + SealedFloat {} /// This trait is implemented for all the fixed-point types. /// @@ -81,7 +81,7 @@ pub trait Float: SealedFloat {} /// [`FixedU32`]: ../struct.FixedU32.html /// [`FixedU64`]: ../struct.FixedU64.html /// [`FixedU8`]: ../struct.FixedU8.html -pub trait Fixed: SealedFixed {} +pub trait Fixed: Copy + SealedFixed {} impl Int for i8 {} impl Int for i16 {} diff --git a/src/sealed_fixed.rs b/src/sealed_fixed.rs index f9c2b70..ccfa40c 100644 --- a/src/sealed_fixed.rs +++ b/src/sealed_fixed.rs @@ -31,9 +31,10 @@ pub enum Widest { Negative(i128), } -pub trait SealedFixed: Copy + Debug + Default + Display + Eq + Hash + Ord { +pub trait SealedFixed: Copy { type FracNBits: Unsigned; type SBits: SealedInt; + type Traits: Copy + Debug + Default + Into + Display + Eq + Hash + Ord; const FRAC_NBITS: u32 = Self::FracNBits::U32; const INT_NBITS: u32 = Self::SBits::NBITS - Self::FRAC_NBITS; @@ -47,10 +48,12 @@ pub trait SealedFixed: Copy + Debug + Default + Display + Eq + Hash + Ord { // 0 for no int bits const INT_LSB: u128 = Self::INT_MASK ^ (Self::INT_MASK << 1); + fn traits(self) -> Self::Traits; + #[inline] fn from_fixed(val: F) -> Self { let (wrapped, overflow) = SealedFixed::overflowing_from_fixed(val); - debug_assert!(!overflow, "{} overflows", val); + debug_assert!(!overflow, "{} overflows", val.traits()); let _ = overflow; wrapped } @@ -98,6 +101,12 @@ macro_rules! sealed_fixed { { type FracNBits = Frac; type SBits = $Bits; + type Traits = $Fixed; + + #[inline] + fn traits(self) -> Self::Traits { + self + } #[inline] fn saturating_from_fixed(val: F) -> Self { @@ -202,7 +211,7 @@ macro_rules! sealed_fixed { #[inline] fn overflowing_from_float(val: F) -> (Self, bool) { if !val.is_finite() { - panic!("{} is not finite", val); + panic!("{} is not finite", val.traits()); } let (value, _, mut overflow) = val.to_fixed_dir_overflow(Self::FRAC_NBITS, Self::INT_NBITS); diff --git a/src/sealed_float.rs b/src/sealed_float.rs index 2f7c95f..3cc0842 100644 --- a/src/sealed_float.rs +++ b/src/sealed_float.rs @@ -21,8 +21,9 @@ use core::{ #[cfg(feature = "f16")] use half::f16; -pub trait SealedFloat: Copy + Debug + Display { +pub trait SealedFloat: Copy { type Bits: SealedInt; + type Traits: Copy + Debug + Display; const PREC: u32; const EXP_BIAS: i32 = (1 << (Self::Bits::NBITS - Self::PREC - 1)) - 1; @@ -32,6 +33,8 @@ pub trait SealedFloat: Copy + Debug + Display { const EXP_MASK: Self::Bits; const MANT_MASK: Self::Bits; + fn traits(self) -> Self::Traits; + fn zero(neg: bool) -> Self; fn infinity(neg: bool) -> Self; fn is_nan(self) -> bool; @@ -46,7 +49,7 @@ pub trait SealedFloat: Copy + Debug + Display { #[inline] fn to_fixed(self) -> F { let (wrapped, overflow) = Self::overflowing_to_fixed(self); - debug_assert!(!overflow, "{} overflows", self); + debug_assert!(!overflow, "{} overflows", self.traits()); let _ = overflow; wrapped } @@ -83,12 +86,18 @@ macro_rules! sealed_float { ($Float:ident($Bits:ty, $IBits:ty, $prec:expr)) => { impl SealedFloat for $Float { type Bits = $Bits; + type Traits = $Float; const PREC: u32 = $prec; const SIGN_MASK: Self::Bits = Self::Bits::MSB; const EXP_MASK: Self::Bits = Self::SIGN_MASK - (1 << (Self::PREC - 1)); const MANT_MASK: Self::Bits = (1 << (Self::PREC - 1)) - 1; + #[inline] + fn traits(self) -> Self::Traits { + self + } + #[inline] fn zero(neg: bool) -> $Float { Self::from_bits(if neg { Self::SIGN_MASK } else { 0 }) diff --git a/src/sealed_int.rs b/src/sealed_int.rs index 9f844cc..e4af3ec 100644 --- a/src/sealed_int.rs +++ b/src/sealed_int.rs @@ -24,21 +24,24 @@ use core::{ fmt::{Debug, Display}, }; -pub trait SealedInt: Copy + Ord + Debug + Display { +pub trait SealedInt: Copy { type NBits: Unsigned; type IsSigned: Bit; type Unsigned: SealedInt; type ReprFixed: Fixed; + type Traits: Copy + Ord + Debug + Display; const NBITS: u32 = Self::NBits::U32; const IS_SIGNED: bool = Self::IsSigned::BOOL; const MSB: Self; const ZERO: Self; + fn traits(self) -> Self::Traits; + #[inline] fn from_fixed(val: F) -> Self { let (wrapped, overflow) = Self::overflowing_from_fixed(val); - debug_assert!(!overflow, "{} overflows", val); + debug_assert!(!overflow, "{} overflows", val.traits()); let _ = overflow; wrapped } @@ -60,7 +63,7 @@ pub trait SealedInt: Copy + Ord + Debug + Display { #[inline] fn to_fixed(self) -> F { let (wrapped, overflow) = Self::overflowing_to_fixed(self); - debug_assert!(!overflow, "{} overflows", self); + debug_assert!(!overflow, "{} overflows", self.traits()); let _ = overflow; wrapped } @@ -109,10 +112,16 @@ macro_rules! sealed_int { type IsSigned = $IsSigned; type Unsigned = $Unsigned; type ReprFixed = $ReprFixed; + type Traits = $Int; const MSB: $Int = 1 << (Self::NBITS - 1); const ZERO: $Int = 0; + #[inline] + fn traits(self) -> Self::Traits { + self + } + #[inline] fn min_value() -> $Int { $Int::min_value() diff --git a/src/wrapping.rs b/src/wrapping.rs index d4c3250..acb2e94 100644 --- a/src/wrapping.rs +++ b/src/wrapping.rs @@ -135,28 +135,28 @@ impl Copy for Wrapping {} impl Default for Wrapping { #[inline] fn default() -> Wrapping { - Wrapping(F::default()) + Wrapping(F::Traits::default().into()) } } impl Hash for Wrapping { #[inline] fn hash(&self, state: &mut H) { - (self.0).hash(state); + self.0.traits().hash(state); } } impl Debug for Wrapping { #[inline] fn fmt(&self, f: &mut Formatter) -> FmtResult { - ::fmt(&self.0, f) + ::fmt(&self.0.traits(), f) } } impl Display for Wrapping { #[inline] fn fmt(&self, f: &mut Formatter) -> FmtResult { - ::fmt(&self.0, f) + ::fmt(&self.0.traits(), f) } } @@ -171,35 +171,35 @@ impl Eq for Wrapping {} impl PartialEq> for Wrapping { #[inline] fn eq(&self, other: &Wrapping) -> bool { - (self.0).eq(&other.0) + self.0.traits().eq(&other.0.traits()) } } impl Ord for Wrapping { #[inline] fn cmp(&self, other: &Wrapping) -> Ordering { - (self.0).cmp(&other.0) + self.0.traits().cmp(&other.0.traits()) } } impl PartialOrd> for Wrapping { #[inline] fn partial_cmp(&self, other: &Wrapping) -> Option { - (self.0).partial_cmp(&other.0) + self.0.traits().partial_cmp(&other.0.traits()) } #[inline] fn lt(&self, other: &Wrapping) -> bool { - (self.0).lt(&other.0) + self.0.traits().lt(&other.0.traits()) } #[inline] fn le(&self, other: &Wrapping) -> bool { - (self.0).le(&other.0) + self.0.traits().le(&other.0.traits()) } #[inline] fn gt(&self, other: &Wrapping) -> bool { - (self.0).gt(&other.0) + self.0.traits().gt(&other.0.traits()) } #[inline] fn ge(&self, other: &Wrapping) -> bool { - (self.0).ge(&other.0) + self.0.traits().ge(&other.0.traits()) } }