use super::{
Buffer, ESTree, ESTreeSequenceSerializer, ESTreeSerializer, Formatter, Serializer,
SerializerPrivate,
};
pub trait StructSerializer {
type Formatter: Formatter;
fn serialize_field<T: ESTree + ?Sized>(&mut self, key: &str, value: &T);
fn end(self);
}
pub struct ESTreeStructSerializer<'s, F: Formatter> {
serializer: &'s mut ESTreeSerializer<F>,
state: StructState,
}
impl<'s, F: Formatter> ESTreeStructSerializer<'s, F> {
pub(super) fn new(mut serializer: &'s mut ESTreeSerializer<F>) -> Self {
serializer.buffer_mut().push_ascii_byte(b'{');
Self { serializer, state: StructState::Empty }
}
}
impl<F: Formatter> StructSerializer for ESTreeStructSerializer<'_, F> {
type Formatter = F;
fn serialize_field<T: ESTree + ?Sized>(&mut self, key: &str, value: &T) {
let (buffer, formatter) = self.serializer.buffer_and_formatter_mut();
if self.state == StructState::Empty {
self.state = StructState::HasFields;
formatter.before_first_element(buffer);
} else {
buffer.push_ascii_byte(b',');
formatter.before_later_element(buffer);
}
buffer.push_ascii_byte(b'"');
buffer.push_str(key);
buffer.push_str("\":");
formatter.before_field_value(buffer);
value.serialize(&mut *self.serializer);
}
fn end(self) {
let mut serializer = self.serializer;
let (buffer, formatter) = serializer.buffer_and_formatter_mut();
if self.state == StructState::HasFields {
formatter.after_last_element(buffer);
}
buffer.push_ascii_byte(b'}');
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum StructState {
Empty,
HasFields,
}
pub struct FlatStructSerializer<'p, P: StructSerializer>(pub &'p mut P);
impl<'p, P: StructSerializer> Serializer for FlatStructSerializer<'p, P> {
type StructSerializer = Self;
type SequenceSerializer = ESTreeSequenceSerializer<'p, P::Formatter>;
fn serialize_struct(self) -> Self {
self
}
fn serialize_sequence(self) -> ESTreeSequenceSerializer<'p, P::Formatter> {
const {
panic!("Cannot flatten a sequence into a struct");
}
}
}
impl<P: StructSerializer> SerializerPrivate for FlatStructSerializer<'_, P> {
type Formatter = P::Formatter;
fn buffer_mut(&mut self) -> &mut Buffer {
const {
panic!("Cannot flatten anything but a struct into another struct");
}
}
fn buffer_and_formatter_mut(&mut self) -> (&mut Buffer, &mut P::Formatter) {
const {
panic!("Cannot flatten anything but a struct into another struct");
}
}
}
impl<P: StructSerializer> StructSerializer for FlatStructSerializer<'_, P> {
type Formatter = P::Formatter;
#[inline(always)]
fn serialize_field<T: ESTree + ?Sized>(&mut self, key: &str, value: &T) {
self.0.serialize_field(key, value);
}
fn end(self) {
}
}
#[cfg(test)]
mod tests {
use super::super::{CompactSerializer, FlatStructSerializer, PrettySerializer, Serializer};
use super::*;
#[test]
fn serialize_struct() {
struct Foo<'a> {
n: f64,
u: u32,
bar: Bar<'a>,
empty: Null,
hello: Option<&'a str>,
maybe_bar: Option<Bar<'a>>,
maybe_not_bar: Option<Bar<'a>>,
}
struct Bar<'a> {
yes: &'a str,
no: &'a str,
}
struct Null;
impl ESTree for Foo<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("n", &self.n);
state.serialize_field("u", &self.u);
state.serialize_field("bar", &self.bar);
state.serialize_field("empty", &self.empty);
state.serialize_field("hello", &self.hello);
state.serialize_field("maybe_bar", &self.maybe_bar);
state.serialize_field("maybe_not_bar", &self.maybe_not_bar);
state.end();
}
}
impl ESTree for Bar<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("yes", &self.yes);
state.serialize_field("no", &self.no);
state.end();
}
}
impl ESTree for Null {
fn serialize<S: Serializer>(&self, serializer: S) {
let state = serializer.serialize_struct();
state.end();
}
}
let foo = Foo {
n: 123.0,
u: 12345,
bar: Bar { yes: "yup", no: "nope" },
empty: Null,
hello: Some("hi!"),
maybe_bar: Some(Bar { yes: "hell yeah!", no: "not a chance in a million, mate" }),
maybe_not_bar: None,
};
let mut serializer = CompactSerializer::new();
foo.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(
&s,
r#"{"n":123,"u":12345,"bar":{"yes":"yup","no":"nope"},"empty":{},"hello":"hi!","maybe_bar":{"yes":"hell yeah!","no":"not a chance in a million, mate"},"maybe_not_bar":null}"#
);
let mut serializer = PrettySerializer::new();
foo.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(
&s,
r#"{
"n": 123,
"u": 12345,
"bar": {
"yes": "yup",
"no": "nope"
},
"empty": {},
"hello": "hi!",
"maybe_bar": {
"yes": "hell yeah!",
"no": "not a chance in a million, mate"
},
"maybe_not_bar": null
}"#
);
}
#[test]
fn serialize_flattened_struct() {
struct Outer {
outer1: &'static str,
inner: Inner,
outer2: &'static str,
}
struct Inner {
inner1: &'static str,
innermost: Innermost,
inner2: &'static str,
}
struct Innermost {
innermost1: &'static str,
innermost2: &'static str,
}
impl ESTree for Outer {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("outer1", &self.outer1);
self.inner.serialize(FlatStructSerializer(&mut state));
state.serialize_field("outer2", &self.outer2);
state.end();
}
}
impl ESTree for Inner {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("inner1", &self.inner1);
self.innermost.serialize(FlatStructSerializer(&mut state));
state.serialize_field("inner2", &self.inner2);
state.end();
}
}
impl ESTree for Innermost {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("innermost1", &self.innermost1);
state.serialize_field("innermost2", &self.innermost2);
state.end();
}
}
let outer = Outer {
outer1: "out1",
inner: Inner {
inner1: "in1",
innermost: Innermost { innermost1: "inin1", innermost2: "inin2" },
inner2: "in2",
},
outer2: "out2",
};
let mut serializer = CompactSerializer::new();
outer.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(
&s,
r#"{"outer1":"out1","inner1":"in1","innermost1":"inin1","innermost2":"inin2","inner2":"in2","outer2":"out2"}"#
);
let mut serializer = PrettySerializer::new();
outer.serialize(&mut serializer);
let s = serializer.into_string();
assert_eq!(
&s,
r#"{
"outer1": "out1",
"inner1": "in1",
"innermost1": "inin1",
"innermost2": "inin2",
"inner2": "in2",
"outer2": "out2"
}"#
);
}
}