Merge pull request #20 from Marwes/buffer

feat: Provide a safe API to write integers to a buffer
This commit is contained in:
David Tolnay 2018-09-08 12:00:25 -07:00 committed by GitHub
commit 762dedb54c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 44 additions and 24 deletions

View File

@ -26,14 +26,44 @@ use core::{fmt, mem, ptr, slice, str};
/// Write integer to an `io::Write`. /// Write integer to an `io::Write`.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[inline] #[inline]
pub fn write<W: io::Write, V: Integer>(wr: W, value: V) -> io::Result<usize> { pub fn write<W: io::Write, V: Integer>(mut wr: W, value: V) -> io::Result<usize> {
value.write(wr) let mut buf = Buffer::new();
let s = buf.format(value);
try!(wr.write_all(s.as_bytes()));
Ok(s.len())
} }
/// Write integer to an `fmt::Write`. /// Write integer to an `fmt::Write`.
#[inline] #[inline]
pub fn fmt<W: fmt::Write, V: Integer>(wr: W, value: V) -> fmt::Result { pub fn fmt<W: fmt::Write, V: Integer>(mut wr: W, value: V) -> fmt::Result {
value.fmt(wr) let mut buf = Buffer::new();
wr.write_str(buf.format(value))
}
/// A safe API for formatting integers to text.
#[derive(Copy, Clone)]
pub struct Buffer {
bytes: [u8; I128_MAX_LEN],
}
impl Default for Buffer {
fn default() -> Buffer {
Buffer::new()
}
}
impl Buffer {
/// This is a cheap operation; you don't need to worry about reusing buffers
/// for efficiency.
pub fn new() -> Buffer {
Buffer { bytes: unsafe { mem::uninitialized() } }
}
/// Print an integer into this buffer and return a reference to its string representation
/// within the buffer
pub fn format<I: Integer>(&mut self, i: I) -> &str {
i.write(self)
}
} }
// Seal to prevent downstream implementations of the Integer trait. // Seal to prevent downstream implementations of the Integer trait.
@ -47,12 +77,7 @@ mod private {
pub trait Integer: private::Sealed { pub trait Integer: private::Sealed {
// Not public API. // Not public API.
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "std")] fn write<'a>(self, buf: &'a mut Buffer) -> &'a str;
fn write<W: io::Write>(self, W) -> io::Result<usize>;
// Not public API.
#[doc(hidden)]
fn fmt<W: fmt::Write>(self, W) -> fmt::Result;
} }
trait IntegerPrivate<B> { trait IntegerPrivate<B> {
@ -71,20 +96,16 @@ const DEC_DIGITS_LUT: &'static[u8] =
macro_rules! impl_IntegerCommon { macro_rules! impl_IntegerCommon {
($max_len:expr, $t:ident) => { ($max_len:expr, $t:ident) => {
impl Integer for $t { impl Integer for $t {
#[cfg(feature = "std")]
#[inline] #[inline]
fn write<W: io::Write>(self, mut wr: W) -> io::Result<usize> { fn write<'a>(self, buf: &'a mut Buffer) -> &'a str {
let mut buf: [u8; $max_len] = unsafe { mem::uninitialized() }; unsafe {
let bytes = self.write_to(&mut buf); debug_assert!($max_len <= I128_MAX_LEN);
try!(wr.write_all(bytes)); let buf = mem::transmute::<&mut [u8; I128_MAX_LEN], &mut [u8; $max_len]>(
Ok(bytes.len()) &mut buf.bytes
} );
let bytes = self.write_to(buf);
#[inline] str::from_utf8_unchecked(bytes)
fn fmt<W: fmt::Write>(self, mut wr: W) -> fmt::Result { }
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) })
} }
} }
@ -254,7 +275,6 @@ macro_rules! impl_Integer128 {
#[cfg(all(feature = "i128"))] #[cfg(all(feature = "i128"))]
const U128_MAX_LEN: usize = 39; const U128_MAX_LEN: usize = 39;
#[cfg(all(feature = "i128"))]
const I128_MAX_LEN: usize = 40; const I128_MAX_LEN: usize = 40;
#[cfg(all(feature = "i128"))] #[cfg(all(feature = "i128"))]