use crate::{Error, ErrorKind, Position};
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::string::String;
pub trait JsonWrite {
type Error;
#[inline]
fn reserve_hint(&mut self, _additional: usize) {}
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error>;
#[inline]
#[allow(unsafe_code)]
unsafe fn write_byte_unchecked(&mut self, b: u8) -> Result<(), Self::Error> {
self.write_byte(b)
}
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error>;
#[inline]
fn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.write_byte(b'"')?;
for &b in s.as_bytes() {
write_escape_byte(self, b)?;
}
self.write_byte(b'"')
}
#[inline]
fn write_raw_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error> {
let s = core::str::from_utf8(b).expect("write_raw_bytes input must be valid UTF-8");
self.write_str_raw(s)
}
#[inline]
fn write_int_i64(&mut self, n: i64) -> Result<(), Self::Error> {
let mut buf = [0u8; 20];
let s = format_i64(n, &mut buf);
self.write_str_raw(s)
}
#[inline]
fn write_int_u64(&mut self, n: u64) -> Result<(), Self::Error> {
let mut buf = [0u8; 20];
let s = format_u64(n, &mut buf);
self.write_str_raw(s)
}
#[inline]
fn write_int_i128(&mut self, n: i128) -> Result<(), Self::Error> {
let mut buf = [0u8; 40];
let s = format_i128(n, &mut buf);
self.write_str_raw(s)
}
#[inline]
fn write_int_u128(&mut self, n: u128) -> Result<(), Self::Error> {
let mut buf = [0u8; 40];
let s = format_u128(n, &mut buf);
self.write_str_raw(s)
}
#[cfg(feature = "alloc")]
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error>;
#[cfg(feature = "alloc")]
#[inline]
#[allow(unsafe_code)]
unsafe fn write_float_f64_unchecked(&mut self, f: f64) -> Result<(), Self::Error> {
self.write_float_f64(f)
}
#[cfg(feature = "alloc")]
#[inline]
#[allow(unsafe_code)]
unsafe fn write_float_f64_unchecked_finite(&mut self, f: f64) -> Result<(), Self::Error> {
unsafe { self.write_float_f64_unchecked(f) }
}
#[cfg(feature = "alloc")]
#[inline]
#[allow(unsafe_code)]
unsafe fn write_float_f64_taint(&mut self, f: f64) -> Result<(), Self::Error> {
unsafe { self.write_float_f64_unchecked(f) }
}
#[inline]
fn take_nonfinite_taint(&mut self) -> u64 {
0
}
}
const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
const ESCAPE_TABLE: [u8; 256] = {
let mut t = [0u8; 256];
t[b'"' as usize] = b'"';
t[b'\\' as usize] = b'\\';
t[b'\n' as usize] = b'n';
t[b'\r' as usize] = b'r';
t[b'\t' as usize] = b't';
t[0x08] = b'b';
t[0x0C] = b'f';
t
};
fn write_escape_byte<W: JsonWrite + ?Sized>(w: &mut W, b: u8) -> Result<(), W::Error> {
let esc = ESCAPE_TABLE[b as usize];
if esc != 0 {
w.write_byte(b'\\')?;
return w.write_byte(esc);
}
if b < 0x20 {
w.write_byte(b'\\')?;
w.write_byte(b'u')?;
w.write_byte(b'0')?;
w.write_byte(b'0')?;
w.write_byte(HEX_LOWER[(b >> 4) as usize])?;
return w.write_byte(HEX_LOWER[(b & 0x0F) as usize]);
}
w.write_byte(b)
}
#[cfg(feature = "alloc")]
#[inline]
const fn needs_escape(b: u8) -> bool {
b == b'"' || b == b'\\' || b < 0x20
}
#[cfg(feature = "alloc")]
#[derive(Debug)]
pub struct StringSink<'a> {
out: &'a mut String,
}
#[cfg(feature = "alloc")]
impl<'a> StringSink<'a> {
#[must_use]
pub const fn new(out: &'a mut String) -> Self {
Self { out }
}
}
#[cfg(feature = "alloc")]
impl JsonWrite for StringSink<'_> {
type Error = Error;
#[inline]
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
self.out.push(b as char);
Ok(())
}
#[inline]
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error> {
self.out.push_str(s);
Ok(())
}
fn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.out.push('"');
let bytes = s.as_bytes();
let mut i = 0;
let mut start = 0;
while i < bytes.len() {
let b = bytes[i];
if needs_escape(b) {
if start < i {
self.out.push_str(&s[start..i]);
}
write_escape_byte(self, b)?;
start = i + 1;
}
i += 1;
}
if start < bytes.len() {
self.out.push_str(&s[start..]);
}
self.out.push('"');
Ok(())
}
#[inline]
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error> {
float::format_f64_write(f, self.out)
}
}
#[cfg(feature = "alloc")]
#[derive(Debug)]
pub struct ByteSink<'a> {
out: &'a mut alloc::vec::Vec<u8>,
nonfinite_taint: u64,
}
#[cfg(feature = "alloc")]
impl<'a> ByteSink<'a> {
#[must_use]
pub const fn new(out: &'a mut alloc::vec::Vec<u8>) -> Self {
Self {
out,
nonfinite_taint: 0,
}
}
}
#[cfg(feature = "alloc")]
impl JsonWrite for ByteSink<'_> {
type Error = Error;
#[inline]
fn reserve_hint(&mut self, additional: usize) {
self.out.reserve(additional);
}
#[inline]
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
self.out.push(b);
Ok(())
}
#[inline]
#[allow(unsafe_code)]
unsafe fn write_byte_unchecked(&mut self, b: u8) -> Result<(), Self::Error> {
unsafe {
let len = self.out.len();
let ptr = self.out.as_mut_ptr().add(len);
core::ptr::write(ptr, b);
self.out.set_len(len + 1);
}
Ok(())
}
#[inline]
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error> {
self.out.extend_from_slice(s.as_bytes());
Ok(())
}
#[inline]
fn write_raw_bytes(&mut self, b: &[u8]) -> Result<(), Self::Error> {
self.out.extend_from_slice(b);
Ok(())
}
fn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.out.push(b'"');
let bytes = s.as_bytes();
let mut i = 0;
let mut start = 0;
while i < bytes.len() {
let b = bytes[i];
if needs_escape(b) {
if start < i {
self.out.extend_from_slice(&bytes[start..i]);
}
write_escape_byte(self, b)?;
start = i + 1;
}
i += 1;
}
if start < bytes.len() {
self.out.extend_from_slice(&bytes[start..]);
}
self.out.push(b'"');
Ok(())
}
#[inline]
fn write_int_i64(&mut self, n: i64) -> Result<(), Self::Error> {
if n >= 0 {
#[allow(clippy::cast_sign_loss)]
return self.write_int_u64(n as u64);
}
self.out.push(b'-');
#[allow(clippy::cast_possible_truncation)]
let mag = i128::from(n).unsigned_abs() as u64;
self.write_int_u64(mag)
}
#[inline]
fn write_int_u64(&mut self, n: u64) -> Result<(), Self::Error> {
format_u64_direct(n, self.out);
Ok(())
}
#[inline]
fn write_int_i128(&mut self, n: i128) -> Result<(), Self::Error> {
let mut buf = [0u8; 40];
let s = format_i128(n, &mut buf);
self.out.extend_from_slice(s.as_bytes());
Ok(())
}
#[inline]
fn write_int_u128(&mut self, n: u128) -> Result<(), Self::Error> {
let mut buf = [0u8; 40];
let s = format_u128(n, &mut buf);
self.out.extend_from_slice(s.as_bytes());
Ok(())
}
#[inline]
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error> {
if crate::float::format_finite_to_vec(f, self.out) {
Ok(())
} else {
Err(Error::new(ErrorKind::NonFiniteFloat, Position::START))
}
}
#[inline]
#[allow(unsafe_code)]
unsafe fn write_float_f64_unchecked(&mut self, f: f64) -> Result<(), Self::Error> {
if unsafe { crate::float::format_finite_to_vec_unchecked(f, self.out) } {
Ok(())
} else {
cold_nonfinite_byte_sink()
}
}
#[inline]
#[allow(unsafe_code)]
unsafe fn write_float_f64_unchecked_finite(&mut self, f: f64) -> Result<(), Self::Error> {
unsafe { crate::float::format_finite_to_vec_unchecked_finite(f, self.out) };
Ok(())
}
#[inline]
#[allow(unsafe_code)]
unsafe fn write_float_f64_taint(&mut self, f: f64) -> Result<(), Self::Error> {
self.nonfinite_taint |= unsafe { crate::float::format_finite_to_vec_taint(f, self.out) };
Ok(())
}
#[inline]
fn take_nonfinite_taint(&mut self) -> u64 {
core::mem::take(&mut self.nonfinite_taint)
}
}
#[cfg(feature = "alloc")]
#[cold]
#[inline(never)]
const fn cold_nonfinite_byte_sink() -> Result<(), Error> {
Err(Error::new(ErrorKind::NonFiniteFloat, Position::START))
}
const DIGIT_LUT: &[u8; 200] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";
#[inline]
#[allow(clippy::cast_possible_truncation)]
fn fast_digit_count(n: u64) -> usize {
static TABLE: [(u8, u64); 64] = [
(19, 9_999_999_999_999_999_999), (19, 9_223_372_036_854_775_807), (19, 4_611_686_018_427_387_903), (19, 2_305_843_009_213_693_951), (18, 999_999_999_999_999_999), (18, 576_460_752_303_423_487), (18, 288_230_376_151_711_743), (17, 99_999_999_999_999_999), (17, 72_057_594_037_927_935), (17, 36_028_797_018_963_967), (16, 9_999_999_999_999_999), (16, 9_007_199_254_740_991), (16, 4_503_599_627_370_495), (16, 2_251_799_813_685_247), (15, 999_999_999_999_999), (15, 562_949_953_421_311), (15, 281_474_976_710_655), (14, 99_999_999_999_999), (14, 70_368_744_177_663), (14, 35_184_372_088_831), (13, 9_999_999_999_999), (13, 8_796_093_022_207), (13, 4_398_046_511_103), (13, 2_199_023_255_551), (12, 999_999_999_999), (12, 549_755_813_887), (12, 274_877_906_943), (11, 99_999_999_999), (11, 68_719_476_735), (11, 34_359_738_367), (10, 9_999_999_999), (10, 8_589_934_591), (10, 4_294_967_295), (10, 2_147_483_647), (9, 999_999_999), (9, 536_870_911), (9, 268_435_455), (8, 99_999_999), (8, 67_108_863), (8, 33_554_431), (7, 9_999_999), (7, 8_388_607), (7, 4_194_303), (7, 2_097_151), (6, 999_999), (6, 524_287), (6, 262_143), (5, 99_999), (5, 65_535), (5, 32_767), (4, 9_999), (4, 8_191), (4, 4_095), (4, 2_047), (3, 999), (3, 511), (3, 255), (2, 99), (2, 63), (2, 31), (1, 9), (1, 7), (1, 3), (1, 1), ];
let lz = (n | 1).leading_zeros() as usize;
let (candidate, threshold) = TABLE[lz];
candidate as usize + usize::from(n > threshold)
}
#[inline]
#[allow(clippy::cast_possible_truncation, unsafe_code)]
fn write_digits_backward(mut n: u64, buf: *mut u8, end: usize) {
let mut pos = end;
while n >= 100 {
let r = (n % 100) as usize;
n /= 100;
pos -= 2;
unsafe {
*buf.add(pos) = DIGIT_LUT[r * 2];
*buf.add(pos + 1) = DIGIT_LUT[r * 2 + 1];
}
}
if n >= 10 {
let r = n as usize;
pos -= 2;
unsafe {
*buf.add(pos) = DIGIT_LUT[r * 2];
*buf.add(pos + 1) = DIGIT_LUT[r * 2 + 1];
}
} else {
pos -= 1;
unsafe {
*buf.add(pos) = b'0' + n as u8;
}
}
}
#[cfg(feature = "alloc")]
#[allow(clippy::cast_possible_truncation)]
fn format_u64_direct(n: u64, out: &mut alloc::vec::Vec<u8>) {
let digits = fast_digit_count(n);
out.reserve(digits);
let old_len = out.len();
#[allow(unsafe_code)]
unsafe {
let base = out.as_mut_ptr().add(old_len);
write_digits_backward(n, base, digits);
out.set_len(old_len + digits);
}
}
#[allow(clippy::cast_possible_truncation)]
fn format_u64(n: u64, buf: &mut [u8; 20]) -> &str {
let digits = fast_digit_count(n);
write_digits_backward(n, buf.as_mut_ptr(), digits);
core::str::from_utf8(&buf[..digits]).expect("integer formatter emits ASCII")
}
fn format_i64(n: i64, buf: &mut [u8; 20]) -> &str {
if n >= 0 {
#[allow(clippy::cast_sign_loss)]
return format_u64(n as u64, buf);
}
#[allow(clippy::cast_possible_truncation)]
let mag = i128::from(n).unsigned_abs() as u64;
let digits = fast_digit_count(mag);
buf[0] = b'-';
write_digits_backward(mag, buf[1..].as_mut_ptr(), digits);
let total = 1 + digits;
core::str::from_utf8(&buf[..total]).expect("integer formatter emits ASCII")
}
#[allow(clippy::cast_possible_truncation)]
fn format_u128(mut n: u128, buf: &mut [u8; 40]) -> &str {
let mut pos = buf.len();
while n >= 100 {
let r = (n % 100) as usize;
n /= 100;
pos -= 2;
buf[pos] = DIGIT_LUT[r * 2];
buf[pos + 1] = DIGIT_LUT[r * 2 + 1];
}
if n >= 10 {
let r = n as usize;
pos -= 2;
buf[pos] = DIGIT_LUT[r * 2];
buf[pos + 1] = DIGIT_LUT[r * 2 + 1];
} else {
pos -= 1;
buf[pos] = b'0' + n as u8;
}
core::str::from_utf8(&buf[pos..]).expect("integer formatter emits ASCII")
}
fn format_i128(n: i128, buf: &mut [u8; 40]) -> &str {
if n >= 0 {
#[allow(clippy::cast_sign_loss)]
return format_u128(n as u128, buf);
}
let mag = n.unsigned_abs();
let mut tmp = [0u8; 40];
let s = format_u128(mag, &mut tmp);
let len = s.len();
buf[0] = b'-';
buf[1..=len].copy_from_slice(s.as_bytes());
let total = 1 + len;
core::str::from_utf8(&buf[..total]).expect("integer formatter emits ASCII")
}
#[cfg(feature = "alloc")]
pub mod float {
use super::{Error, ErrorKind, Position};
use alloc::string::String;
#[inline]
const fn reject_non_finite(f: f64) -> Result<(), Error> {
if f.is_finite() {
Ok(())
} else {
Err(Error::new(ErrorKind::NonFiniteFloat, Position::START))
}
}
#[inline]
pub fn format_f64_write(f: f64, out: &mut String) -> Result<(), Error> {
reject_non_finite(f)?;
crate::float::format_finite(f, out);
Ok(())
}
}
pub trait ToJson {
const MIN_SERIALIZED_LEN: usize = 0;
const MAX_SERIALIZED_LEN: usize = 0;
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error>;
#[inline]
#[allow(unsafe_code)]
unsafe fn write_json_in_reserved<W: JsonWrite + ?Sized>(
&self,
w: &mut W,
) -> Result<(), W::Error> {
self.write_json(w)
}
const NEEDS_VALIDATION: bool = false;
#[inline]
fn pre_validate_slice(slice: &[Self]) -> Result<(), Error>
where
Self: Sized,
{
let _ = slice;
Ok(())
}
}
#[cfg(feature = "alloc")]
#[allow(clippy::missing_panics_doc)]
pub fn to_string<T: ToJson + ?Sized>(value: &T) -> Result<String, Error> {
let bytes = to_vec(value)?;
Ok(String::from_utf8(bytes).expect("json-bourne emits only valid UTF-8"))
}
#[cfg(feature = "alloc")]
pub fn to_vec<T: ToJson + ?Sized>(value: &T) -> Result<alloc::vec::Vec<u8>, Error> {
let cap = if T::MIN_SERIALIZED_LEN > 128 {
T::MIN_SERIALIZED_LEN
} else {
128
};
let mut out = alloc::vec::Vec::with_capacity(cap);
let mut sink = ByteSink::new(&mut out);
value.write_json(&mut sink)?;
Ok(out)
}
#[cfg(feature = "alloc")]
#[derive(Debug)]
pub struct FmtWriteSink<'a, W: ?Sized> {
out: &'a mut W,
}
#[cfg(feature = "alloc")]
impl<'a, W: core::fmt::Write + ?Sized> FmtWriteSink<'a, W> {
pub const fn new(out: &'a mut W) -> Self {
Self { out }
}
}
#[cfg(feature = "alloc")]
impl<W: core::fmt::Write + ?Sized> JsonWrite for FmtWriteSink<'_, W> {
type Error = Error;
#[inline]
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
self.out
.write_char(b as char)
.map_err(|_| fmt_write_error())
}
#[inline]
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error> {
self.out.write_str(s).map_err(|_| fmt_write_error())
}
#[inline]
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error> {
if !f.is_finite() {
return Err(Error::new(ErrorKind::NonFiniteFloat, Position::START));
}
crate::float::format_finite_fmt(f, self.out).map_err(|_| fmt_write_error())
}
}
#[cfg(feature = "alloc")]
#[inline]
const fn fmt_write_error() -> Error {
Error::new(ErrorKind::TypeMismatch, Position::START)
}
#[cfg(feature = "std")]
#[derive(Debug)]
pub struct IoWriteSink<'a, W: ?Sized> {
out: &'a mut W,
}
#[cfg(feature = "std")]
impl<'a, W: std::io::Write + ?Sized> IoWriteSink<'a, W> {
pub const fn new(out: &'a mut W) -> Self {
Self { out }
}
}
#[cfg(feature = "std")]
struct IoFmtAdapter<'a, W: std::io::Write + ?Sized> {
inner: &'a mut W,
err: Option<std::io::Error>,
}
#[cfg(feature = "std")]
impl<W: std::io::Write + ?Sized> core::fmt::Write for IoFmtAdapter<'_, W> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
match self.inner.write_all(s.as_bytes()) {
Ok(()) => Ok(()),
Err(e) => {
self.err = Some(e);
Err(core::fmt::Error)
}
}
}
}
#[cfg(feature = "std")]
impl<W: std::io::Write + ?Sized> JsonWrite for IoWriteSink<'_, W> {
type Error = std::io::Error;
#[inline]
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
self.out.write_all(&[b])
}
#[inline]
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error> {
self.out.write_all(s.as_bytes())
}
#[inline]
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error> {
if !f.is_finite() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"non-finite float not representable in JSON",
));
}
let mut adapter = IoFmtAdapter {
inner: self.out,
err: None,
};
match crate::float::format_finite_fmt(f, &mut adapter) {
Ok(()) => Ok(()),
Err(_) => Err(adapter
.err
.unwrap_or_else(|| std::io::Error::other("fmt error in float formatter"))),
}
}
}
#[cfg(feature = "std")]
pub fn to_writer<T: ToJson + ?Sized, W: std::io::Write>(
value: &T,
writer: &mut W,
) -> Result<(), std::io::Error> {
let mut sink = IoWriteSink::new(writer);
value.write_json(&mut sink)
}
#[cfg(feature = "alloc")]
pub fn to_fmt<T: ToJson + ?Sized, W: core::fmt::Write + ?Sized>(
value: &T,
writer: &mut W,
) -> Result<(), Error> {
let mut sink = FmtWriteSink::new(writer);
value.write_json(&mut sink)
}
#[cfg(feature = "alloc")]
#[derive(Debug)]
pub struct PrettyStringSink<'a> {
out: &'a mut String,
indent: &'static str,
depth: usize,
pending_open: Option<u8>,
}
#[cfg(feature = "alloc")]
impl<'a> PrettyStringSink<'a> {
#[must_use]
pub const fn new(out: &'a mut String) -> Self {
Self {
out,
indent: " ",
depth: 0,
pending_open: None,
}
}
#[must_use]
pub const fn with_indent(out: &'a mut String, indent: &'static str) -> Self {
Self {
out,
indent,
depth: 0,
pending_open: None,
}
}
fn flush_pending_open(&mut self) {
if let Some(b) = self.pending_open.take() {
self.out.push(b as char);
self.depth += 1;
self.newline_and_indent();
}
}
fn newline_and_indent(&mut self) {
self.out.push('\n');
for _ in 0..self.depth {
self.out.push_str(self.indent);
}
}
}
#[cfg(feature = "alloc")]
impl JsonWrite for PrettyStringSink<'_> {
type Error = Error;
fn write_byte(&mut self, b: u8) -> Result<(), Self::Error> {
match b {
b'[' | b'{' => {
self.flush_pending_open();
self.pending_open = Some(b);
Ok(())
}
b']' | b'}' => {
if let Some(open) = self.pending_open.take() {
self.out.push(open as char);
self.out.push(b as char);
return Ok(());
}
self.depth -= 1;
self.newline_and_indent();
self.out.push(b as char);
Ok(())
}
b',' => {
debug_assert!(self.pending_open.is_none());
self.out.push(',');
self.newline_and_indent();
Ok(())
}
b':' => {
self.out.push_str(": ");
Ok(())
}
_ => {
self.flush_pending_open();
self.out.push(b as char);
Ok(())
}
}
}
fn write_str_raw(&mut self, s: &str) -> Result<(), Self::Error> {
if s.is_empty() {
return Ok(());
}
self.flush_pending_open();
self.out.push_str(s);
Ok(())
}
fn write_escaped_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.flush_pending_open();
let mut inner = StringSink::new(self.out);
inner.write_escaped_str(s)
}
fn write_float_f64(&mut self, f: f64) -> Result<(), Self::Error> {
self.flush_pending_open();
float::format_f64_write(f, self.out)
}
}
#[cfg(feature = "alloc")]
pub fn to_string_pretty<T: ToJson + ?Sized>(value: &T) -> Result<String, Error> {
let mut out = String::with_capacity(256);
let mut sink = PrettyStringSink::new(&mut out);
value.write_json(&mut sink)?;
Ok(out)
}
impl ToJson for bool {
const MIN_SERIALIZED_LEN: usize = 4; const MAX_SERIALIZED_LEN: usize = 5; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_str_raw(if *self { "true" } else { "false" })
}
}
impl ToJson for () {
const MIN_SERIALIZED_LEN: usize = 4; const MAX_SERIALIZED_LEN: usize = 4;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_str_raw("null")
}
}
impl ToJson for str {
const MIN_SERIALIZED_LEN: usize = 2; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_escaped_str(self)
}
}
macro_rules! impl_int_signed {
($($t:ty),* $(,)?) => {
$(
impl ToJson for $t {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 20;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_int_i64(i64::from(*self))
}
}
)*
};
}
macro_rules! impl_int_unsigned {
($($t:ty),* $(,)?) => {
$(
impl ToJson for $t {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 20;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_int_u64(u64::from(*self))
}
}
)*
};
}
impl_int_signed!(i8, i16, i32, i64);
impl_int_unsigned!(u8, u16, u32, u64);
#[allow(clippy::cast_possible_wrap, clippy::cast_lossless, clippy::use_self)]
impl ToJson for isize {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 20;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_int_i64(*self as i64)
}
}
#[allow(clippy::cast_lossless, clippy::use_self)]
impl ToJson for usize {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 20;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_int_u64(*self as u64)
}
}
impl ToJson for i128 {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 40;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_int_i128(*self)
}
}
impl ToJson for u128 {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 39;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_int_u128(*self)
}
}
impl<T: ToJson> ToJson for Option<T> {
const MIN_SERIALIZED_LEN: usize = 4; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
match self {
None => w.write_str_raw("null"),
Some(v) => v.write_json(w),
}
}
}
impl<T: ToJson + ?Sized> ToJson for &T {
const MIN_SERIALIZED_LEN: usize = T::MIN_SERIALIZED_LEN;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
(*self).write_json(w)
}
}
fn write_array<T: ToJson, I: IntoIterator<Item = T>, W: JsonWrite + ?Sized>(
iter: I,
w: &mut W,
) -> Result<(), W::Error> {
w.write_byte(b'[')?;
let mut iter = iter.into_iter();
if let Some(v) = iter.next() {
v.write_json(w)?;
for v in iter {
w.write_byte(b',')?;
v.write_json(w)?;
}
}
w.write_byte(b']')
}
#[allow(unsafe_code)]
unsafe fn write_array_reserved<T: ToJson, W: JsonWrite + ?Sized>(
slice: &[T],
w: &mut W,
) -> Result<(), W::Error> {
unsafe {
w.write_byte_unchecked(b'[')?;
}
if let Some((first, rest)) = slice.split_first() {
unsafe { first.write_json_in_reserved(w) }?;
for v in rest {
unsafe { w.write_byte_unchecked(b',') }?;
unsafe { v.write_json_in_reserved(w) }?;
}
}
unsafe { w.write_byte_unchecked(b']') }
}
impl<T: ToJson> ToJson for [T] {
const MIN_SERIALIZED_LEN: usize = 2; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
if T::MAX_SERIALIZED_LEN != 0 {
#[cfg(feature = "alloc")]
{
if T::NEEDS_VALIDATION && T::pre_validate_slice(self).is_err() {
return w.write_float_f64(f64::NAN);
}
}
let hint = self
.len()
.saturating_mul(T::MAX_SERIALIZED_LEN.saturating_add(1))
.saturating_add(2);
w.reserve_hint(hint);
#[allow(unsafe_code)]
let res = unsafe { write_array_reserved(self, w) };
#[cfg(feature = "alloc")]
{
let taint = w.take_nonfinite_taint();
if taint != 0 {
return w.write_float_f64(f64::NAN);
}
}
return res;
}
write_array(self.iter(), w)
}
}
impl<T: ToJson, const N: usize> ToJson for [T; N] {
const MIN_SERIALIZED_LEN: usize = 2; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
(self as &[T]).write_json(w)
}
}
macro_rules! impl_tuple_to_json {
($first_idx:tt: $First:ident $(, $idx:tt: $T:ident)* $(,)?) => {
impl<$First: ToJson $(, $T: ToJson)*> ToJson for ($First, $($T,)*) {
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_byte(b'[')?;
self.$first_idx.write_json(w)?;
$(
w.write_byte(b',')?;
self.$idx.write_json(w)?;
)*
w.write_byte(b']')
}
}
};
}
impl_tuple_to_json!(0: A);
impl_tuple_to_json!(0: A, 1: B);
impl_tuple_to_json!(0: A, 1: B, 2: C);
impl_tuple_to_json!(0: A, 1: B, 2: C, 3: D);
impl_tuple_to_json!(0: A, 1: B, 2: C, 3: D, 4: E);
impl_tuple_to_json!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
#[cfg(feature = "alloc")]
mod alloc_impls {
use super::{Error, JsonWrite, ToJson};
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
impl ToJson for String {
const MIN_SERIALIZED_LEN: usize = 2; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_escaped_str(self.as_str())
}
}
impl ToJson for Cow<'_, str> {
const MIN_SERIALIZED_LEN: usize = 2; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_escaped_str(self.as_ref())
}
}
impl ToJson for f64 {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 32;
const NEEDS_VALIDATION: bool = false;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_float_f64(*self)
}
#[inline]
#[allow(unsafe_code)]
unsafe fn write_json_in_reserved<W: JsonWrite + ?Sized>(
&self,
w: &mut W,
) -> Result<(), W::Error> {
unsafe { w.write_float_f64_taint(*self) }
}
#[inline]
fn pre_validate_slice(_slice: &[Self]) -> Result<(), Error> {
Ok(())
}
}
impl ToJson for f32 {
const MIN_SERIALIZED_LEN: usize = 1;
const MAX_SERIALIZED_LEN: usize = 32;
const NEEDS_VALIDATION: bool = false;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_float_f64(f64::from(*self))
}
#[inline]
#[allow(unsafe_code)]
unsafe fn write_json_in_reserved<W: JsonWrite + ?Sized>(
&self,
w: &mut W,
) -> Result<(), W::Error> {
unsafe { w.write_float_f64_taint(f64::from(*self)) }
}
}
impl ToJson for char {
const MIN_SERIALIZED_LEN: usize = 3; fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
let mut buf = [0u8; 4];
let s: &str = self.encode_utf8(&mut buf);
w.write_escaped_str(s)
}
}
impl<T: ToJson + ?Sized> ToJson for Box<T> {
const MIN_SERIALIZED_LEN: usize = T::MIN_SERIALIZED_LEN;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
(**self).write_json(w)
}
}
impl<T: ToJson + ?Sized> ToJson for Rc<T> {
const MIN_SERIALIZED_LEN: usize = T::MIN_SERIALIZED_LEN;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
(**self).write_json(w)
}
}
impl<T: ToJson + ?Sized> ToJson for Arc<T> {
const MIN_SERIALIZED_LEN: usize = T::MIN_SERIALIZED_LEN;
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
(**self).write_json(w)
}
}
impl<T: ToJson> ToJson for alloc::vec::Vec<T> {
const MIN_SERIALIZED_LEN: usize = 2; #[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
self.as_slice().write_json(w)
}
}
pub trait MapKeyOut {
fn as_str(&self) -> &str;
}
impl MapKeyOut for String {
#[inline]
fn as_str(&self) -> &str {
self
}
}
impl MapKeyOut for &str {
#[inline]
fn as_str(&self) -> &str {
self
}
}
impl MapKeyOut for Cow<'_, str> {
#[inline]
fn as_str(&self) -> &str {
self.as_ref()
}
}
fn write_object<'a, K, V, I, W>(iter: I, w: &mut W) -> Result<(), W::Error>
where
K: MapKeyOut + 'a,
V: ToJson + 'a,
I: IntoIterator<Item = (&'a K, &'a V)>,
W: JsonWrite + ?Sized,
{
w.write_byte(b'{')?;
let mut first = true;
for (k, v) in iter {
if !first {
w.write_byte(b',')?;
}
w.write_escaped_str(k.as_str())?;
w.write_byte(b':')?;
v.write_json(w)?;
first = false;
}
w.write_byte(b'}')
}
impl<K: MapKeyOut, V: ToJson> ToJson for alloc::collections::BTreeMap<K, V> {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_object(self.iter(), w)
}
}
impl<T: ToJson> ToJson for alloc::collections::BTreeSet<T> {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
super::write_array(self.iter(), w)
}
}
#[cfg(feature = "std")]
impl<K, V, S> ToJson for std::collections::HashMap<K, V, S>
where
K: MapKeyOut + ::core::hash::Hash + Eq,
V: ToJson,
S: ::core::hash::BuildHasher,
{
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_object(self.iter(), w)
}
}
#[cfg(feature = "std")]
impl<T, S> ToJson for std::collections::HashSet<T, S>
where
T: ToJson + ::core::hash::Hash + Eq,
S: ::core::hash::BuildHasher,
{
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
super::write_array(self.iter(), w)
}
}
#[cfg(feature = "std")]
impl ToJson for std::time::SystemTime {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
let secs = match self.duration_since(std::time::UNIX_EPOCH) {
Ok(d) => d.as_secs_f64(),
Err(e) => -e.duration().as_secs_f64(),
};
w.write_float_f64(secs)
}
}
#[cfg(feature = "std")]
impl ToJson for std::time::Duration {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_float_f64(self.as_secs_f64())
}
}
#[cfg(feature = "std")]
fn write_display<T: ::core::fmt::Display, W: JsonWrite + ?Sized>(
v: &T,
w: &mut W,
) -> Result<(), W::Error> {
use ::core::fmt::Write as _;
let mut buf = String::new();
let _ = write!(&mut buf, "{v}");
w.write_escaped_str(&buf)
}
#[cfg(feature = "std")]
impl ToJson for std::net::IpAddr {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_display(self, w)
}
}
#[cfg(feature = "std")]
impl ToJson for std::net::Ipv4Addr {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_display(self, w)
}
}
#[cfg(feature = "std")]
impl ToJson for std::net::Ipv6Addr {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_display(self, w)
}
}
#[cfg(feature = "std")]
impl ToJson for std::net::SocketAddr {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_display(self, w)
}
}
#[cfg(feature = "std")]
impl ToJson for std::path::PathBuf {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_escaped_str(&self.to_string_lossy())
}
}
#[cfg(feature = "std")]
impl ToJson for std::path::Path {
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
w.write_escaped_str(&self.to_string_lossy())
}
}
#[cfg(feature = "indexmap")]
impl<K, V, S> ToJson for indexmap::IndexMap<K, V, S>
where
K: super::MapKeyOut + ::core::hash::Hash + Eq,
V: ToJson,
S: ::core::hash::BuildHasher,
{
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
write_object(self.iter(), w)
}
}
#[cfg(feature = "indexmap")]
impl<T, S> ToJson for indexmap::IndexSet<T, S>
where
T: ToJson + ::core::hash::Hash + Eq,
S: ::core::hash::BuildHasher,
{
#[inline]
fn write_json<W: JsonWrite + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> {
super::write_array(self.iter(), w)
}
}
}
#[cfg(feature = "alloc")]
pub use alloc_impls::MapKeyOut;
#[allow(dead_code)]
const _: fn() -> Error = || Error::new(ErrorKind::NonFiniteFloat, Position::START);