diff --git a/src/lib.rs b/src/lib.rs index 0deabb4..9a95d02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,8 +55,8 @@ pub trait Integer: private::Sealed { fn fmt(self, W) -> fmt::Result; } -trait IntegerPrivate { - fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8]; +trait IntegerPrivate { + fn write_to(self, buf: &mut B) -> &[u8]; } const DEC_DIGITS_LUT: &'static[u8] = @@ -66,23 +66,21 @@ const DEC_DIGITS_LUT: &'static[u8] = 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; -const MAX_LEN: usize = 40; // i128::MIN (including minus sign) - // Adaptation of the original implementation at // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266 macro_rules! impl_IntegerCommon { - ($t:ident) => { + ($max_len:expr, $t:ident) => { impl Integer for $t { #[cfg(feature = "std")] fn write(self, mut wr: W) -> io::Result { - let mut buf = unsafe { mem::uninitialized() }; + let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); try!(wr.write_all(bytes)); Ok(bytes.len()) } fn fmt(self, mut wr: W) -> fmt::Result { - let mut buf = unsafe { mem::uninitialized() }; + let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); wr.write_str(unsafe { str::from_utf8_unchecked(bytes) }) } @@ -93,12 +91,11 @@ macro_rules! impl_IntegerCommon { } macro_rules! impl_Integer { - ($($t:ident),* as $conv_fn:ident) => {$( - impl_IntegerCommon!($t); + (private $($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( - impl IntegerPrivate for $t { + impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] - fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8] { + fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let mut n = if is_nonnegative { self as $conv_fn @@ -158,25 +155,50 @@ macro_rules! impl_Integer { } } )*}; + + ($($max_len:expr => $t:ident),* as $conv_fn:ident) => { + $(impl_IntegerCommon!($max_len, $t);)* + impl_Integer!(private $($max_len => $t),* as $conv_fn); + }; } -impl_Integer!(i8, u8, i16, u16, i32, u32 as u32); -impl_Integer!(i64, u64 as u64); +const I8_MAX_LEN: usize = 4; +const U8_MAX_LEN: usize = 3; +const I16_MAX_LEN: usize = 6; +const U16_MAX_LEN: usize = 5; +const I32_MAX_LEN: usize = 11; +const U32_MAX_LEN: usize = 10; +const I64_MAX_LEN: usize = 20; +const U64_MAX_LEN: usize = 20; + +impl_Integer!( + I8_MAX_LEN => i8, + U8_MAX_LEN => u8, + I16_MAX_LEN => i16, + U16_MAX_LEN => u16, + I32_MAX_LEN => i32, + U32_MAX_LEN => u32 + as u32); + +impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64); + #[cfg(target_pointer_width = "16")] -impl_Integer!(isize, usize as u16); +impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16); + #[cfg(target_pointer_width = "32")] -impl_Integer!(isize, usize as u32); +impl_Integer!( I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32); + #[cfg(target_pointer_width = "64")] -impl_Integer!(isize, usize as u64); +impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); #[cfg(all(feature = "i128"))] macro_rules! impl_Integer128 { - ($($t:ident),*) => {$( - impl_IntegerCommon!($t); + ($($max_len:expr => $t:ident),*) => {$( + impl_IntegerCommon!($max_len, $t); - impl IntegerPrivate for $t { + impl IntegerPrivate<[u8; $max_len]> for $t { #[allow(unused_comparisons)] - fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8] { + fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let n = if is_nonnegative { self as u128 @@ -200,7 +222,7 @@ macro_rules! impl_Integer128 { // Divide by 10^19 again. let (n, rem) = udiv128::udivmod_1e19(n); - let buf2 = buf_ptr.offset(curr - buf.len() as isize) as *mut _; + let buf2 = buf_ptr.offset(curr - buf.len() as isize) as *mut [u8; $max_len]; curr -= rem.write_to(&mut *buf2).len() as isize; if n != 0 { @@ -230,4 +252,12 @@ macro_rules! impl_Integer128 { } #[cfg(all(feature = "i128"))] -impl_Integer128!(i128, u128); +const U128_MAX_LEN: usize = 39; +#[cfg(all(feature = "i128"))] +const I128_MAX_LEN: usize = 40; + +#[cfg(all(feature = "i128"))] +impl_Integer!(private U128_MAX_LEN => u64, I128_MAX_LEN => u64 as u64); + +#[cfg(all(feature = "i128"))] +impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128); diff --git a/src/udiv128.rs b/src/udiv128.rs index 24233c6..70fffc6 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -21,6 +21,7 @@ // (https://github.com/rust-lang/rust/issues/44545) and to allow function // inlining which doesn’t happen with the intrinsic. +#[inline] pub fn udivmod_1e19(n: u128) -> (u128, u64) { let d = 10_000_000_000_000_000_000_u64; // 10^19