diff --git a/lexical-util/src/i256.rs b/lexical-util/src/i256.rs new file mode 100644 index 00000000..d9da8012 --- /dev/null +++ b/lexical-util/src/i256.rs @@ -0,0 +1,27 @@ +//! An signed 256-bit integer type. +//! +//! This aims to have feature parity with Rust's signed +//! integer types, such as [i32][core::i32]. The documentation +//! is based off of [i32][core::i32] for each method/member. + +// TODO: Document +// TODO: Feature gate this... + +// FIXME: Add support for [Saturating][core::num::Saturating] and +// [Wrapping][core::num::Wrapping] when we drop support for <1.74.0. + +/// The 256-bit signed integer type. +/// +/// This has the same binary representation as Apache Arrow's types, +/// and therefore can safely be transmuted from one to the other. +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] +#[repr(C)] +pub struct i256 { + lo: u128, + hi: i128, +} + +impl i256 { + // TODO: Here +} diff --git a/lexical-util/src/lib.rs b/lexical-util/src/lib.rs index 22e2cec5..3e77b949 100644 --- a/lexical-util/src/lib.rs +++ b/lexical-util/src/lib.rs @@ -163,12 +163,14 @@ pub mod error; pub mod extended_float; pub mod f16; pub mod format; +pub mod i256; pub mod iterator; pub mod mul; pub mod num; pub mod options; pub mod result; pub mod step; +pub mod u256; mod api; mod feature_format; diff --git a/lexical-util/src/u256.rs b/lexical-util/src/u256.rs new file mode 100644 index 00000000..03731985 --- /dev/null +++ b/lexical-util/src/u256.rs @@ -0,0 +1,637 @@ +//! An unsigned 256-bit integer type. +//! +//! This aims to have feature parity with Rust's unsigned +//! integer types, such as [u32][core::u32]. The documentation +//! is based off of [u32][core::u32] for each method/member. + +use core::cmp::Ordering; +use core::fmt; +use core::iter::{Product, Sum}; +use core::ops::*; +use core::num::{ParseIntError, TryFromIntError}; +use core::str::FromStr; +use crate::i256::i256; +// TODO: Document +// TODO: Feature gate this... + +// FIXME: Add support for [Saturating][core::num::Saturating] and +// [Wrapping][core::num::Wrapping] when we drop support for <1.74.0. + +/// The 256-bit unsigned integer type. +/// +/// This has the same binary representation as Apache Arrow's types, +/// and therefore can safely be transmuted from one to the other. +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] +#[repr(C)] +pub struct u256 { + lo: u128, + hi: u128, +} + +impl u256 { + /// The smallest value that can be represented by this integer type. + /// + /// # Examples + /// + /// ```rust + /// assert_eq!(u256::MIN, 0); + /// ``` + pub const MIN: u256 = u256 { lo: 0, hi: 0 }; + + /// The largest value that can be represented by this integer type + /// (2256 - 1). + /// + /// # Examples + /// + /// ```rust + /// assert_eq!(u256::MAX, 0); // TODO, need to negate... + /// ``` + pub const MAX: u256 = u256 { lo: u128::MAX, hi: u128::MAX }; + + /// The size of this integer type in bits. + /// + /// # Examples + /// + /// ```rust + /// assert_eq!(u256::BITS, 256); + /// ``` + pub const BITS: u32 = 256; + + /// Returns the number of ones in the binary representation of `self`. + /// + /// # Examples + /// + /// ```rust + /// assert_eq!(u256::BITS, 256); // TODO: Fix... + /// ``` + #[inline(always)] + pub const fn count_ones(self) -> u32 { + // TODO: `ctpop` + todo!(); + } + + /// Returns the number of zeros in the binary representation of `self`. + /// + /// # Examples + /// + /// ```rust + /// assert_eq!(u256::BITS, 256); // TODO: Fix... + /// ``` + #[inline(always)] + pub const fn count_zeros(self) -> u32 { + Self::BITS - self.count_ones() + } + + /// Returns the number of leading zeros in the binary representation of `self`. + /// + /// Depending on what you're doing with the value, you might also be + /// interested in the `ilog2` function which returns a consistent + /// number, even if the type widens. + /// + /// # Examples + /// + /// ```rust + /// let n = u256::MAX >> 2; + /// assert_eq!(n.leading_zeros(), 2); + /// + /// let zero = u256::MIN; + /// assert_eq!(zero.leading_zeros(), 256); + /// + /// let max = u256::MAX; + /// assert_eq!(max.leading_zeros(), 0); + /// ``` + #[inline(always)] + pub const fn leading_zeros(self) -> u32 { + // TODO: ctlz + todo!(); + } + + /// Returns the number of trailing zeros in the binary representation of `self`. + /// + /// # Examples + /// + /// ```rust + /// let n = u256::MAX >> 2; // TODO: This is wrong + /// assert_eq!(n.trailing_zeros(), 2); // TODO: This is wrong + /// + /// let zero = u256::MIN; + /// assert_eq!(zero.trailing_zeros(), 256); + /// + /// let max = u256::MAX; + /// assert_eq!(max.trailing_zeros(), 0); + /// ``` + #[inline(always)] + pub const fn trailing_zeros(self) -> u32 { + todo!(); + } + + // TODO: MOre here... +} + +impl u256 { + /// Create the 256-bit unsigned integer to a `u8`, as if by an `as` cast. + #[inline(always)] + pub const fn from_u8(value: u8) -> Self { + Self { lo: value as u128, hi: 0 } + } + + /// Create the 256-bit unsigned integer from a `u16`, as if by an `as` cast. + #[inline(always)] + pub const fn from_u16(value: u16) -> Self { + Self { lo: value as u128, hi: 0 } + } + + /// Create the 256-bit unsigned integer from a `u32`, as if by an `as` cast. + #[inline(always)] + pub const fn from_u32(value: u32) -> Self { + Self { lo: value as u128, hi: 0 } + } + + /// Create the 256-bit unsigned integer from a `u64`, as if by an `as` cast. + #[inline(always)] + pub const fn from_u64(value: u64) -> Self { + Self { lo: value as u128, hi: 0 } + } + + /// Create the 256-bit unsigned integer from a `u128`, as if by an `as` cast. + #[inline(always)] + pub const fn from_u128(value: u128) -> Self { + Self { lo: value as u128, hi: 0 } + } + + /// Create the 256-bit unsigned integer to an `i8`, as if by an `as` cast. + #[inline(always)] + pub const fn from_i8(value: i8) -> Self { + todo!(); + } + + /// Create the 256-bit unsigned integer from an `i16`, as if by an `as` cast. + #[inline(always)] + pub const fn from_i16(value: i16) -> Self { + todo!(); + } + + /// Create the 256-bit unsigned integer from an `i32`, as if by an `as` cast. + #[inline(always)] + pub const fn from_i32(value: i32) -> Self { + todo!(); + } + + /// Create the 256-bit unsigned integer from an `i64`, as if by an `as` cast. + #[inline(always)] + pub const fn from_i64(value: i64) -> Self { + todo!(); + } + + /// Create the 256-bit unsigned integer from an `i128`, as if by an `as` cast. + #[inline(always)] + pub const fn from_i128(value: i128) -> Self { + todo!(); + } + + /// Create the 256-bit unsigned integer from an `i256`, as if by an `as` cast. + #[inline(always)] + pub const fn from_i256(value: i256) -> Self { + todo!(); + } + + /// Convert the 256-bit unsigned integer to an `u8`, as if by an `as` cast. + #[inline(always)] + pub const fn as_u8(&self) -> u8 { + self.lo as u8 + } + + /// Convert the 256-bit unsigned integer to an `u16`, as if by an `as` cast. + #[inline(always)] + pub const fn as_u16(&self) -> u16 { + self.lo as u16 + } + + /// Convert the 256-bit unsigned integer to an `u32`, as if by an `as` cast. + #[inline(always)] + pub const fn as_u32(&self) -> u32 { + self.lo as u32 + } + + /// Convert the 256-bit unsigned integer to an `u64`, as if by an `as` cast. + #[inline(always)] + pub const fn as_u64(&self) -> u64 { + self.lo as u64 + } + + /// Convert the 256-bit unsigned integer to an `u128`, as if by an `as` cast. + #[inline(always)] + pub const fn as_u128(&self) -> u128 { + self.lo as u128 + } + + /// Convert the 256-bit unsigned integer to an `i8`, as if by an `as` cast. + #[inline(always)] + pub const fn as_i8(&self) -> i8 { + self.lo as i8 + } + + /// Convert the 256-bit unsigned integer to an `i16`, as if by an `as` cast. + #[inline(always)] + pub const fn as_i16(&self) -> i16 { + self.lo as i16 + } + + /// Convert the 256-bit unsigned integer to an `i32`, as if by an `as` cast. + #[inline(always)] + pub const fn as_i32(&self) -> i32 { + self.lo as i32 + } + + /// Convert the 256-bit unsigned integer to an `i64`, as if by an `as` cast. + #[inline(always)] + pub const fn as_i64(&self) -> i64 { + self.lo as i64 + } + + /// Convert the 256-bit unsigned integer to an `i128`, as if by an `as` cast. + #[inline(always)] + pub const fn as_i128(&self) -> i128 { + self.lo as i128 + } + + /// Convert the 256-bit unsigned integer to an `i256`, as if by an `as` cast. + #[inline(always)] + pub const fn as_i256(&self) -> i256 { + todo!(); + } +} + +macro_rules! op_impl { + ($trait:ident, $assign:ident, $op:ident, $op_assign:ident) => { + impl $trait<&u256> for u256 { + type Output = ::Output; + + #[inline(always)] + fn $op(self, rhs: &Self) -> Self::Output { + self.$op(*rhs) + } + } + + impl $assign for u256 { + #[inline(always)] + fn $op_assign(&mut self, other: Self) { + *self = self.$op(other); + } + } + + impl $assign<&u256> for u256 { + #[inline(always)] + fn $op_assign(&mut self, other: &Self) { + *self = self.$op(other); + } + } + }; +} + +impl Add for u256 { + type Output = Self; + + #[inline(always)] + fn add(self, other: Self) -> Self::Output { + todo!(); + } +} + +op_impl!(Add, AddAssign, add, add_assign); + +impl fmt::Binary for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl BitAnd for u256 { + type Output = Self; + + #[inline(always)] + fn bitand(self, rhs: Self) -> Self::Output { + Self::Output { hi: self.hi.bitand(rhs.hi), lo: self.lo.bitand(rhs.lo) } + } +} + +op_impl!(BitAnd, BitAndAssign, bitand, bitand_assign); + +impl BitOr for u256 { + type Output = u256; + + #[inline(always)] + fn bitor(self, rhs: Self) -> Self::Output { + Self::Output { hi: self.hi.bitor(rhs.hi), lo: self.lo.bitor(rhs.lo) } + } +} + +op_impl!(BitOr, BitOrAssign, bitor, bitor_assign); + +impl BitXor for u256 { + type Output = Self; + + #[inline(always)] + fn bitxor(self, rhs: Self) -> Self::Output { + Self::Output { hi: self.hi.bitxor(rhs.hi), lo: self.lo.bitxor(rhs.lo) } + } +} + +op_impl!(BitXor, BitXorAssign, bitxor, bitxor_assign); + +impl fmt::Debug for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl fmt::Display for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl Div for u256 { + type Output = Self; + + #[inline(always)] + fn div(self, rhs: Self) -> Self::Output { + todo!(); + } +} + +op_impl!(Div, DivAssign, div, div_assign); + +impl From for u256 { + #[inline(always)] + fn from(small: bool) -> Self { + Self { lo: small as u128, hi: 0 } + } +} + +impl From for u256 { + #[inline(always)] + fn from(c: char) -> Self { + Self { lo: c as u128, hi: 0 } + } +} + +macro_rules! from_impl { + ($t:ty, $op:ident) => { + impl From<$t> for u256 { + #[inline(always)] + fn from(small: $t) -> Self { + Self::$op(small) + } + } + }; +} + +from_impl!(u8, from_u8); +from_impl!(u16, from_u16); +from_impl!(u32, from_u32); +from_impl!(u64, from_u64); +from_impl!(u128, from_u128); + +impl FromStr for u256 { + type Err = ParseIntError; + + /// Parses a string s to return a value of this type. + /// + /// This is not optimized, since all optimization is done in + /// the lexical implementation. + #[inline(always)] + fn from_str(src: &str) -> Result { + todo!(); + } +} + +impl fmt::LowerExp for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl fmt::LowerHex for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl Mul for u256 { + type Output = u256; + + #[inline(always)] + fn mul(self, rhs: Self) -> Self::Output { + todo!(); + } +} + +op_impl!(Mul, MulAssign, mul, mul_assign); + +impl Not for u256 { + type Output = u256; + + #[inline(always)] + fn not(self) -> Self::Output { + todo!(); + } +} + +impl Not for &u256 { + type Output = ::Output; + + #[inline(always)] + fn not(self) -> Self::Output { + u256::not(*self) + } +} + +impl fmt::Octal for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl Ord for u256 { + #[inline(always)] + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for u256 { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} + +impl Product for u256 { + #[inline(always)] + fn product>(iter: I) -> Self { + todo!(); + } +} + +impl Rem for u256 { + type Output = u256; + + #[inline(always)] + fn rem(self, rhs: Self) -> Self::Output { + todo!(); + } +} + +op_impl!(Rem, RemAssign, rem, rem_assign); + +impl Shl for u256 { + type Output = Self; + + #[inline(always)] + fn shl(self, other: Self) -> Self::Output { + todo!(); + } +} + +impl Shl<&u256> for u256 { + type Output = ::Output; + + #[inline(always)] + fn shl(self, other: &u256) -> Self::Output { + self.shl(*other) + } +} + +impl Shr for u256 { + type Output = Self; + + #[inline(always)] + fn shr(self, other: Self) -> Self::Output { + todo!(); + } +} + +macro_rules! shift_impl { + ($($t:ty)*) => ($( + impl Shl<$t> for u256 { + type Output = Self; + + #[inline(always)] + fn shl(self, other: $t) -> Self::Output { + todo!(); + } + } + + impl Shl<&$t> for u256 { + type Output = ::Output; + + #[inline(always)] + fn shl(self, other: &$t) -> Self::Output { + self.shl(*other) + } + } + + impl ShlAssign<$t> for u256 { + #[inline(always)] + fn shl_assign(&mut self, other: $t) { + *self = self.shl(other); + } + } + + impl ShlAssign<&$t> for u256 { + #[inline(always)] + fn shl_assign(&mut self, other: &$t) { + *self = self.shl(other); + } + } + + impl Shr<$t> for u256 { + type Output = Self; + + #[inline(always)] + fn shr(self, other: $t) -> Self::Output { + todo!(); + } + } + + impl Shr<&$t> for u256 { + type Output = ::Output; + + #[inline(always)] + fn shr(self, other: &$t) -> Self::Output { + self.shr(*other) + } + } + + impl ShrAssign<$t> for u256 { + #[inline(always)] + fn shr_assign(&mut self, other: $t) { + *self = self.shr(other); + } + } + + impl ShrAssign<&$t> for u256 { + #[inline(always)] + fn shr_assign(&mut self, other: &$t) { + *self = self.shr(other); + } + } + )*); +} + +shift_impl! { i8 i16 i32 i64 i128 i256 isize u8 u16 u32 u64 u128 usize } + +impl Sub for u256 { + type Output = u256; + + #[inline(always)] + fn sub(self, rhs: Self) -> Self::Output { + todo!(); + } +} + +op_impl!(Sub, SubAssign, sub, sub_assign); + +impl Sum for u256 { + #[inline(always)] + fn sum>(iter: I) -> Self { + todo!(); + } +} + +macro_rules! try_from_impl { + ($($t:ty)*) => ($( + impl TryFrom<$t> for u256 { + type Error = TryFromIntError; + + #[inline(always)] + fn try_from(u: $t) -> Result>::Error> { + todo!(); + } + } + )*); +} + +try_from_impl! { i8 i16 i32 i64 i128 i256 isize } + +impl fmt::UpperExp for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +} + +impl fmt::UpperHex for u256 { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + todo!(); + } +}