use sval::stream::{
self,
stack,
Stack,
Stream,
};
use crate::{
std::{
fmt::{
self,
Write,
},
mem,
},
End,
};
pub fn to_fmt(fmt: impl Write, v: impl sval::Value) -> Result<(), sval::Error> {
let fmt = Formatter::new(fmt);
sval::stream(fmt, v)
}
pub struct Formatter<W> {
stack: Stack,
delim: Option<char>,
out: W,
}
impl<W> Formatter<W>
where
W: Write,
{
pub fn new(out: W) -> Self {
Formatter {
stack: Stack::new(),
delim: None,
out,
}
}
pub fn is_valid(&self) -> bool {
self.stack.can_end()
}
pub fn end(mut self) -> Result<W, End<Self>> {
match self.stack.end() {
Ok(()) => Ok(self.out),
Err(e) => Err(End::new(e, self)),
}
}
pub fn into_inner_unchecked(self) -> W {
self.out
}
#[inline]
fn next_delim(pos: stack::Pos) -> Option<char> {
if pos.is_value() || pos.is_elem() {
return Some(',');
}
if pos.is_key() {
return Some(':');
}
return None;
}
}
impl<W> Stream for Formatter<W>
where
W: Write,
{
#[inline]
fn fmt(&mut self, v: stream::Arguments) -> stream::Result {
let pos = self.stack.primitive()?;
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_char('"')?;
fmt::write(&mut Escape(&mut self.out), v)?;
self.out.write_char('"')?;
Ok(())
}
#[inline]
fn i64(&mut self, v: i64) -> stream::Result {
let pos = self.stack.primitive()?;
if pos.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_str(itoa::Buffer::new().format(v))?;
Ok(())
}
#[inline]
fn u64(&mut self, v: u64) -> stream::Result {
let pos = self.stack.primitive()?;
if pos.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_str(itoa::Buffer::new().format(v))?;
Ok(())
}
#[inline]
fn f64(&mut self, v: f64) -> stream::Result {
let pos = self.stack.primitive()?;
if pos.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_str(ryu::Buffer::new().format(v))?;
Ok(())
}
#[inline]
fn bool(&mut self, v: bool) -> stream::Result {
let pos = self.stack.primitive()?;
if pos.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_str(if v { "true" } else { "false" })?;
Ok(())
}
#[inline]
fn char(&mut self, v: char) -> stream::Result {
let pos = self.stack.primitive()?;
if pos.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_char(v)?;
Ok(())
}
#[inline]
fn str(&mut self, v: &str) -> stream::Result {
let pos = self.stack.primitive()?;
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_char('"')?;
escape_str(&v, &mut self.out)?;
self.out.write_char('"')?;
Ok(())
}
#[inline]
fn none(&mut self) -> stream::Result {
let pos = self.stack.primitive()?;
if pos.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = mem::replace(&mut self.delim, Self::next_delim(pos)) {
self.out.write_char(delim)?;
}
self.out.write_str("null")?;
Ok(())
}
#[inline]
fn seq_begin(&mut self, _: Option<usize>) -> stream::Result {
if self.stack.seq_begin()?.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = self.delim.take() {
self.out.write_char(delim)?;
}
self.out.write_char('[')?;
Ok(())
}
#[inline]
fn seq_elem(&mut self) -> stream::Result {
self.stack.seq_elem()?;
Ok(())
}
#[inline]
fn seq_end(&mut self) -> stream::Result {
let pos = self.stack.seq_end()?;
self.delim = Self::next_delim(pos);
self.out.write_char(']')?;
Ok(())
}
#[inline]
fn map_begin(&mut self, _: Option<usize>) -> stream::Result {
if self.stack.map_begin()?.is_key() {
return Err(stream::Error::msg(
"only strings are supported as json keys",
));
}
if let Some(delim) = self.delim.take() {
self.out.write_char(delim)?;
}
self.out.write_char('{')?;
Ok(())
}
#[inline]
fn map_key(&mut self) -> stream::Result {
self.stack.map_key()?;
Ok(())
}
#[inline]
fn map_value(&mut self) -> stream::Result {
self.stack.map_value()?;
Ok(())
}
#[inline]
fn map_end(&mut self) -> stream::Result {
let pos = self.stack.map_end()?;
self.delim = Self::next_delim(pos);
self.out.write_char('}')?;
Ok(())
}
}
#[inline]
fn escape_str(value: &str, mut out: impl Write) -> Result<(), fmt::Error> {
let bytes = value.as_bytes();
let mut start = 0;
for (i, &byte) in bytes.iter().enumerate() {
let escape = ESCAPE[byte as usize];
if escape == 0 {
continue;
}
if start < i {
out.write_str(&value[start..i])?;
}
match escape {
self::BB => out.write_str("\\b")?,
self::TT => out.write_str("\\t")?,
self::NN => out.write_str("\\n")?,
self::FF => out.write_str("\\f")?,
self::RR => out.write_str("\\r")?,
self::QU => out.write_str("\\\"")?,
self::BS => out.write_str("\\\\")?,
self::U => {
static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
out.write_str("\\u00")?;
out.write_char(HEX_DIGITS[(byte >> 4) as usize] as char)?;
out.write_char(HEX_DIGITS[(byte & 0xF) as usize] as char)?;
}
_ => unreachable!(),
}
start = i + 1;
}
if start != bytes.len() {
out.write_str(&value[start..])?;
}
Ok(())
}
const BB: u8 = b'b';
const TT: u8 = b't';
const NN: u8 = b'n';
const FF: u8 = b'f';
const RR: u8 = b'r';
const QU: u8 = b'"';
const BS: u8 = b'\\';
const U: u8 = b'u';
#[rustfmt::skip]
static ESCAPE: [u8; 256] = [
U, U, U, U, U, U, U, U, BB, TT, NN, U, FF, RR, U, U,
U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
0, 0, QU, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, BS, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
struct Escape<W>(W);
impl<W> Write for Escape<W>
where
W: Write,
{
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
escape_str(s, &mut self.0)
}
}