Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use from_utf8_unchecked in the fmt::Display implementation of Value #751

Merged
merged 1 commit into from Feb 5, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 34 additions & 16 deletions src/value/mod.rs
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