From ccdcae586ff4fabec07e37527ac900f14db88c80 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 17 Mar 2018 10:02:50 +0900 Subject: [PATCH 1/4] Move out impl Integer to a common macro --- src/lib.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 722847f..a7e5a36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,8 +41,8 @@ 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_Integer { - ($($t:ident),* as $conv_fn:ident) => {$( +macro_rules! impl_IntegerCommon { + ($t:ident) => { impl Integer for $t { fn write(self, mut wr: W) -> io::Result { let mut buf = unsafe { mem::uninitialized() }; @@ -51,6 +51,12 @@ macro_rules! impl_Integer { Ok(bytes.len()) } } + }; +} + +macro_rules! impl_Integer { + ($($t:ident),* as $conv_fn:ident) => {$( + impl_IntegerCommon!($t); impl IntegerPrivate for $t { #[allow(unused_comparisons)] @@ -128,14 +134,7 @@ impl_Integer!(isize, usize as u64); #[cfg(all(feature = "i128"))] macro_rules! impl_Integer128 { ($($t:ident),*) => {$( - impl Integer for $t { - 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_IntegerCommon!($t); impl IntegerPrivate for $t { #[allow(unused_comparisons)] From 39e80cca433ad127bfa58cebbbaa4f4791246963 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 18 Mar 2018 15:49:59 +0900 Subject: [PATCH 2/4] Prevent downstream implementations of the Integer trait --- src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a7e5a36..08c452c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,12 @@ pub fn write(wr: W, value: V) -> io::Result { value.write(wr) } -pub trait Integer { +// Seal to prevent downstream implementations of the Integer trait. +mod private { + pub trait Sealed {} +} + +pub trait Integer: private::Sealed { fn write(self, W) -> io::Result; } @@ -51,6 +56,8 @@ macro_rules! impl_IntegerCommon { Ok(bytes.len()) } } + + impl private::Sealed for $t {} }; } From 9f3e867f0499238e74fabade604a4695eab0e913 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 17 Mar 2018 10:11:33 +0900 Subject: [PATCH 3/4] Provide itoa::fmt to write to fmt::Write Fixes #5. --- README.md | 12 ++++++++++-- src/lib.rs | 15 ++++++++++++++- tests/test.rs | 4 ++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 524957b..999faba 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ itoa [![Latest Version](https://img.shields.io/crates/v/itoa.svg)](https://crates.io/crates/itoa) This crate provides fast functions for printing integer primitives to an -[`io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html). The +[`io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html) or a +[`fmt::Write`](https://doc.rust-lang.org/core/fmt/trait.Write.html). The implementation comes straight from [libcore](https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254) but avoids the performance penalty of going through @@ -32,12 +33,19 @@ println!("{:?}", buf); let mut bytes = [b'\0'; 20]; let n = itoa::write(&mut bytes[..], 128u64)?; println!("{:?}", &bytes[..n]); + +// write to a String +let mut s = String::new(); +itoa::fmt(&mut s, 128u64)?; +println!("{}", s); ``` -The function signature is: +The function signatures are: ```rust fn write(writer: W, value: V) -> io::Result + +fn fmt(writer: W, value: V) -> fmt::Result ``` where `itoa::Integer` is implemented for `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, diff --git a/src/lib.rs b/src/lib.rs index 08c452c..86bb7c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,13 +15,18 @@ #[cfg(feature = "i128")] mod udiv128; -use std::{io, mem, ptr, slice}; +use std::{fmt, io, mem, ptr, slice, str}; #[inline] pub fn write(wr: W, value: V) -> io::Result { value.write(wr) } +#[inline] +pub fn fmt(wr: W, value: V) -> fmt::Result { + value.fmt(wr) +} + // Seal to prevent downstream implementations of the Integer trait. mod private { pub trait Sealed {} @@ -29,6 +34,8 @@ mod private { pub trait Integer: private::Sealed { fn write(self, W) -> io::Result; + + fn fmt(self, W) -> fmt::Result; } trait IntegerPrivate { @@ -55,6 +62,12 @@ macro_rules! impl_IntegerCommon { try!(wr.write_all(bytes)); Ok(bytes.len()) } + + fn fmt(self, mut wr: W) -> fmt::Result { + let mut buf = unsafe { mem::uninitialized() }; + let bytes = self.write_to(&mut buf); + wr.write_str(unsafe { str::from_utf8_unchecked(bytes) }) + } } impl private::Sealed for $t {} diff --git a/tests/test.rs b/tests/test.rs index a360293..58b728e 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -20,6 +20,10 @@ macro_rules! test { let mut buf = [b'\0'; 40]; let len = itoa::write(&mut buf[..], $value).unwrap(); assert_eq!(&buf[0..len], $expected.as_bytes()); + + let mut s = String::new(); + itoa::fmt(&mut s, $value).unwrap(); + assert_eq!(s, $expected); } )* } From 70883abe4de1ebe4f64ba8afd8f6cc07f55a1c8c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 17 Mar 2018 10:14:54 +0900 Subject: [PATCH 4/4] Support no_std Fixes #3. --- .travis.yml | 2 ++ Cargo.toml | 2 ++ README.md | 3 +++ src/lib.rs | 9 +++++++++ tests/test.rs | 9 ++++++--- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a5a6db..0748cb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,5 +13,7 @@ matrix: script: - cargo build --verbose --features "$FEATURES" - cargo test --verbose --features "$FEATURES" + - cargo build --verbose --no-default-features --features "$FEATURES" + - cargo test --verbose --no-default-features --features "$FEATURES" - if [ "$BUILD_BENCH" == "true" ]; then cargo bench --verbose --no-run --features "$FEATURES"; fi diff --git a/Cargo.toml b/Cargo.toml index 62b8fe6..3123045 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,6 @@ readme = "README.md" exclude = ["performance.png"] [features] +default = ["std"] i128 = [] +std = [] diff --git a/README.md b/README.md index 999faba..491c602 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,9 @@ where `itoa::Integer` is implemented for `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, only available with the nightly compiler when the `i128` feature is enabled for this crate. The return value gives the number of bytes written. +The `write` function is only available when the `std` feature is enabled +(default is enabled). + ## Dependency Itoa is available on [crates.io](https://crates.io/crates/itoa). Use the diff --git a/src/lib.rs b/src/lib.rs index 86bb7c8..11971f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,8 @@ #![doc(html_root_url = "https://docs.rs/itoa/0.3.4")] +#![cfg_attr(not(feature = "std"), no_std)] + #![cfg_attr(feature = "i128", feature(i128_type, i128))] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless, unreadable_literal))] @@ -15,8 +17,13 @@ #[cfg(feature = "i128")] mod udiv128; +#[cfg(feature = "std")] use std::{fmt, io, mem, ptr, slice, str}; +#[cfg(not(feature = "std"))] +use core::{fmt, mem, ptr, slice, str}; + +#[cfg(feature = "std")] #[inline] pub fn write(wr: W, value: V) -> io::Result { value.write(wr) @@ -33,6 +40,7 @@ mod private { } pub trait Integer: private::Sealed { + #[cfg(feature = "std")] fn write(self, W) -> io::Result; fn fmt(self, W) -> fmt::Result; @@ -56,6 +64,7 @@ const MAX_LEN: usize = 40; // i128::MIN (including minus sign) macro_rules! impl_IntegerCommon { ($t:ident) => { impl Integer for $t { + #[cfg(feature = "std")] fn write(self, mut wr: W) -> io::Result { let mut buf = unsafe { mem::uninitialized() }; let bytes = self.write_to(&mut buf); diff --git a/tests/test.rs b/tests/test.rs index 58b728e..ad7c3d7 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -17,9 +17,12 @@ macro_rules! test { $(#[$attr])* #[test] fn $name() { - let mut buf = [b'\0'; 40]; - let len = itoa::write(&mut buf[..], $value).unwrap(); - assert_eq!(&buf[0..len], $expected.as_bytes()); + #[cfg(feature = "std")] + { + let mut buf = [b'\0'; 40]; + let len = itoa::write(&mut buf[..], $value).unwrap(); + assert_eq!(&buf[0..len], $expected.as_bytes()); + } let mut s = String::new(); itoa::fmt(&mut s, $value).unwrap();