make it difficult to accidently leak supertraits in sealed traits

This commit is contained in:
Trevor Spiteri 2019-08-11 11:23:15 +02:00
parent 7695b680e3
commit 414e63a6dc
6 changed files with 50 additions and 23 deletions

View File

@ -357,7 +357,7 @@ fn fmt_dec_helper<F: FmtDecHelper>(
*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 => {

View File

@ -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 {}

View File

@ -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<Self> + 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<F: 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<Frac>;
#[inline]
fn traits(self) -> Self::Traits {
self
}
#[inline]
fn saturating_from_fixed<F: Fixed>(val: F) -> Self {
@ -202,7 +211,7 @@ macro_rules! sealed_fixed {
#[inline]
fn overflowing_from_float<F: SealedFloat>(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);

View File

@ -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<F: 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 })

View File

@ -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<F: 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<F: 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<U0>;
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()

View File

@ -135,28 +135,28 @@ impl<F: Fixed> Copy for Wrapping<F> {}
impl<F: Fixed> Default for Wrapping<F> {
#[inline]
fn default() -> Wrapping<F> {
Wrapping(F::default())
Wrapping(F::Traits::default().into())
}
}
impl<F: Fixed> Hash for Wrapping<F> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(self.0).hash(state);
self.0.traits().hash(state);
}
}
impl<F: Fixed> Debug for Wrapping<F> {
#[inline]
fn fmt(&self, f: &mut Formatter) -> FmtResult {
<F as Debug>::fmt(&self.0, f)
<F::Traits as Debug>::fmt(&self.0.traits(), f)
}
}
impl<F: Fixed> Display for Wrapping<F> {
#[inline]
fn fmt(&self, f: &mut Formatter) -> FmtResult {
<F as Display>::fmt(&self.0, f)
<F::Traits as Display>::fmt(&self.0.traits(), f)
}
}
@ -171,35 +171,35 @@ impl<F: Fixed> Eq for Wrapping<F> {}
impl<F: Fixed> PartialEq<Wrapping<F>> for Wrapping<F> {
#[inline]
fn eq(&self, other: &Wrapping<F>) -> bool {
(self.0).eq(&other.0)
self.0.traits().eq(&other.0.traits())
}
}
impl<F: Fixed> Ord for Wrapping<F> {
#[inline]
fn cmp(&self, other: &Wrapping<F>) -> Ordering {
(self.0).cmp(&other.0)
self.0.traits().cmp(&other.0.traits())
}
}
impl<F: Fixed> PartialOrd<Wrapping<F>> for Wrapping<F> {
#[inline]
fn partial_cmp(&self, other: &Wrapping<F>) -> Option<Ordering> {
(self.0).partial_cmp(&other.0)
self.0.traits().partial_cmp(&other.0.traits())
}
#[inline]
fn lt(&self, other: &Wrapping<F>) -> bool {
(self.0).lt(&other.0)
self.0.traits().lt(&other.0.traits())
}
#[inline]
fn le(&self, other: &Wrapping<F>) -> bool {
(self.0).le(&other.0)
self.0.traits().le(&other.0.traits())
}
#[inline]
fn gt(&self, other: &Wrapping<F>) -> bool {
(self.0).gt(&other.0)
self.0.traits().gt(&other.0.traits())
}
#[inline]
fn ge(&self, other: &Wrapping<F>) -> bool {
(self.0).ge(&other.0)
self.0.traits().ge(&other.0.traits())
}
}