use crate::{Write, WriteError};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ScopeKind {
Array,
Object,
}
#[derive(Copy, Clone)]
struct Scope {
kind: ScopeKind,
tail: bool,
key: bool,
}
pub struct Serializer<W, const DEPTH: usize = 32> {
writer: W,
scopes: [Scope; DEPTH],
depth: usize,
pub pp: usize,
}
#[derive(Debug)]
pub enum SerializeError<E> {
Write(E),
DepthExceeded,
InvalidState,
InvalidUtf8(usize),
InvalidValue(&'static str),
}
impl<E> From<E> for SerializeError<E> {
fn from(e: E) -> Self {
SerializeError::Write(e)
}
}
impl<E: core::fmt::Display> core::fmt::Display for SerializeError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Write(e) => write!(f, "write error: {e}"),
Self::DepthExceeded => f.write_str("nesting depth exceeded"),
Self::InvalidState => f.write_str("invalid serializer call order"),
Self::InvalidValue(m) => write!(f, "invalid value: {m}"),
Self::InvalidUtf8(off) => write!(f, "invalid utf-8 generated at: {off}"),
}
}
}
#[cfg(feature = "std")]
impl<E: std::error::Error + 'static> std::error::Error for SerializeError<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
SerializeError::Write(e) => Some(e),
_ => None,
}
}
}
impl<W: Write, const DEPTH: usize> Serializer<W, DEPTH> {
pub fn new(writer: W) -> Self {
Self {
writer,
scopes: [Scope { kind: ScopeKind::Array, tail: false, key: false }; DEPTH],
depth: 0,
pp: 0,
}
}
pub fn with_pp(writer: W, indent: usize) -> Self {
let mut s = Self::new(writer);
s.pp = indent;
s
}
pub fn into_writer(self) -> W {
self.writer
}
fn write(&mut self, b: &[u8]) -> Result<(), SerializeError<W::Error>> {
self.writer.write_bytes(b).map_err(SerializeError::Write)
}
fn current_scope(&mut self) -> Option<&mut Scope> {
if self.depth > 0 {
Some(&mut self.scopes[self.depth - 1])
} else {
None
}
}
fn element_begin(&mut self) -> Result<(), SerializeError<W::Error>> {
let (tail, key, depth) = if let Some(s) = self.current_scope() {
(s.tail, s.key, self.depth)
} else {
return Ok(());
};
if tail && !key {
self.write(b",")?;
}
if self.pp > 0 {
if key {
self.write(b" ")?;
} else {
self.write(b"\n")?;
for _ in 0..depth * self.pp {
self.write(b" ")?;
}
}
}
Ok(())
}
fn element_end(&mut self) {
if let Some(s) = self.current_scope() {
s.tail = true;
s.key = false;
}
}
fn push_scope(&mut self, kind: ScopeKind) -> Result<(), SerializeError<W::Error>> {
if self.depth >= DEPTH {
return Err(SerializeError::DepthExceeded);
}
self.scopes[self.depth] = Scope { kind, tail: false, key: false };
self.depth += 1;
Ok(())
}
fn pop_scope(&mut self) {
if self.depth > 0 {
self.depth -= 1;
}
}
fn write_closing(&mut self, close: &[u8]) -> Result<(), SerializeError<W::Error>> {
let (tail, depth) = if let Some(s) = self.current_scope() {
(s.tail, self.depth)
} else {
(false, 0)
};
if self.pp > 0 && tail {
self.write(b"\n")?;
for _ in 0..(depth.saturating_sub(1)) * self.pp {
self.write(b" ")?;
}
}
self.write(close)
}
fn write_integer_raw(&mut self, x: i64) -> Result<(), SerializeError<W::Error>> {
if x < 0 {
self.write(b"-")?;
let u = if x == i64::MIN {
(i64::MAX as u64) + 1
} else {
(-x) as u64
};
return self.write_u64_raw(u);
}
self.write_u64_raw(x as u64)
}
fn write_u64_raw(&mut self, x: u64) -> Result<(), SerializeError<W::Error>> {
if x == 0 {
return self.write(b"0");
}
let mut buf = [0u8; 20];
let mut i = 20usize;
let mut n = x;
while n > 0 {
i -= 1;
buf[i] = b'0' + (n % 10) as u8;
n /= 10;
}
self.write(&buf[i..])
}
fn write_u128_raw(&mut self, x: u128) -> Result<(), SerializeError<W::Error>> {
if x == 0 {
return self.write(b"0");
}
let mut buf = [0u8; 39]; let mut i = 39usize;
let mut n = x;
while n > 0 {
i -= 1;
buf[i] = b'0' + (n % 10) as u8;
n /= 10;
}
self.write(&buf[i..])
}
fn write_i128_raw(&mut self, x: i128) -> Result<(), SerializeError<W::Error>> {
if x < 0 {
self.write(b"-")?;
let u = if x == i128::MIN {
(i128::MAX as u128) + 1
} else {
(-x) as u128
};
return self.write_u128_raw(u);
}
self.write_u128_raw(x as u128)
}
fn write_string_escaped(&mut self, bytes: &[u8]) -> Result<(), SerializeError<W::Error>> {
self.write(b"\"")?;
let mut i = 0;
while i < bytes.len() {
let ch = bytes[i];
match ch {
b'"' => { self.write(b"\\\"")?; i += 1; }
b'\\' => { self.write(b"\\\\")?; i += 1; }
0x08 => { self.write(b"\\b")?; i += 1; }
0x09 => { self.write(b"\\t")?; i += 1; }
0x0A => { self.write(b"\\n")?; i += 1; }
0x0B => { self.escape_byte(ch)?; i += 1; }
0x0C => { self.write(b"\\f")?; i += 1; }
0x0D => { self.write(b"\\r")?; i += 1; }
0x20..=0x7E => {
let start = i;
while i < bytes.len() && matches!(bytes[i], 0x20..=0x7E)
&& bytes[i] != b'"' && bytes[i] != b'\\'
{
i += 1;
}
self.write(&bytes[start..i])?;
}
_ => {
let seq_len = utf8_char_len(ch);
if seq_len == 1 || i + seq_len > bytes.len() {
self.escape_byte(ch)?;
i += 1;
continue;
}
let mut valid = true;
for j in 1..seq_len {
if (bytes[i + j] & 0b1100_0000) != 0b1000_0000 {
valid = false;
break;
}
}
if valid {
self.write(&bytes[i..i + seq_len])?;
i += seq_len;
} else {
self.escape_byte(ch)?;
i += 1;
}
}
}
}
self.write(b"\"")
}
pub fn null(&mut self) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write(b"null")?;
self.element_end();
Ok(())
}
pub fn boolean(&mut self, v: bool) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write(if v { b"true" } else { b"false" })?;
self.element_end();
Ok(())
}
pub fn integer(&mut self, v: i64) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write_integer_raw(v)?;
self.element_end();
Ok(())
}
pub fn float(&mut self, v: f64) -> Result<(), SerializeError<W::Error>> {
if !v.is_finite() {
return Err(SerializeError::InvalidValue("float must be finite (not NaN or Infinity)"));
}
let mut buf = [0u8; 32];
let mut pos = 0usize;
struct FloatBuf<'a>(&'a mut [u8], &'a mut usize);
impl core::fmt::Write for FloatBuf<'_> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let b = s.as_bytes();
let end = *self.1 + b.len();
if end > self.0.len() { return Err(core::fmt::Error); }
self.0[*self.1..end].copy_from_slice(b);
*self.1 = end;
Ok(())
}
}
let _ = core::fmt::write(&mut FloatBuf(&mut buf, &mut pos), format_args!("{v}"));
self.element_begin()?;
self.number_raw(&buf[..pos])?;
self.element_end();
Ok(())
}
pub fn unsigned(&mut self, v: u64) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write_u64_raw(v)?;
self.element_end();
Ok(())
}
pub fn integer128(&mut self, v: i128) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write_i128_raw(v)?;
self.element_end();
Ok(())
}
pub fn unsigned128(&mut self, v: u128) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write_u128_raw(v)?;
self.element_end();
Ok(())
}
pub fn number_raw(&mut self, raw: &[u8]) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write(raw)?;
self.element_end();
Ok(())
}
pub fn string(&mut self, s: &str) -> Result<(), SerializeError<W::Error>> {
self.string_bytes(s.as_bytes())
}
pub fn string_bytes(&mut self, b: &[u8]) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write_string_escaped(b)?;
self.element_end();
Ok(())
}
pub fn array_begin(&mut self) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write(b"[")?;
self.push_scope(ScopeKind::Array)?;
Ok(())
}
pub fn array_end(&mut self) -> Result<(), SerializeError<W::Error>> {
self.write_closing(b"]")?;
self.pop_scope();
self.element_end();
Ok(())
}
pub fn object_begin(&mut self) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
self.write(b"{")?;
self.push_scope(ScopeKind::Object)?;
Ok(())
}
pub fn member(&mut self, key: &str) -> Result<(), SerializeError<W::Error>> {
self.member_bytes(key.as_bytes())
}
pub fn member_bytes(&mut self, key: &[u8]) -> Result<(), SerializeError<W::Error>> {
self.element_begin()?;
match self.current_scope() {
Some(s) if s.kind == ScopeKind::Object && !s.key => {}
_ => return Err(SerializeError::InvalidState),
}
self.write_string_escaped(key)?;
self.write(b":")?;
if let Some(s) = self.current_scope() {
s.tail = true;
s.key = true;
}
Ok(())
}
pub fn object_end(&mut self) -> Result<(), SerializeError<W::Error>> {
self.write_closing(b"}")?;
self.pop_scope();
self.element_end();
Ok(())
}
fn escape_byte(&mut self, ch: u8) -> Result<(), SerializeError<W::Error>> {
const HEX: &[u8; 16] = b"0123456789abcdef";
self.write(b"\\u00")?;
self.write(&[
HEX[(ch >> 4) as usize],
HEX[(ch & 0x0F) as usize],
])?;
Ok(())
}
}
fn utf8_char_len(first_byte: u8) -> usize {
if first_byte & 0x80 == 0 { 1 }
else if first_byte & 0xE0 == 0xC0 { 2 }
else if first_byte & 0xF0 == 0xE0 { 3 }
else if first_byte & 0xF8 == 0xF0 { 4 }
else { 1 } }
pub trait Serialize {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>>;
}
impl Serialize for bool {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.boolean(*self)
}
}
macro_rules! impl_integer {
($($t:ty),*) => {$(
impl Serialize for $t {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.integer(*self as i64)
}
}
)*};
}
impl_integer!(i8, i16, i32, i64, u8, u16, u32, isize);
impl Serialize for u64 {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.unsigned(*self)
}
}
impl Serialize for usize {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.unsigned(*self as u64)
}
}
impl Serialize for i128 {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.integer128(*self)
}
}
impl Serialize for u128 {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.unsigned128(*self)
}
}
impl Serialize for str {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.string(self)
}
}
impl Serialize for &str {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.string(self)
}
}
#[cfg(feature = "alloc")]
impl Serialize for alloc::string::String {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.string(self)
}
}
impl<T: Serialize> Serialize for Option<T> {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
match self {
None => ser.null(),
Some(v) => v.serialize(ser),
}
}
}
impl<T: Serialize> Serialize for [T] {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.array_begin()?;
for item in self {
item.serialize(ser)?;
}
ser.array_end()
}
}
impl<T: Serialize, const N: usize> Serialize for [T; N] {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
self.as_slice().serialize(ser)
}
}
impl Serialize for f32 {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.float(*self as f64)
}
}
impl Serialize for f64 {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.float(*self as f64)
}
}
#[cfg(feature = "alloc")]
impl<T: Serialize> Serialize for alloc::vec::Vec<T> {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
self.as_slice().serialize(ser)
}
}
#[cfg(feature = "alloc")]
impl<T: Serialize> Serialize for alloc::boxed::Box<T> {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
(**self).serialize(ser)
}
}
macro_rules! impl_serialize_map {
($($bound:tt)*) => {
fn serialize<__W: Write>(&self, ser: &mut Serializer<__W>) -> Result<(), SerializeError<__W::Error>> {
ser.object_begin()?;
for (k, v) in self {
ser.member(k.as_ref())?;
v.serialize(ser)?;
}
ser.object_end()
}
};
}
#[cfg(feature = "alloc")]
impl<K: AsRef<str>, V: Serialize> Serialize for alloc::collections::BTreeMap<K, V> {
impl_serialize_map!();
}
#[cfg(feature = "std")]
impl<K: AsRef<str> + Eq + std::hash::Hash, V: Serialize> Serialize
for std::collections::HashMap<K, V>
{
impl_serialize_map!();
}
#[cfg(feature = "arrayvec")]
impl<T: Serialize, const N: usize> Serialize for arrayvec::ArrayVec<T, N> {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
self.as_slice().serialize(ser)
}
}
#[cfg(feature = "arrayvec")]
impl<const N: usize> Serialize for arrayvec::ArrayString<N> {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.string(self.as_str())
}
}
impl Serialize for () {
fn serialize<W: Write>(&self, ser: &mut Serializer<W>) -> Result<(), SerializeError<W::Error>> {
ser.null()
}
}
#[inline]
pub fn stringify_sized_as<'buf>(
buf: &'buf mut [u8],
f: impl FnOnce(&mut Serializer<&mut crate::write::SliceWriter<'_>>) -> Result<(), SerializeError<WriteError>>,
) -> Result<&'buf str, SerializeError<WriteError>> {
let mut w = crate::write::SliceWriter::new(buf);
let mut ser = Serializer::new(&mut w);
f(&mut ser)?;
let len = w.pos();
core::str::from_utf8(&buf[..len]).map_err(
|e| SerializeError::InvalidUtf8(e.valid_up_to())
)
}
#[inline]
pub fn stringify_sized<'buf, T: Serialize>(
buf: &'buf mut [u8],
val: &T,
) -> Result<&'buf str, SerializeError<WriteError>> {
stringify_sized_as(buf, |s| val.serialize(s))
}
#[inline]
pub fn stringify_sized_pretty_as<'buf>(
buf: &'buf mut [u8],
indent: usize,
f: impl FnOnce(&mut Serializer<&mut crate::write::SliceWriter<'_>>) -> Result<(), SerializeError<WriteError>>,
) -> Result<&'buf str, SerializeError<WriteError>> {
let mut w = crate::write::SliceWriter::new(buf);
let mut ser = Serializer::with_pp(&mut w, indent);
f(&mut ser)?;
let len = w.pos();
core::str::from_utf8(&buf[..len]).map_err(
|e| SerializeError::InvalidUtf8(e.valid_up_to())
)
}
#[inline]
pub fn stringify_sized_pretty<'buf, T: Serialize>(
buf: &'buf mut [u8],
indent: usize,
val: &T,
) -> Result<&'buf str, SerializeError<WriteError>> {
stringify_sized_pretty_as(buf, indent, |s| val.serialize(s))
}
#[inline]
pub fn measure(
f: impl FnOnce(&mut Serializer<&mut crate::write::SizeCounter>) -> Result<(), SerializeError<core::convert::Infallible>>,
) -> usize {
let mut counter = crate::write::SizeCounter::new();
let mut ser = Serializer::new(&mut counter);
let _ = f(&mut ser);
counter.count
}
#[cfg(feature = "std")]
#[inline]
pub fn stringify<T: Serialize>(
val: &T,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
stringify_as(|s| val.serialize(s))
}
#[cfg(feature = "std")]
#[inline]
pub fn stringify_as(
f: impl FnOnce(&mut Serializer<std::vec::Vec<u8>>) -> Result<(), SerializeError<core::convert::Infallible>>,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
let mut ser: Serializer<_> = Serializer::new(std::vec::Vec::new());
f(&mut ser)?;
let vec = ser.into_writer();
std::string::String::from_utf8(vec).map_err(
|e| SerializeError::InvalidUtf8(e.utf8_error().error_len().unwrap_or(0))
)
}
#[cfg(feature = "std")]
#[inline]
pub fn stringify_pretty<T: Serialize>(
indent: usize,
val: &T,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
stringify_pretty_as(indent, |s| val.serialize(s))
}
#[cfg(feature = "std")]
#[inline]
pub fn stringify_pretty_as(
indent: usize,
f: impl FnOnce(&mut Serializer<std::vec::Vec<u8>>) -> Result<(), SerializeError<core::convert::Infallible>>,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
let mut ser: Serializer<_> = Serializer::with_pp(std::vec::Vec::new(), indent);
f(&mut ser)?;
let vec = ser.into_writer();
std::string::String::from_utf8(vec).map_err(
|e| SerializeError::InvalidUtf8(e.utf8_error().error_len().unwrap_or(0))
)
}
#[cfg(feature = "std")]
#[test]
fn outputs_invalid_utf8_for_malformed_sequence() {
let input = [0xE2u8, 0x28, 0xA1];
let json = stringify_as(|s| s.string_bytes(&input)).unwrap();
let ans = r#""\u00e2(\u00a1""#;
assert_eq!(json, ans);
assert!(std::str::from_utf8(json.as_bytes()).is_ok(),
"Output is not valid UTF-8: {:?}", json);
}
#[test]
fn escapes_vertical_tab_as_unicode() {
let mut out = [0u8; 16];
let json = stringify_sized_as(&mut out, |s| s.string_bytes(&[0x0B])).unwrap();
assert_eq!(&json[..], r#""\u000b""#);
}