| //! Interfaces used throughout this crate. | |
| use std::str::FromStr; | |
| use std::{fmt, ops}; | |
| use num::Integer; | |
| use num::bigint::ToBigInt; | |
| use crate::validate::Constants; | |
| /// Integer types. | |
| #[allow(dead_code)] // Some functions only used for testing | |
| pub trait Int: | |
| Clone | |
| + Copy | |
| + fmt::Debug | |
| + fmt::Display | |
| + fmt::LowerHex | |
| + ops::Add<Output = Self> | |
| + ops::Sub<Output = Self> | |
| + ops::Shl<u32, Output = Self> | |
| + ops::Shr<u32, Output = Self> | |
| + ops::BitAnd<Output = Self> | |
| + ops::BitOr<Output = Self> | |
| + ops::Not<Output = Self> | |
| + ops::AddAssign | |
| + ops::BitAndAssign | |
| + ops::BitOrAssign | |
| + From<u8> | |
| + TryFrom<i8> | |
| + TryFrom<u32, Error: fmt::Debug> | |
| + TryFrom<u64, Error: fmt::Debug> | |
| + TryFrom<u128, Error: fmt::Debug> | |
| + TryInto<u64, Error: fmt::Debug> | |
| + TryInto<u32, Error: fmt::Debug> | |
| + ToBigInt | |
| + PartialOrd | |
| + Integer | |
| + Send | |
| + 'static | |
| { | |
| type Signed: Int; | |
| type Bytes: Default + AsMut<[u8]>; | |
| const BITS: u32; | |
| const ZERO: Self; | |
| const ONE: Self; | |
| const MAX: Self; | |
| fn to_signed(self) -> Self::Signed; | |
| fn wrapping_neg(self) -> Self; | |
| fn trailing_zeros(self) -> u32; | |
| fn hex(self) -> String { | |
| format!("{self:x}") | |
| } | |
| } | |
| macro_rules! impl_int { | |
| ($($uty:ty, $sty:ty);+) => { | |
| $( | |
| impl Int for $uty { | |
| type Signed = $sty; | |
| type Bytes = [u8; Self::BITS as usize / 8]; | |
| const BITS: u32 = Self::BITS; | |
| const ZERO: Self = 0; | |
| const ONE: Self = 1; | |
| const MAX: Self = Self::MAX; | |
| fn to_signed(self) -> Self::Signed { | |
| self.try_into().unwrap() | |
| } | |
| fn wrapping_neg(self) -> Self { | |
| self.wrapping_neg() | |
| } | |
| fn trailing_zeros(self) -> u32 { | |
| self.trailing_zeros() | |
| } | |
| } | |
| impl Int for $sty { | |
| type Signed = Self; | |
| type Bytes = [u8; Self::BITS as usize / 8]; | |
| const BITS: u32 = Self::BITS; | |
| const ZERO: Self = 0; | |
| const ONE: Self = 1; | |
| const MAX: Self = Self::MAX; | |
| fn to_signed(self) -> Self::Signed { | |
| self | |
| } | |
| fn wrapping_neg(self) -> Self { | |
| self.wrapping_neg() | |
| } | |
| fn trailing_zeros(self) -> u32 { | |
| self.trailing_zeros() | |
| } | |
| } | |
| )+ | |
| } | |
| } | |
| impl_int!(u16, i16; u32, i32; u64, i64); | |
| /// Floating point types. | |
| pub trait Float: | |
| Copy + fmt::Debug + fmt::LowerExp + FromStr<Err: fmt::Display> + Sized + Send + 'static | |
| { | |
| /// Unsigned integer of same width | |
| type Int: Int<Signed = Self::SInt>; | |
| type SInt: Int; | |
| /// Total bits | |
| const BITS: u32; | |
| /// (Stored) bits in the mantissa) | |
| const MAN_BITS: u32; | |
| /// Bits in the exponent | |
| const EXP_BITS: u32 = Self::BITS - Self::MAN_BITS - 1; | |
| /// A saturated exponent (all ones) | |
| const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; | |
| /// The exponent bias, also its maximum value | |
| const EXP_BIAS: u32 = Self::EXP_SAT >> 1; | |
| const MAN_MASK: Self::Int; | |
| const SIGN_MASK: Self::Int; | |
| fn from_bits(i: Self::Int) -> Self; | |
| fn to_bits(self) -> Self::Int; | |
| /// Rational constants associated with this float type. | |
| fn constants() -> &'static Constants; | |
| fn is_sign_negative(self) -> bool { | |
| (self.to_bits() & Self::SIGN_MASK) > Self::Int::ZERO | |
| } | |
| /// Exponent without adjustment for bias. | |
| fn exponent(self) -> u32 { | |
| ((self.to_bits() >> Self::MAN_BITS) & Self::EXP_SAT.try_into().unwrap()).try_into().unwrap() | |
| } | |
| fn mantissa(self) -> Self::Int { | |
| self.to_bits() & Self::MAN_MASK | |
| } | |
| } | |
| macro_rules! impl_float { | |
| ($($fty:ty, $ity:ty);+) => { | |
| $( | |
| impl Float for $fty { | |
| type Int = $ity; | |
| type SInt = <Self::Int as Int>::Signed; | |
| const BITS: u32 = <$ity>::BITS; | |
| const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1; | |
| const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE; | |
| const SIGN_MASK: Self::Int = Self::Int::ONE << (<Self as Float>::BITS-1); | |
| fn from_bits(i: Self::Int) -> Self { Self::from_bits(i) } | |
| fn to_bits(self) -> Self::Int { self.to_bits() } | |
| fn constants() -> &'static Constants { | |
| use std::sync::LazyLock; | |
| static CONSTANTS: LazyLock<Constants> = LazyLock::new(Constants::new::<$fty>); | |
| &CONSTANTS | |
| } | |
| } | |
| )+ | |
| } | |
| } | |
| impl_float!(f32, u32; f64, u64); | |
| #[cfg(target_has_reliable_f16)] | |
| impl_float!(f16, u16); | |
| /// A test generator. Should provide an iterator that produces unique patterns to parse. | |
| /// | |
| /// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to | |
| /// write the string at a later step. This is done separately so that we can reuse string | |
| /// allocations (which otherwise turn out to be a pretty expensive part of these tests). | |
| pub trait Generator<F: Float>: Iterator<Item = Self::WriteCtx> + Send + 'static { | |
| /// Full display and filtering name | |
| const NAME: &'static str = Self::SHORT_NAME; | |
| /// Name for display with the progress bar | |
| const SHORT_NAME: &'static str; | |
| /// The context needed to create a test string. | |
| type WriteCtx: Send; | |
| /// Number of tests that will be run. | |
| fn total_tests() -> u64; | |
| /// Constructor for this test generator. | |
| fn new() -> Self; | |
| /// Create a test string given write context, which was produced as a step from the iterator. | |
| /// | |
| /// `s` will be provided empty. | |
| fn write_string(s: &mut String, ctx: Self::WriteCtx); | |
| } | |
| /// For tests that use iterator combinators, it is easier to just to box the iterator than trying | |
| /// to specify its type. This is a shorthand for the usual type. | |
| pub type BoxGenIter<This, F> = Box<dyn Iterator<Item = <This as Generator<F>>::WriteCtx> + Send>; |