diff --git a/src/lib.rs b/src/lib.rs index e2fad15..e7ab276 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,11 @@ clippy::needless_doctest_main, clippy::unreadable_literal )] +#![feature(const_intrinsic_copy)] +#![feature(const_mut_refs)] +#![feature(const_ptr_write)] +#![feature(const_trait_impl)] +#![feature(effects)] mod udiv128; @@ -84,7 +89,7 @@ impl Buffer { /// for efficiency. #[inline] #[cfg_attr(feature = "no-panic", no_panic)] - pub fn new() -> Buffer { + pub const fn new() -> Buffer { let bytes = [MaybeUninit::::uninit(); I128_MAX_LEN]; Buffer { bytes } } @@ -92,10 +97,10 @@ impl Buffer { /// Print an integer into this buffer and return a reference to its string /// representation within the buffer. #[cfg_attr(feature = "no-panic", no_panic)] - pub fn format(&mut self, i: I) -> &str { + pub const fn format(&mut self, i: I) -> &str { i.write(unsafe { &mut *(&mut self.bytes as *mut [MaybeUninit; I128_MAX_LEN] - as *mut ::Buffer) + as *mut I::Buffer) }) } } @@ -103,13 +108,18 @@ impl Buffer { /// An integer that can be written into an [`itoa::Buffer`][Buffer]. /// /// This trait is sealed and cannot be implemented for types outside of itoa. -pub trait Integer: private::Sealed {} +#[const_trait] +pub trait Integer: private::Sealed { + #[doc(hidden)] + type Buffer: 'static; + + #[doc(hidden)] + fn write(self, buf: &mut Self::Buffer) -> &str; +} // Seal to prevent downstream implementations of the Integer trait. mod private { pub trait Sealed: Copy { - type Buffer: 'static; - fn write(self, buf: &mut Self::Buffer) -> &str; } } @@ -124,9 +134,7 @@ const DEC_DIGITS_LUT: &[u8] = b"\ // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266 macro_rules! impl_Integer { ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( - impl Integer for $t {} - - impl private::Sealed for $t { + impl const Integer for $t { type Buffer = [MaybeUninit; $max_len]; #[allow(unused_comparisons)] @@ -192,6 +200,8 @@ macro_rules! impl_Integer { unsafe { str::from_utf8_unchecked(bytes) } } } + + impl private::Sealed for $t {} )*}; } @@ -226,9 +236,7 @@ impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); macro_rules! impl_Integer128 { ($($max_len:expr => $t:ident),*) => {$( - impl Integer for $t {} - - impl private::Sealed for $t { + impl const Integer for $t { type Buffer = [MaybeUninit; $max_len]; #[allow(unused_comparisons)] @@ -286,6 +294,8 @@ macro_rules! impl_Integer128 { } } } + + impl private::Sealed for $t {} )*}; } diff --git a/src/udiv128.rs b/src/udiv128.rs index 0587047..f7e5ff2 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -4,7 +4,7 @@ use no_panic::no_panic; /// Multiply unsigned 128 bit integers, return upper 128 bits of the result #[inline] #[cfg_attr(feature = "no-panic", no_panic)] -fn u128_mulhi(x: u128, y: u128) -> u128 { +const fn u128_mulhi(x: u128, y: u128) -> u128 { let x_lo = x as u64; let x_hi = (x >> 64) as u64; let y_lo = y as u64; @@ -31,7 +31,7 @@ fn u128_mulhi(x: u128, y: u128) -> u128 { /// #[inline] #[cfg_attr(feature = "no-panic", no_panic)] -pub fn udivmod_1e19(n: u128) -> (u128, u64) { +pub const fn udivmod_1e19(n: u128) -> (u128, u64) { let d = 10_000_000_000_000_000_000_u64; // 10^19 let quot = if n < 1 << 83 { @@ -41,8 +41,8 @@ pub fn udivmod_1e19(n: u128) -> (u128, u64) { }; let rem = (n - quot * d as u128) as u64; - debug_assert_eq!(quot, n / d as u128); - debug_assert_eq!(rem as u128, n % d as u128); + debug_assert!(quot == n / d as u128); + debug_assert!(rem as u128 == n % d as u128); (quot, rem) }