use alloc::boxed::Box;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::mem::ManuallyDrop;
use deser_core::ext::RawInput;
use deser_core::ext::{BigInt, Decimal, ExtValue, Number};
use deser_core::ser::SerializeRef;
use deser_core::ser::{self, EventSink, SerializeDriver};
use deser_core::{Atom, BytesFormat, Error, ErrorKind, Event, Implicit, ImplicitValue, Serialize};
use crate::Trailing;
use crate::buf::Buffer;
use crate::escape::find_escape;
use crate::pretty::PrettyWriter;
use crate::scan::skip_to_escape;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum Indent {
#[default]
None,
Spaces(usize),
Tab,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum InlinePolicy {
#[default]
Never,
LeafIfFits(usize),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SerializerConfig {
indent: Indent,
compact: bool,
inline: InlinePolicy,
trailing: Trailing,
non_finite_floats: bool,
context: deser_core::Context,
}
impl Default for SerializerConfig {
fn default() -> SerializerConfig {
SerializerConfig::new()
}
}
impl SerializerConfig {
pub const fn new() -> SerializerConfig {
SerializerConfig {
indent: Indent::None,
compact: true,
inline: InlinePolicy::Never,
trailing: Trailing::Strict,
non_finite_floats: false,
context: deser_core::Context::new(),
}
}
pub const fn builder() -> SerializerConfigBuilder {
SerializerConfigBuilder::new()
}
pub const fn into_builder(self) -> SerializerConfigBuilder {
SerializerConfigBuilder { value: self }
}
pub fn set_context(&mut self, context: deser_core::Context) {
self.context = context;
}
pub fn context(&self) -> &deser_core::Context {
&self.context
}
#[inline]
fn apply_context(&self, driver: &mut SerializeDriver<'_>) {
if !self.context.is_empty() {
driver.set_default_context(self.context.clone());
}
}
pub const fn set_trailing(&mut self, trailing: Trailing) {
self.trailing = trailing;
}
pub(crate) fn trailing_mode(&self) -> Trailing {
self.trailing
}
pub const fn set_indent(&mut self, indent: Indent) {
self.indent = indent;
}
pub const fn set_compact(&mut self, yes: bool) {
self.compact = yes;
}
pub const fn set_inline(&mut self, policy: InlinePolicy) {
self.inline = policy;
}
pub const fn set_pretty(&mut self, indent: Indent) {
self.indent = indent;
self.compact = matches!(indent, Indent::None);
}
pub const fn set_non_finite_floats(&mut self, yes: bool) {
self.non_finite_floats = yes;
}
#[inline]
pub fn to_string<T: Serialize + ?Sized>(&self, value: &T) -> Result<String, Error> {
let value = SerializeRef::new(&value);
if self.is_compact() {
self.to_string_compact(value)
} else {
self.to_string_pretty(value)
}
}
#[inline(never)]
fn to_string_compact(&self, value: SerializeRef<'_>) -> Result<String, Error> {
let mut driver = SerializeDriver::from_ref(value);
self.apply_context(&mut driver);
accept_raw(&mut driver);
self.serialize_compact(&mut driver)
}
#[inline(never)]
fn to_string_pretty(&self, value: SerializeRef<'_>) -> Result<String, Error> {
let mut driver = SerializeDriver::from_ref(value);
self.apply_context(&mut driver);
accept_raw(&mut driver);
self.serialize_pretty(&mut driver)
}
pub fn to_string_with<F, T: Serialize + ?Sized>(
&self,
value: &T,
setup: F,
) -> Result<String, Error>
where
F: FnOnce(&mut SerializeDriver<'_>),
{
let mut driver = SerializeDriver::new(&value);
setup(&mut driver);
self.apply_context(&mut driver);
self.serialize_driver(&mut driver)
}
#[inline]
pub(crate) fn serialize_driver(
&self,
driver: &mut SerializeDriver<'_>,
) -> Result<String, Error> {
accept_raw(driver);
if self.is_compact() {
self.serialize_compact(driver)
} else {
self.serialize_pretty(driver)
}
}
#[inline(always)]
fn is_compact(&self) -> bool {
self.indent == Indent::None && self.compact
}
#[inline(never)]
fn serialize_compact(&self, driver: &mut SerializeDriver<'_>) -> Result<String, Error> {
let bytes = BytesFormat::of(driver.state());
let mut writer = self.compact_writer(Buffer::with_capacity(128), bytes);
driver.drive_sink(&mut writer)?;
Ok(writer.ser.out.into_string())
}
#[inline(never)]
fn serialize_pretty(&self, driver: &mut SerializeDriver<'_>) -> Result<String, Error> {
let bytes = BytesFormat::of(driver.state());
let mut writer = self.pretty_writer(Buffer::with_capacity(128), bytes);
driver.drive(|event, state| writer.event(event, state))?;
Ok(writer.finish())
}
fn compact_writer(&self, out: Buffer, bytes: BytesFormat) -> Writer {
Writer {
ser: Output {
out,
bytes,
non_finite_floats: self.non_finite_floats,
},
stack: Vec::new(),
container: Container::Top,
first: true,
is_key: false,
limit: usize::MAX,
}
}
fn pretty_writer(&self, out: Buffer, bytes: BytesFormat) -> PrettyWriter {
let ser = Output {
out,
bytes,
non_finite_floats: self.non_finite_floats,
};
let inline_width = match self.inline {
InlinePolicy::Never => None,
InlinePolicy::LeafIfFits(width) => Some(width),
};
PrettyWriter::new(ser, self.indent, self.compact, inline_width)
}
pub(crate) fn value_writer(&self, out: Buffer, bytes: BytesFormat) -> ValueWriter {
if self.is_compact() {
ValueWriter::Compact(self.compact_writer(out, bytes))
} else {
ValueWriter::Pretty(self.pretty_writer(out, bytes))
}
}
}
#[derive(Debug, Clone)]
#[must_use]
pub struct SerializerConfigBuilder {
value: SerializerConfig,
}
impl SerializerConfigBuilder {
pub const fn new() -> SerializerConfigBuilder {
SerializerConfigBuilder {
value: SerializerConfig::new(),
}
}
pub const fn trailing(mut self, trailing: Trailing) -> SerializerConfigBuilder {
self.value.set_trailing(trailing);
self
}
pub const fn indent(mut self, indent: Indent) -> SerializerConfigBuilder {
self.value.set_indent(indent);
self
}
pub const fn compact(mut self, yes: bool) -> SerializerConfigBuilder {
self.value.set_compact(yes);
self
}
pub const fn inline(mut self, policy: InlinePolicy) -> SerializerConfigBuilder {
self.value.set_inline(policy);
self
}
pub const fn pretty(mut self, indent: Indent) -> SerializerConfigBuilder {
self.value.set_pretty(indent);
self
}
pub const fn non_finite_floats(mut self, yes: bool) -> SerializerConfigBuilder {
self.value.set_non_finite_floats(yes);
self
}
pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
self.value.set_context(context);
self
}
pub const fn build(self) -> SerializerConfig {
let value = unsafe { core::ptr::read(&self.value) };
core::mem::forget(self);
value
}
}
impl Default for SerializerConfigBuilder {
fn default() -> SerializerConfigBuilder {
SerializerConfigBuilder::new()
}
}
fn accept_raw(driver: &mut SerializeDriver<'_>) {
driver.state_mut().declare_raw_format(&crate::raw::ID);
}
pub(crate) enum ValueWriter {
Compact(Writer),
Pretty(PrettyWriter),
}
impl ValueWriter {
pub(crate) fn drive(
&mut self,
driver: &mut SerializeDriver<'_>,
limit: usize,
) -> Result<bool, Error> {
if limit == usize::MAX {
return self.drive_whole(driver).map(|()| true);
}
match self {
ValueWriter::Compact(writer) => {
writer.limit = limit;
driver.drive_until(writer)
}
ValueWriter::Pretty(writer) => {
writer.limit = limit;
driver.drive_until(writer)
}
}
}
pub(crate) fn drive_whole(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
match self {
ValueWriter::Compact(writer) => driver.drive_sink(writer),
ValueWriter::Pretty(writer) => driver.drive(|event, state| writer.event(event, state)),
}
}
pub(crate) fn output(&mut self) -> &mut Buffer {
match self {
ValueWriter::Compact(writer) => &mut writer.ser.out,
ValueWriter::Pretty(writer) => writer.output(),
}
}
pub(crate) fn take_output(&mut self) -> Vec<u8> {
match self {
ValueWriter::Compact(writer) => writer.ser.out.take(),
ValueWriter::Pretty(writer) => writer.take_output(),
}
}
}
pub struct Serializer {
config: SerializerConfig,
out: Vec<u8>,
written: usize,
value: Option<Box<ValueWriter>>,
in_progress: bool,
}
impl Default for Serializer {
fn default() -> Serializer {
Serializer::new()
}
}
impl Clone for Serializer {
fn clone(&self) -> Serializer {
Serializer {
config: self.config.clone(),
out: self.out.clone(),
written: self.written,
value: None,
in_progress: self.in_progress,
}
}
}
impl core::fmt::Debug for Serializer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Serializer")
.field("config", &self.config)
.field("output", &self.as_str())
.field("written", &self.written)
.field("in_progress", &self.in_progress)
.finish()
}
}
impl Serializer {
pub fn new() -> Serializer {
Serializer::with_config(SerializerConfig::new())
}
pub fn with_config(config: SerializerConfig) -> Serializer {
Serializer::with_written(config, 0)
}
pub fn with_written(config: SerializerConfig, written: usize) -> Serializer {
Serializer {
config,
out: Vec::new(),
written,
value: None,
in_progress: false,
}
}
pub fn config(&self) -> &SerializerConfig {
&self.config
}
pub fn written(&self) -> usize {
self.written
}
pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
ser::Serializer::serialize(self, value)
}
pub fn serialize_with<F, T: Serialize + ?Sized>(
&mut self,
value: &T,
setup: F,
) -> Result<(), Error>
where
F: FnOnce(&mut SerializeDriver<'_>),
{
ser::Serializer::serialize_with(self, value, setup)
}
pub fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(&self.out) }
}
pub fn finish(self) -> String {
unsafe { String::from_utf8_unchecked(self.out) }
}
fn start_value(&mut self) -> Result<(), Error> {
if self.in_progress {
return Err(Error::in_progress());
}
match self.config.trailing_mode() {
Trailing::Strict if self.written > 0 => Err(Error::new(
ErrorKind::InvalidState,
"with Trailing::Strict only a single value can be written",
)),
Trailing::Stop if self.written > 0 => {
self.out.push(b'\n');
Ok(())
}
_ => Ok(()),
}
}
fn finish_value(&mut self) {
if self.config.trailing_mode() == Trailing::Newline {
self.out.push(b'\n');
}
self.written += 1;
self.in_progress = false;
}
}
impl ser::Serializer for Serializer {
fn drive(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
if self.in_progress {
return Err(Error::in_progress());
}
ser::StreamSerializer::drive_partial(self, driver, usize::MAX).map(|_| ())
}
}
impl ser::StreamSerializer for Serializer {
fn output(&self) -> &[u8] {
&self.out
}
fn clear_output(&mut self) {
self.out.clear();
}
fn supports_partial(&self) -> bool {
true
}
fn drive_partial(
&mut self,
driver: &mut SerializeDriver<'_>,
limit: usize,
) -> Result<bool, Error> {
if !self.config.context.is_empty() {
driver.set_default_context(self.config.context.clone());
}
accept_raw(driver);
let rollback = self.out.len();
let (mut local, adopt) = match self.value.take() {
Some(mut writer) => {
let adopt = self.out.is_empty();
if adopt {
*writer.output() = Buffer::from_vec(core::mem::take(&mut self.out));
}
(writer, adopt)
}
None => {
self.start_value()?;
let out = Buffer::from_vec(core::mem::take(&mut self.out));
let writer = self
.config
.value_writer(out, BytesFormat::of(driver.state()));
if limit == usize::MAX {
return self.drive_whole(writer, driver, rollback);
}
(Box::new(writer), true)
}
};
let rv = local.drive(driver, limit);
match rv {
Ok(done) => {
let output = local.take_output();
if adopt {
self.out = output;
} else {
self.out.extend_from_slice(&output);
}
if done {
self.finish_value();
Ok(true)
} else {
self.value = Some(local);
self.in_progress = true;
Ok(false)
}
}
Err(err) => {
if adopt {
self.out = local.output().take();
self.out.truncate(rollback);
}
Err(err)
}
}
}
fn in_progress(&self) -> bool {
self.in_progress
}
}
impl Serializer {
fn drive_whole(
&mut self,
mut writer: ValueWriter,
driver: &mut SerializeDriver<'_>,
rollback: usize,
) -> Result<bool, Error> {
let rv = writer.drive_whole(driver);
self.out = writer.output().take();
match rv {
Ok(_) => {
self.finish_value();
Ok(true)
}
Err(err) => {
self.out.truncate(rollback);
Err(err)
}
}
}
}
#[cfg(feature = "io")]
impl SerializerConfig {
pub fn writer<W: std::io::Write>(&self, writer: W) -> deser_core::io::Writer<W, Serializer> {
deser_core::io::Writer::new(writer, Serializer::with_config(self.clone()))
}
pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
&self,
writer: W,
value: &T,
) -> Result<(), Error> {
self.writer(writer).write(value)
}
}
#[cfg(feature = "io")]
pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
writer: W,
value: &T,
) -> Result<(), Error> {
JSON5_CONFIG.to_writer(writer, value)
}
pub(crate) struct Output {
pub(crate) out: Buffer,
bytes: BytesFormat,
non_finite_floats: bool,
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Container {
Top,
Seq,
Map,
}
pub(crate) struct Writer {
ser: Output,
stack: Vec<Container>,
container: Container,
first: bool,
is_key: bool,
limit: usize,
}
impl EventSink for Writer {
#[inline(always)]
fn event(
&mut self,
event: Event<'_>,
_value: SerializeRef<'_>,
_state: &mut deser_core::State,
) -> Result<(), Error> {
Writer::event(self, event)
}
#[inline(always)]
fn pause(&mut self) -> bool {
self.ser.out.len() >= self.limit
}
}
impl Writer {
#[inline(always)]
fn event(&mut self, event: Event) -> Result<(), Error> {
match event {
Event::Atom(atom) => {
if self.is_key {
self.ser.write_key_atom(atom, self.first)?;
self.is_key = false;
} else {
match self.container {
Container::Seq => {
if !self.first {
self.ser.write_char(',');
}
}
Container::Map => self.is_key = true,
Container::Top => {}
}
self.ser.write_atom(atom)?;
}
self.first = false;
Ok(())
}
Event::MapStart(_) => self.start(true),
Event::SeqStart(_) => self.start(false),
Event::MapEnd => self.end(true),
Event::SeqEnd => self.end(false),
}
}
#[inline]
fn start(&mut self, is_map: bool) -> Result<(), Error> {
if self.is_key {
return Err(Error::new(
ErrorKind::UnsupportedType,
"JSON does not support this value for map keys",
));
}
if self.container == Container::Seq && !self.first {
self.ser.write_char(',');
}
self.stack.push(self.container);
self.first = true;
if is_map {
self.container = Container::Map;
self.is_key = true;
self.ser.write_char('{');
} else {
self.container = Container::Seq;
self.ser.write_char('[');
}
Ok(())
}
#[inline]
fn end(&mut self, is_map: bool) -> Result<(), Error> {
if is_map {
if self.container != Container::Map || !self.is_key {
return Err(Error::new(ErrorKind::InvalidState, "unexpected map end"));
}
self.ser.write_char('}');
} else {
if self.container != Container::Seq {
return Err(Error::new(ErrorKind::InvalidState, "unexpected array end"));
}
self.ser.write_char(']');
}
self.container = self.stack.pop().unwrap_or(Container::Top);
self.first = false;
self.is_key = self.container == Container::Map;
Ok(())
}
}
impl Output {
#[inline(always)]
fn write_key_atom(&mut self, atom: Atom, first: bool) -> Result<(), Error> {
let atom = ManuallyDrop::new(atom);
match *atom {
Atom::Str(ref val) | Atom::Lexical(ref val) if val.is_borrowed() => {
self.write_key(val, first);
Ok(())
}
_ => self.write_other_key_atom(ManuallyDrop::into_inner(atom), first),
}
}
#[inline(never)]
fn write_other_key_atom(&mut self, atom: Atom, first: bool) -> Result<(), Error> {
if !first {
self.write_char(',');
}
self.write_key_text(atom)?;
self.write_char(':');
Ok(())
}
pub(crate) fn write_key_text(&mut self, atom: Atom) -> Result<(), Error> {
match atom {
Atom::Str(ref val) | Atom::Lexical(ref val) => self.write_escaped_str(val),
Atom::Char(c) => self.write_escaped_str(c.encode_utf8(&mut [0u8; 4])),
Atom::U64(val) => {
self.write_char('"');
self.write_u64(val);
self.write_char('"');
}
Atom::I64(val) => {
self.write_char('"');
self.write_i64(val);
self.write_char('"');
}
Atom::Bool(val) => self.write_str(if val { "\"true\"" } else { "\"false\"" }),
Atom::Ext(ref ext) => self.write_ext_key(ext)?,
Atom::Bytes(ref val) => self.write_bytes_str(val, val.fallback),
Atom::Implicit(ref val) => match json_literal(val) {
Some(text) if val.value() != ImplicitValue::Null => self.write_escaped_str(text),
_ => return self.write_key_text(val.value().to_atom()),
},
_ => {
return Err(Error::new(
ErrorKind::UnsupportedType,
"JSON does not support this value for map keys",
));
}
}
Ok(())
}
#[inline(always)]
pub(crate) fn write_atom(&mut self, atom: Atom) -> Result<(), Error> {
let atom = ManuallyDrop::new(atom);
match *atom {
Atom::Null => self.write_str("null"),
Atom::Bool(true) => self.write_str("true"),
Atom::Bool(false) => self.write_str("false"),
Atom::Str(ref val) if val.is_borrowed() => self.write_escaped_str(val),
Atom::Char(c) => self.write_escaped_str(c.encode_utf8(&mut [0u8; 4])),
Atom::U64(val) => self.write_u64(val),
Atom::I64(val) => self.write_i64(val),
Atom::F64(val) => self.write_float(val),
Atom::F32(val) => self.write_float(val),
_ => return self.write_other_atom(ManuallyDrop::into_inner(atom)),
}
Ok(())
}
#[inline(never)]
fn write_other_atom(&mut self, atom: Atom) -> Result<(), Error> {
match atom {
Atom::Str(ref val) | Atom::Lexical(ref val) => self.write_escaped_str(val),
Atom::Ext(ref ext) => self.write_ext_value(ext)?,
Atom::Bytes(ref val) => {
self.write_bytes(val, val.fallback.copied().unwrap_or(self.bytes))
}
Atom::Implicit(ref val) => match json_literal(val) {
Some(text) => self.write_str(text),
None => return self.write_atom(val.value().to_atom()),
},
_ => return Err(Error::new(ErrorKind::UnsupportedType, "unknown atom")),
}
Ok(())
}
fn write_bytes(&mut self, bytes: &[u8], format: BytesFormat) {
match format.encode(bytes) {
Some(encoded) => self.write_escaped_str(&encoded),
None => {
self.write_char('[');
for (idx, &byte) in bytes.iter().enumerate() {
if idx > 0 {
self.write_char(',');
}
self.write_u64(byte.into());
}
self.write_char(']');
}
}
}
fn write_bytes_str(&mut self, bytes: &[u8], fallback: Option<&BytesFormat>) {
let format = fallback.copied().unwrap_or(self.bytes);
let encoded = format
.encode(bytes)
.or_else(|| BytesFormat::BASE64.encode(bytes))
.unwrap_or_default();
self.write_escaped_str(&encoded);
}
#[inline(always)]
pub(crate) fn write_str(&mut self, s: &str) {
self.out.push_str(s);
}
#[inline(always)]
pub(crate) fn write_char(&mut self, c: char) {
assert!(c.is_ascii(), "only ASCII characters can be written");
self.out.push(c as u8);
}
#[inline]
fn write_key(&mut self, key: &str, first: bool) {
if find_escape(key.as_bytes()) != key.len() {
if !first {
self.write_char(',');
}
self.write_escaped_str_slow(key);
self.write_char(':');
return;
}
self.out.reserve(key.len() + 4);
unsafe {
if !first {
self.out.push_unchecked(b',');
}
self.out.push_unchecked(b'"');
self.out.push_str_unchecked(key);
self.out.push_unchecked(b'"');
self.out.push_unchecked(b':');
}
}
#[inline]
fn write_float<F: zmij::Float + Into<f64>>(&mut self, val: F) {
let wide: f64 = val.into();
if wide.is_finite() {
self.write_str(zmij::Buffer::new().format_finite(val))
} else {
self.write_non_finite(wide)
}
}
#[cold]
fn write_non_finite(&mut self, val: f64) {
self.write_str(if !self.non_finite_floats {
"null"
} else if val.is_nan() {
"NaN"
} else if val > 0.0 {
"Infinity"
} else {
"-Infinity"
})
}
#[cold]
fn write_ext_key(&mut self, ext: &ExtValue) -> Result<(), Error> {
if ext.is::<u128>() || ext.is::<i128>() {
self.write_char('"');
self.write_ext_value(ext)?;
self.write_char('"');
return Ok(());
}
match ext.fallback() {
Atom::Str(val) | Atom::Lexical(val) => self.write_escaped_str(&val),
Atom::Char(c) => self.write_escaped_str(c.encode_utf8(&mut [0u8; 4])),
Atom::U64(val) => {
self.write_char('"');
self.write_u64(val);
self.write_char('"');
}
Atom::I64(val) => {
self.write_char('"');
self.write_i64(val);
self.write_char('"');
}
Atom::Bool(val) => self.write_str(if val { "\"true\"" } else { "\"false\"" }),
_ => {
return Err(Error::new(
ErrorKind::UnsupportedType,
"JSON does not support this value for map keys",
));
}
}
Ok(())
}
#[cold]
fn write_ext_value(&mut self, ext: &ExtValue) -> Result<(), Error> {
if let Some(raw) = ext.downcast_value_ref::<RawInput>()
&& raw.is_format(&crate::raw::ID)
&& let Some(text) = raw.as_str()
{
self.write_str(text);
return Ok(());
}
if let Some(&val) = ext.downcast_ref::<u128>() {
self.write_int(val);
return Ok(());
} else if let Some(&val) = ext.downcast_ref::<i128>() {
self.write_int(val);
return Ok(());
} else if let Some(val) = ext.downcast_ref::<BigInt>() {
let text = val.to_string();
check_number(&text)?;
self.write_str(&text);
return Ok(());
} else if let Some(val) = ext.downcast_ref::<Decimal>() {
check_number(val.as_str())?;
self.write_str(val.as_str());
return Ok(());
} else if let Some(val) = ext.downcast_value_ref::<Number>() {
check_number(val.as_str())?;
self.write_str(val.as_str());
return Ok(());
}
match ext.fallback() {
Atom::Null => self.write_str("null"),
Atom::Bool(val) => self.write_str(if val { "true" } else { "false" }),
Atom::Str(val) | Atom::Lexical(val) => self.write_escaped_str(&val),
Atom::Char(c) => self.write_escaped_str(c.encode_utf8(&mut [0u8; 4])),
Atom::U64(val) => self.write_u64(val),
Atom::I64(val) => self.write_i64(val),
Atom::F64(val) => self.write_float(val),
Atom::F32(val) => self.write_float(val),
Atom::Bytes(val) => self.write_bytes_str(&val, val.fallback),
_ => {
return Err(Error::new(
ErrorKind::UnsupportedType,
"JSON does not support this value",
));
}
}
Ok(())
}
fn write_int<I: core::fmt::Display>(&mut self, val: I) {
self.write_str(&val.to_string())
}
#[inline]
fn write_u64(&mut self, val: u64) {
self.write_str(itoa::Buffer::new().format(val))
}
#[inline]
fn write_i64(&mut self, val: i64) {
self.write_str(itoa::Buffer::new().format(val))
}
#[inline]
fn write_escaped_str(&mut self, value: &str) {
if find_escape(value.as_bytes()) != value.len() {
return self.write_escaped_str_slow(value);
}
self.out.reserve(value.len() + 2);
unsafe {
self.out.push_unchecked(b'"');
self.out.push_str_unchecked(value);
self.out.push_unchecked(b'"');
}
}
#[inline(never)]
fn write_escaped_str_slow(&mut self, value: &str) {
self.write_char('"');
let bytes = value.as_bytes();
let mut start = 0;
loop {
let next = skip_to_escape(bytes, start);
if start < next {
self.write_str(&value[start..next]);
}
if next == bytes.len() {
break;
}
let byte = bytes[next];
match ESCAPE[byte as usize] {
self::BB => self.write_str("\\b"),
self::TT => self.write_str("\\t"),
self::NN => self.write_str("\\n"),
self::FF => self.write_str("\\f"),
self::RR => self.write_str("\\r"),
self::QU => self.write_str("\\\""),
self::BS => self.write_str("\\\\"),
self::U => {
static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
self.write_str("\\u00");
self.write_char(HEX_DIGITS[(byte >> 4) as usize] as char);
self.write_char(HEX_DIGITS[(byte & 0xF) as usize] as char);
}
_ => unreachable!(),
}
start = next + 1;
}
self.write_char('"');
}
}
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, ];
const JSON5_CONFIG: SerializerConfig = SerializerConfig::builder().non_finite_floats(true).build();
#[inline]
pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
JSON5_CONFIG.to_string(value)
}
fn json_literal<'a>(value: &'a Implicit) -> Option<&'a str> {
let text = value.text().as_str();
let same = match value.value() {
ImplicitValue::Null => text == "null",
ImplicitValue::Bool(value) => text == if value { "true" } else { "false" },
ImplicitValue::U64(value) => is_json_int(text) && text.parse::<u64>() == Ok(value),
ImplicitValue::I64(value) => is_json_int(text) && text.parse::<i64>() == Ok(value),
ImplicitValue::F64(value) => {
value.is_finite()
&& Number::parse(text)
.is_ok_and(|x| !x.is_integer() && x.value().to_bits() == value.to_bits())
}
_ => false,
};
same.then_some(text)
}
#[cold]
fn check_number(text: &str) -> Result<(), Error> {
match text.parse::<f64>() {
Ok(value) if value.is_finite() => Ok(()),
_ => Err(Error::new(ErrorKind::OutOfRange, "number out of range")),
}
}
fn is_json_int(text: &str) -> bool {
let digits = text.strip_prefix('-').unwrap_or(text).as_bytes();
match digits {
[b'0'] => true,
[b'1'..=b'9', rest @ ..] => rest.iter().all(u8::is_ascii_digit),
_ => false,
}
}