Skip to content

Commit

Permalink
Merge pull request #751 from icewind1991/value-display-utf8-unchecked
Browse files Browse the repository at this point in the history
use from_utf8_unchecked in the fmt::Display implementation of Value
  • Loading branch information
dtolnay authored Feb 5, 2021
2 parents 7ff8ec6 + e0747b9 commit e81e7d9
Showing 1 changed file with 34 additions and 16 deletions.
50 changes: 34 additions & 16 deletions src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@
//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html

use crate::error::Error;
use crate::io;
use crate::lib::*;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
Expand Down Expand Up @@ -191,27 +190,43 @@ impl Debug for Value {
}
}

struct WriterFormatter<'a, 'b: 'a> {
inner: &'a mut fmt::Formatter<'b>,
}
// WriterFormatter is in it's own little module to enforce using the unsafe constructor
mod writer_formatter {
use crate::io;
use crate::lib::*;

pub struct WriterFormatter<'a, 'b: 'a> {
inner: &'a mut fmt::Formatter<'b>,
}

impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn io_error<E>(_: E) -> io::Error {
// Error value does not matter because fmt::Display impl below just
// maps it to fmt::Error
io::Error::new(io::ErrorKind::Other, "fmt error")
impl<'a, 'b: 'a> WriterFormatter<'a, 'b> {
/// Safety: the caller needs to ensure that only valid utf8 bytes are written into this writer
pub unsafe fn new(inner: &'a mut fmt::Formatter<'b>) -> Self {
Self { inner }
}
let s = tri!(str::from_utf8(buf).map_err(io_error));
tri!(self.inner.write_str(s).map_err(io_error));
Ok(buf.len())
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn io_error<E>(_: E) -> io::Error {
// Error value does not matter because fmt::Display impl below just
// maps it to fmt::Error
io::Error::new(io::ErrorKind::Other, "fmt error")
}
// The safety requirements of passing in valid utf8 is passed trough to the caller trough the unsafe `new` method
let s = unsafe { str::from_utf8_unchecked(buf) };
tri!(self.inner.write_str(s).map_err(io_error));
Ok(buf.len())
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
}

use writer_formatter::WriterFormatter;

impl fmt::Display for Value {
/// Display a JSON value as a string.
///
Expand Down Expand Up @@ -239,7 +254,10 @@ impl fmt::Display for Value {
/// ```
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let alternate = f.alternate();
let mut wr = WriterFormatter { inner: f };
let mut wr = unsafe {
// The serializer only emits valid json with the default formatters
WriterFormatter::new(f)
};
if alternate {
// {:#}
super::ser::to_writer_pretty(&mut wr, self).map_err(|_| fmt::Error)
Expand Down

0 comments on commit e81e7d9

Please sign in to comment.