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,
}
}
}
macro_rules! write_uint_raw {
($self:expr, $x:expr, $t:ty, $buf_size:literal) => {{
let x: $t = $x;
if x == 0 { return $self.write(b"0"); }
let mut buf = [0u8; $buf_size];
let mut i = $buf_size;
let mut n = x;
while n > 0 { i -= 1; buf[i] = b'0' + (n % 10) as u8; n /= 10; }
$self.write(&buf[i..])
}};
}
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_pretty(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"-")?; }
self.write_u64_raw(x.unsigned_abs())
}
fn write_u64_raw(&mut self, x: u64) -> Result<(), SerializeError<W::Error>> {
write_uint_raw!(self, x, u64, 20)
}
fn write_u128_raw(&mut self, x: u128) -> Result<(), SerializeError<W::Error>> {
write_uint_raw!(self, x, u128, 39)
}
fn write_i128_raw(&mut self, x: i128) -> Result<(), SerializeError<W::Error>> {
if x < 0 { self.write(b"-")?; }
self.write_u128_raw(x.unsigned_abs())
}
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()
}
}
fn stringify_sized_impl<'buf>(
buf: &'buf mut [u8],
pp: 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_pretty(&mut w, pp);
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_as<'buf>(
buf: &'buf mut [u8],
f: impl FnOnce(&mut Serializer<&mut crate::write::SliceWriter<'_>>) -> Result<(), SerializeError<WriteError>>,
) -> Result<&'buf str, SerializeError<WriteError>> {
stringify_sized_impl(buf, 0, f)
}
#[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>> {
stringify_sized_impl(buf, indent, f)
}
#[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")]
fn serialize_to_vec(
pp: usize,
f: impl FnOnce(&mut Serializer<std::vec::Vec<u8>>) -> Result<(), SerializeError<core::convert::Infallible>>,
) -> Result<std::vec::Vec<u8>, SerializeError<core::convert::Infallible>> {
let mut ser: Serializer<_> = Serializer::with_pretty(std::vec::Vec::new(), pp);
f(&mut ser)?;
Ok(ser.into_writer())
}
#[cfg(feature = "std")]
fn vec_to_string(
vec: std::vec::Vec<u8>,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
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<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>> {
vec_to_string(serialize_to_vec(0, f)?)
}
#[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>> {
vec_to_string(serialize_to_vec(indent, f)?)
}
#[cfg(feature = "std")]
fn apply_smart_format(
compact: std::vec::Vec<u8>,
line_width: usize,
indent: usize,
) -> std::vec::Vec<u8> {
if compact.is_empty() { return compact };
let mut out = std::vec::Vec::with_capacity(compact.len() * 2);
smart_format(&compact, &mut 0, &mut out, line_width, indent, 0);
out
}
#[cfg(feature = "std")]
fn skip_string_end(input: &[u8], pos: &mut usize) {
*pos += 1; loop {
match input[*pos] {
b'\\' => *pos += 2, b'"' => { *pos += 1; return; }
_ => *pos += 1,
}
}
}
#[cfg(feature = "std")]
fn find_container_end(input: &[u8], start: usize) -> usize {
let mut pos = start + 1;
let mut depth = 1usize;
loop {
match input[pos] {
b'"' => skip_string_end(input, &mut pos),
b'{' | b'[' => { depth += 1; pos += 1; }
b'}' | b']' => {
pos += 1;
depth -= 1;
if depth == 0 { return pos; }
}
_ => pos += 1,
}
}
}
#[cfg(feature = "std")]
fn find_value_end(input: &[u8], start: usize) -> usize {
match input[start] {
b'{' | b'[' => find_container_end(input, start),
b'"' => {
let mut pos = start;
skip_string_end(input, &mut pos);
pos
}
b't' => start + 4,
b'f' => start + 5,
b'n' => start + 4,
_ => {
let mut pos = start;
while pos < input.len() {
match input[pos] {
b'0'..=b'9' | b'.' | b'e' | b'E' | b'+' | b'-' => pos += 1,
_ => break,
}
}
pos
}
}
}
#[cfg(feature = "std")]
fn spaced_len(input: &[u8], start: usize, end: usize) -> usize {
let mut len = end - start;
let mut pos = start;
while pos < end {
match input[pos] {
b'"' => skip_string_end(input, &mut pos),
b':' | b',' => { len += 1; pos += 1; }
_ => pos += 1,
}
}
len
}
#[cfg(feature = "std")]
fn copy_with_spacing(input: &[u8], start: usize, end: usize, out: &mut std::vec::Vec<u8>) {
let mut pos = start;
while pos < end {
match input[pos] {
b'"' => {
let s = pos;
skip_string_end(input, &mut pos);
out.extend_from_slice(&input[s..pos]);
}
b':' | b',' => {
out.push(input[pos]);
out.push(b' ');
pos += 1;
}
b => {
out.push(b);
pos += 1;
}
}
}
}
#[cfg(feature = "std")]
fn write_indent(out: &mut std::vec::Vec<u8>, depth: usize, indent: usize) {
let n = depth * indent;
out.resize(out.len() + n, b' ');
}
#[cfg(feature = "std")]
fn measure_value(input: &[u8], scan: usize, line_width: usize) -> (usize, bool) {
let val_end = find_value_end(input, scan);
let is_container = matches!(input[scan], b'{' | b'[');
let inline = !is_container || val_end - scan <= line_width;
let display = if inline { spaced_len(input, scan, val_end) } else { 0 };
(display, inline)
}
#[cfg(feature = "std")]
fn format_expanded(
input: &[u8],
pos: &mut usize,
out: &mut std::vec::Vec<u8>,
line_width: usize,
indent: usize,
depth: usize,
) {
let is_object = input[*pos] == b'{';
let open = input[*pos];
let close = if is_object { b'}' } else { b']' };
out.push(open);
*pos += 1;
if input[*pos] == close {
out.push(close);
*pos += 1;
return;
}
out.push(b'\n');
write_indent(out, depth + 1, indent);
let base_indent = (depth + 1) * indent;
let mut current_col = base_indent;
let mut first = true;
while input[*pos] != close {
let (elem_display_len, value_is_inline) = {
let mut scan = *pos;
if is_object {
let key_start = scan;
skip_string_end(input, &mut scan); let key_display = spaced_len(input, key_start, scan);
scan += 1; let (val_display, val_inline) = measure_value(input, scan, line_width);
(key_display + 2 + val_display, val_inline) } else {
measure_value(input, scan, line_width)
}
};
let sep = if first { 0 } else { 2 }; let needs_new_line = !first
&& (!value_is_inline || current_col + sep + elem_display_len > line_width);
if needs_new_line {
out.extend_from_slice(b",\n");
write_indent(out, depth + 1, indent);
current_col = base_indent;
} else if !first {
out.extend_from_slice(b", ");
current_col += 2;
}
if is_object {
let key_start = *pos;
skip_string_end(input, pos);
out.extend_from_slice(&input[key_start..*pos]);
out.extend_from_slice(b": ");
*pos += 1; }
if value_is_inline {
let val_end = find_value_end(input, *pos);
copy_with_spacing(input, *pos, val_end, out);
*pos = val_end;
current_col += elem_display_len;
} else {
format_expanded(input, pos, out, line_width, indent, depth + 1);
current_col = line_width.saturating_add(1);
}
if input[*pos] == b',' {
*pos += 1;
}
first = false;
}
out.push(b'\n');
write_indent(out, depth, indent);
out.push(close);
*pos += 1;
}
#[cfg(feature = "std")]
fn smart_format(
input: &[u8],
pos: &mut usize,
out: &mut std::vec::Vec<u8>,
line_width: usize,
indent: usize,
depth: usize,
) {
match input[*pos] {
b'{' | b'[' => {
let end = find_container_end(input, *pos);
if end - *pos <= line_width {
copy_with_spacing(input, *pos, end, out);
*pos = end;
} else {
format_expanded(input, pos, out, line_width, indent, depth);
}
}
_ => {
let end = find_value_end(input, *pos);
out.extend_from_slice(&input[*pos..end]);
*pos = end;
}
}
}
#[cfg(feature = "std")]
#[inline]
pub fn stringify_compact_as(
line_width: usize,
indent: usize,
f: impl FnOnce(&mut Serializer<std::vec::Vec<u8>>) -> Result<(), SerializeError<core::convert::Infallible>>,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
vec_to_string(apply_smart_format(serialize_to_vec(0, f)?, line_width, indent))
}
#[cfg(feature = "std")]
#[inline]
pub fn stringify_compact<T: Serialize>(
val: &T,
line_width: usize,
indent: usize,
) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
stringify_compact_as(line_width, indent, |s| val.serialize(s))
}
#[cfg(feature = "std")]
pub struct SmartSerializer {
inner: Serializer<std::vec::Vec<u8>>,
line_width: usize,
indent: usize,
}
#[cfg(feature = "std")]
impl SmartSerializer {
pub fn with_compact(line_width: usize, indent: usize) -> Self {
Self { inner: Serializer::new(std::vec::Vec::new()), line_width, indent }
}
pub fn finish(self) -> Result<std::string::String, SerializeError<core::convert::Infallible>> {
vec_to_string(apply_smart_format(self.inner.into_writer(), self.line_width, self.indent))
}
}
#[cfg(feature = "std")]
impl core::ops::Deref for SmartSerializer {
type Target = Serializer<std::vec::Vec<u8>>;
fn deref(&self) -> &Self::Target { &self.inner }
}
#[cfg(feature = "std")]
impl core::ops::DerefMut for SmartSerializer {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
}