use crate::error::Error;
use forma_core::ser::*;
use std::io;
pub struct Serializer<W: io::Write> {
writer: W,
first: Vec<bool>,
indent: Option<&'static str>,
current_indent: usize,
}
impl<W: io::Write> Serializer<W> {
pub fn new(writer: W) -> Self {
Serializer {
writer,
first: Vec::new(),
indent: None,
current_indent: 0,
}
}
pub fn pretty(writer: W, indent: &'static str) -> Self {
Serializer {
writer,
first: Vec::new(),
indent: Some(indent),
current_indent: 0,
}
}
pub fn into_inner(self) -> W {
self.writer
}
fn is_pretty(&self) -> bool {
self.indent.is_some()
}
fn push_scope(&mut self) {
self.first.push(true);
self.current_indent += 1;
}
fn write_comma(&mut self) -> Result<(), Error> {
match self.first.last_mut() {
Some(first) if *first => {
*first = false;
if self.is_pretty() {
self.write_newline_indent()?;
}
Ok(())
}
Some(_) => {
self.writer.write_all(b",")?;
if self.is_pretty() {
self.write_newline_indent()?;
}
Ok(())
}
None => Ok(()),
}
}
fn pop_scope(&mut self) {
self.first.pop();
self.current_indent -= 1;
}
fn write_newline_indent(&mut self) -> Result<(), Error> {
if let Some(indent) = self.indent {
self.writer.write_all(b"\n")?;
for _ in 0..self.current_indent {
self.writer.write_all(indent.as_bytes())?;
}
}
Ok(())
}
}
impl<'a, W: io::Write> forma_core::ser::Serializer for &'a mut Serializer<W> {
type Ok = ();
type Error = Error;
type SerializeSeq = Compound<'a, W>;
type SerializeTuple = Compound<'a, W>;
type SerializeTupleStruct = Compound<'a, W>;
type SerializeTupleVariant = Compound<'a, W>;
type SerializeMap = Compound<'a, W>;
type SerializeStruct = Compound<'a, W>;
type SerializeStructVariant = Compound<'a, W>;
fn serialize_bool(self, v: bool) -> Result<(), Error> {
self.writer
.write_all(if v { b"true" } else { b"false" })?;
Ok(())
}
fn serialize_i8(self, v: i8) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_i16(self, v: i16) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_i32(self, v: i32) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_i64(self, v: i64) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_i128(self, v: i128) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_u8(self, v: u8) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_u16(self, v: u16) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_u32(self, v: u32) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_u64(self, v: u64) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_u128(self, v: u128) -> Result<(), Error> {
write!(self.writer, "{v}")?;
Ok(())
}
fn serialize_f32(self, v: f32) -> Result<(), Error> {
if v.is_finite() {
write!(self.writer, "{v}")?;
} else {
return Err(Error::Message(format!(
"JSON does not support {v}"
)));
}
Ok(())
}
fn serialize_f64(self, v: f64) -> Result<(), Error> {
if v.is_finite() {
write!(self.writer, "{v}")?;
} else {
return Err(Error::Message(format!(
"JSON does not support {v}"
)));
}
Ok(())
}
fn serialize_char(self, v: char) -> Result<(), Error> {
let mut buf = [0u8; 4];
self.serialize_str(v.encode_utf8(&mut buf))
}
fn serialize_str(self, v: &str) -> Result<(), Error> {
write_escaped_str(&mut self.writer, v)
}
fn serialize_bytes(self, v: &[u8]) -> Result<(), Error> {
self.writer.write_all(b"[")?;
self.current_indent += 1;
for (i, byte) in v.iter().enumerate() {
if i > 0 {
self.writer.write_all(b",")?;
}
if self.is_pretty() {
self.write_newline_indent()?;
}
write!(self.writer, "{byte}")?;
}
self.current_indent -= 1;
if self.is_pretty() && !v.is_empty() {
self.write_newline_indent()?;
}
self.writer.write_all(b"]")?;
Ok(())
}
fn serialize_none(self) -> Result<(), Error> {
self.writer.write_all(b"null")?;
Ok(())
}
fn serialize_some<T: Serialize + ?Sized>(self, value: &T) -> Result<(), Error> {
value.serialize(self)
}
fn serialize_unit(self) -> Result<(), Error> {
self.writer.write_all(b"null")?;
Ok(())
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> {
self.writer.write_all(b"null")?;
Ok(())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<(), Error> {
self.serialize_str(variant)
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(
self,
_name: &'static str,
value: &T,
) -> Result<(), Error> {
value.serialize(self)
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<(), Error> {
self.writer.write_all(b"{")?;
self.current_indent += 1;
if self.is_pretty() {
self.write_newline_indent()?;
}
write_escaped_str(&mut self.writer, variant)?;
self.writer.write_all(if self.is_pretty() { b": " } else { b":" })?;
value.serialize(&mut *self)?;
self.current_indent -= 1;
if self.is_pretty() {
self.write_newline_indent()?;
}
self.writer.write_all(b"}")?;
Ok(())
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Compound<'a, W>, Error> {
self.writer.write_all(b"[")?;
self.push_scope();
Ok(Compound { ser: self, kind: CompoundKind::Array })
}
fn serialize_tuple(self, _len: usize) -> Result<Compound<'a, W>, Error> {
self.serialize_seq(None)
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Compound<'a, W>, Error> {
self.serialize_seq(None)
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
_len: usize,
) -> Result<Compound<'a, W>, Error> {
self.writer.write_all(b"{")?;
self.current_indent += 1;
if self.is_pretty() {
self.write_newline_indent()?;
}
write_escaped_str(&mut self.writer, variant)?;
self.writer.write_all(if self.is_pretty() { b": [" } else { b":[" })?;
self.push_scope();
Ok(Compound { ser: self, kind: CompoundKind::WrappedArray })
}
fn serialize_map(self, _len: Option<usize>) -> Result<Compound<'a, W>, Error> {
self.writer.write_all(b"{")?;
self.push_scope();
Ok(Compound { ser: self, kind: CompoundKind::Object })
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Compound<'a, W>, Error> {
self.serialize_map(None)
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
_len: usize,
) -> Result<Compound<'a, W>, Error> {
self.writer.write_all(b"{")?;
self.current_indent += 1;
if self.is_pretty() {
self.write_newline_indent()?;
}
write_escaped_str(&mut self.writer, variant)?;
self.writer.write_all(if self.is_pretty() { b": {" } else { b":{" })?;
self.push_scope();
Ok(Compound { ser: self, kind: CompoundKind::WrappedObject })
}
}
#[derive(Clone, Copy)]
enum CompoundKind {
Array,
Object,
WrappedArray,
WrappedObject,
}
pub struct Compound<'a, W: io::Write> {
ser: &'a mut Serializer<W>,
kind: CompoundKind,
}
impl<W: io::Write> SerializeSeq for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
self.ser.write_comma()?;
value.serialize(&mut *self.ser)
}
fn end(self) -> Result<(), Error> {
let had_elements = !self.ser.first.last().copied().unwrap_or(true);
self.ser.pop_scope();
match self.kind {
CompoundKind::Array => {
if self.ser.is_pretty() && had_elements {
self.ser.write_newline_indent()?;
}
self.ser.writer.write_all(b"]")?;
}
CompoundKind::WrappedArray => {
if self.ser.is_pretty() && had_elements {
self.ser.write_newline_indent()?;
}
self.ser.writer.write_all(b"]")?;
self.ser.current_indent -= 1;
if self.ser.is_pretty() {
self.ser.write_newline_indent()?;
}
self.ser.writer.write_all(b"}")?;
}
_ => unreachable!(),
}
Ok(())
}
}
impl<W: io::Write> SerializeTuple for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<(), Error> {
SerializeSeq::end(self)
}
}
impl<W: io::Write> SerializeTupleStruct for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<(), Error> {
SerializeSeq::end(self)
}
}
impl<W: io::Write> SerializeTupleVariant for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<(), Error> {
SerializeSeq::end(self)
}
}
impl<W: io::Write> SerializeMap for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
self.ser.write_comma()?;
key.serialize(MapKeySerializer(&mut *self.ser))
}
fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
self.ser.writer.write_all(if self.ser.is_pretty() { b": " } else { b":" })?;
value.serialize(&mut *self.ser)
}
fn end(self) -> Result<(), Error> {
let had_entries = !self.ser.first.last().copied().unwrap_or(true);
self.ser.pop_scope();
match self.kind {
CompoundKind::Object => {
if self.ser.is_pretty() && had_entries {
self.ser.write_newline_indent()?;
}
self.ser.writer.write_all(b"}")?;
}
CompoundKind::WrappedObject => {
if self.ser.is_pretty() && had_entries {
self.ser.write_newline_indent()?;
}
self.ser.writer.write_all(b"}")?;
self.ser.current_indent -= 1;
if self.ser.is_pretty() {
self.ser.write_newline_indent()?;
}
self.ser.writer.write_all(b"}")?;
}
_ => unreachable!(),
}
Ok(())
}
}
impl<W: io::Write> SerializeStruct for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Error> {
SerializeMap::serialize_key(self, key)?;
SerializeMap::serialize_value(self, value)
}
fn end(self) -> Result<(), Error> {
SerializeMap::end(self)
}
}
impl<W: io::Write> SerializeStructVariant for Compound<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_field<T: Serialize + ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Error> {
SerializeMap::serialize_key(self, key)?;
SerializeMap::serialize_value(self, value)
}
fn end(self) -> Result<(), Error> {
SerializeMap::end(self)
}
}
struct MapKeySerializer<'a, W: io::Write>(&'a mut Serializer<W>);
impl<W: io::Write> forma_core::ser::Serializer for MapKeySerializer<'_, W> {
type Ok = ();
type Error = Error;
type SerializeSeq = Impossible<(), Error>;
type SerializeTuple = Impossible<(), Error>;
type SerializeTupleStruct = Impossible<(), Error>;
type SerializeTupleVariant = Impossible<(), Error>;
type SerializeMap = Impossible<(), Error>;
type SerializeStruct = Impossible<(), Error>;
type SerializeStructVariant = Impossible<(), Error>;
fn serialize_bool(self, v: bool) -> Result<(), Error> {
self.0.serialize_str(if v { "true" } else { "false" })
}
fn serialize_i8(self, v: i8) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_i16(self, v: i16) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_i32(self, v: i32) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_i64(self, v: i64) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_i128(self, v: i128) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_u8(self, v: u8) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_u16(self, v: u16) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_u32(self, v: u32) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_u64(self, v: u64) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_u128(self, v: u128) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, &v.to_string())
}
fn serialize_f32(self, _v: f32) -> Result<(), Error> {
Err(Error::Message("float keys are not supported in JSON".into()))
}
fn serialize_f64(self, _v: f64) -> Result<(), Error> {
Err(Error::Message("float keys are not supported in JSON".into()))
}
fn serialize_char(self, v: char) -> Result<(), Error> {
let mut buf = [0u8; 4];
self.serialize_str(v.encode_utf8(&mut buf))
}
fn serialize_str(self, v: &str) -> Result<(), Error> {
write_escaped_str(&mut self.0.writer, v)
}
fn serialize_bytes(self, _v: &[u8]) -> Result<(), Error> {
Err(Error::Message("bytes keys are not supported in JSON".into()))
}
fn serialize_none(self) -> Result<(), Error> {
Err(Error::Message("null keys are not supported in JSON".into()))
}
fn serialize_some<T: Serialize + ?Sized>(self, _value: &T) -> Result<(), Error> {
Err(Error::Message("option keys are not supported in JSON".into()))
}
fn serialize_unit(self) -> Result<(), Error> {
Err(Error::Message("unit keys are not supported in JSON".into()))
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> {
Err(Error::Message("unit struct keys are not supported in JSON".into()))
}
fn serialize_unit_variant(self, _name: &'static str, _idx: u32, variant: &'static str) -> Result<(), Error> {
self.serialize_str(variant)
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(self, _name: &'static str, value: &T) -> Result<(), Error> {
value.serialize(self)
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(self, _name: &'static str, _idx: u32, _variant: &'static str, _value: &T) -> Result<(), Error> {
Err(Error::Message("newtype variant keys are not supported in JSON".into()))
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
Err(Error::Message("seq keys are not supported in JSON".into()))
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Error> {
Err(Error::Message("tuple keys are not supported in JSON".into()))
}
fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeTupleStruct, Error> {
Err(Error::Message("tuple struct keys are not supported in JSON".into()))
}
fn serialize_tuple_variant(self, _name: &'static str, _idx: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeTupleVariant, Error> {
Err(Error::Message("tuple variant keys are not supported in JSON".into()))
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
Err(Error::Message("map keys are not supported in JSON".into()))
}
fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct, Error> {
Err(Error::Message("struct keys are not supported in JSON".into()))
}
fn serialize_struct_variant(self, _name: &'static str, _idx: u32, _variant: &'static str, _len: usize) -> Result<Self::SerializeStructVariant, Error> {
Err(Error::Message("struct variant keys are not supported in JSON".into()))
}
}
fn write_escaped_str(writer: &mut impl io::Write, s: &str) -> Result<(), Error> {
writer.write_all(b"\"")?;
let bytes = s.as_bytes();
let mut start = 0;
for (i, &b) in bytes.iter().enumerate() {
let escape = match b {
b'"' => Some(b"\\\"" as &[u8]),
b'\\' => Some(b"\\\\" as &[u8]),
b'\n' => Some(b"\\n" as &[u8]),
b'\r' => Some(b"\\r" as &[u8]),
b'\t' => Some(b"\\t" as &[u8]),
0x00..=0x1F => {
if start < i {
writer.write_all(&bytes[start..i])?;
}
write!(writer, "\\u{:04x}", b)?;
start = i + 1;
None
}
_ => None, };
if let Some(esc) = escape {
if start < i {
writer.write_all(&bytes[start..i])?;
}
writer.write_all(esc)?;
start = i + 1;
}
}
if start < bytes.len() {
writer.write_all(&bytes[start..])?;
}
writer.write_all(b"\"")?;
Ok(())
}