#[cfg(feature = "derive")]
use alloc::borrow::Cow;
use crate::State;
use crate::error::Error;
use crate::event::{Atom, ContainerShape};
pub(crate) const PLAIN_BUDGET: usize = 256;
#[inline]
pub(crate) fn atom_cost(atom: &Atom<'_>) -> usize {
match atom {
Atom::Str(text) | Atom::Lexical(text) => 1 + text.len() / 32,
Atom::Bytes(bytes) => 1 + bytes.len() / 32,
_ => 1,
}
}
#[cfg(feature = "derive")]
use crate::ser::StructEmitter;
use crate::ser::{Chunk, SeqEmitter, Serialize, SerializeHandle};
pub struct Begin<'a> {
pub(crate) kind: BeginKind<'a>,
pub(crate) shape: ContainerShape,
pub(crate) needs_finish: bool,
}
pub(crate) enum BeginKind<'a> {
Chunk(Chunk<'a>),
Struct(&'a dyn IndexedStruct),
Seq(&'a dyn IndexedSeq),
Plain(&'a dyn Serialize),
}
impl<'a> Begin<'a> {
#[inline]
pub fn chunk(chunk: Chunk<'a>, shape: ContainerShape, needs_finish: bool) -> Begin<'a> {
Begin {
kind: BeginKind::Chunk(chunk),
shape,
needs_finish,
}
}
#[inline]
pub fn indexed_struct(value: &'a dyn IndexedStruct, shape: ContainerShape) -> Begin<'a> {
Begin {
kind: BeginKind::Struct(value),
shape,
needs_finish: false,
}
}
#[inline]
pub fn plain(value: &'a dyn Serialize, shape: ContainerShape) -> Begin<'a> {
Begin {
kind: BeginKind::Plain(value),
shape,
needs_finish: false,
}
}
#[inline]
pub fn indexed_seq(value: &'a dyn IndexedSeq, shape: ContainerShape) -> Begin<'a> {
Begin {
kind: BeginKind::Seq(value),
shape,
needs_finish: false,
}
}
}
pub enum StructField<'a> {
Field(&'a str, SerializeHandle<'a>),
Skip,
End,
}
pub trait IndexedStruct: Sync {
fn field(&self, index: usize) -> StructField<'_>;
#[inline]
fn emit_plain_fields(
&self,
index: usize,
bounded: bool,
sink: &mut dyn PlainSink,
) -> Result<usize, Error> {
let _ = (bounded, sink);
Ok(index)
}
}
#[cfg(feature = "derive")]
#[inline]
pub fn emit_plain_field<T: Serialize>(
value: &T,
name: &str,
sink: &mut dyn PlainSink,
bounded: bool,
) -> Result<bool, Error> {
if !value.__private_is_plain_value() {
return Ok(false);
}
if bounded && value.__private_plain_cost(PLAIN_BUDGET).is_none() {
return Ok(false);
}
sink.field(name)?;
value.__private_emit_plain(sink)?;
Ok(true)
}
#[cfg(feature = "derive")]
pub struct IndexedStructEmitter<'a> {
fields: &'a dyn IndexedStruct,
index: usize,
}
#[cfg(feature = "derive")]
impl<'a> IndexedStructEmitter<'a> {
pub fn new(fields: &'a dyn IndexedStruct) -> IndexedStructEmitter<'a> {
IndexedStructEmitter { fields, index: 0 }
}
}
#[cfg(feature = "derive")]
#[inline(never)]
pub fn serialize_indexed<'a>(
fields: &'a dyn IndexedStruct,
state: &mut State,
) -> Result<Chunk<'a>, Error> {
Ok(Chunk::structure(IndexedStructEmitter::new(fields), state))
}
#[cfg(feature = "derive")]
#[inline(never)]
pub fn describe_struct(
d: &mut dyn crate::ser::Describe,
name: &str,
fields: &'static [&'static str],
) {
d.structure(name);
d.fields(fields);
}
#[cfg(feature = "derive")]
impl<'a> StructEmitter for IndexedStructEmitter<'a> {
fn next(
&mut self,
_state: &mut State,
) -> Result<Option<(Cow<'_, str>, SerializeHandle<'_>)>, Error> {
loop {
let field = self.fields.field(self.index);
self.index += 1;
match field {
StructField::Field(key, value) => return Ok(Some((Cow::Borrowed(key), value))),
StructField::Skip => continue,
StructField::End => return Ok(None),
}
}
}
}
pub trait IndexedSeq: Sync {
fn element(
&self,
index: usize,
state: &mut State,
) -> Result<Option<SerializeHandle<'_>>, Error>;
#[inline]
fn emit_plain(&self, sink: &mut dyn PlainSink) -> Result<bool, Error> {
let _ = sink;
Ok(false)
}
#[inline]
fn emit_plain_chunk(
&self,
index: usize,
budget: usize,
sink: &mut dyn PlainSink,
) -> Result<usize, Error> {
let _ = (budget, sink);
Ok(index)
}
}
pub struct IndexedSeqEmitter<'a> {
seq: &'a dyn IndexedSeq,
index: usize,
}
impl<'a> IndexedSeqEmitter<'a> {
pub fn new(seq: &'a dyn IndexedSeq) -> IndexedSeqEmitter<'a> {
IndexedSeqEmitter { seq, index: 0 }
}
}
impl<'a> SeqEmitter for IndexedSeqEmitter<'a> {
fn next(&mut self, state: &mut State) -> Result<Option<SerializeHandle<'_>>, Error> {
let index = self.index;
self.index += 1;
self.seq.element(index, state)
}
}
pub const FIELDS_END: usize = usize::MAX;
pub trait PlainSink {
fn atom(&mut self, atom: Atom<'_>) -> Result<(), Error>;
fn seq_start(&mut self, shape: ContainerShape) -> Result<(), Error>;
fn seq_end(&mut self) -> Result<(), Error>;
fn map_start(&mut self, shape: ContainerShape) -> Result<(), Error>;
fn map_end(&mut self) -> Result<(), Error>;
fn key(&mut self);
fn field(&mut self, name: &str) -> Result<(), Error>;
}
macro_rules! plain_atom {
(|$this:ident| $atom:expr) => {
#[inline]
fn __private_is_plain() -> bool
where
Self: Sized,
{
true
}
#[inline]
fn __private_emit_plain(
&self,
sink: &mut dyn crate::ser::PlainSink,
) -> Result<(), crate::Error> {
let $this = self;
sink.atom($atom)
}
#[inline]
fn __private_plain_cost(&self, budget: usize) -> Option<usize> {
let $this = self;
budget.checked_sub(crate::ser::atom_cost(&$atom))
}
};
}
pub(crate) use plain_atom;