blob: 65a8721bfa5cda8c27c53d18d1ed6e67bf58276b [file] [log] [blame]
//! 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::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>;