diff --git a/Cargo.toml b/Cargo.toml index a1113ef..db6516d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "itoa" -version = "0.3.2" # remember to update html_root_url +version = "0.3.3" # remember to update html_root_url authors = ["David Tolnay "] license = "MIT/Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" diff --git a/src/lib.rs b/src/lib.rs index 0e240c1..9f8b030 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![doc(html_root_url = "https://docs.rs/itoa/0.3.2")] +#![doc(html_root_url = "https://docs.rs/itoa/0.3.3")] use std::{io, mem, ptr, slice}; @@ -19,6 +19,10 @@ pub trait Integer { fn write(self, W) -> io::Result; } +trait IntegerPrivate { + fn write_to(self, buf: &mut [u8; MAX_LEN]) -> &[u8]; +} + const DEC_DIGITS_LUT: &'static[u8] = b"0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ @@ -26,22 +30,31 @@ const DEC_DIGITS_LUT: &'static[u8] = 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; +const MAX_LEN: usize = 20; // Tie between i64::MIN (including minus sign) and u64::MAX + // Adaptation of the original implementation at // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266 macro_rules! impl_Integer { ($($t:ident),* as $conv_fn:ident) => ($( impl Integer for $t { - #[allow(unused_comparisons)] fn write(self, mut wr: W) -> io::Result { + let mut buf = unsafe { mem::uninitialized() }; + let bytes = self.write_to(&mut buf); + try!(wr.write_all(bytes)); + Ok(bytes.len()) + } + } + + impl IntegerPrivate for $t { + #[allow(unused_comparisons)] + 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 } else { - try!(wr.write_all(b"-")); // convert the negative num to positive by summing 1 to it's 2 complement (!(self as $conv_fn)).wrapping_add(1) }; - let mut buf: [u8; 20] = unsafe { mem::uninitialized() }; let mut curr = buf.len() as isize; let buf_ptr = buf.as_mut_ptr(); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); @@ -75,20 +88,21 @@ macro_rules! impl_Integer { // decode last 1 or 2 chars if n < 10 { curr -= 1; - *buf_ptr.offset(curr) = (n as u8) + 48; + *buf_ptr.offset(curr) = (n as u8) + b'0'; } else { let d1 = n << 1; curr -= 2; ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); } - } - let mut len = buf.len() - curr as usize; - try!(wr.write_all(unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) })); - if !is_nonnegative { - len += 1; + if !is_nonnegative { + curr -= 1; + *buf_ptr.offset(curr) = b'-'; + } } - Ok(len) + + let len = buf.len() - curr as usize; + unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) } } })*); } diff --git a/tests/test.rs b/tests/test.rs index 7615c19..0a33f80 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -19,6 +19,7 @@ test!( test_0u64(0u64, "0"), test_HALFu64(::max_value() as u64, "4294967295"), test_MAXu64(::max_value(), "18446744073709551615"), + test_MINi64(::min_value(), "-9223372036854775808"), test_0i16(0i16, "0"), test_MINi16(::min_value(), "-32768"),