#[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,
}
}
use crate::ser::{Emit, SeqEmitter, SerializeHandle, SerializeRef};
#[cfg(feature = "derive")]
use crate::ser::{Serialize, StructEmitter};
pub struct Begin<'a> {
pub(crate) kind: BeginKind<'a>,
pub(crate) shape: ContainerShape,
pub(crate) needs_finish: bool,
}
pub(crate) enum BeginKind<'a> {
Emit(Emit<'a>),
Struct(&'a dyn IndexedStruct),
Seq(&'a dyn IndexedSeq),
Plain(SerializeRef<'a>),
}
impl<'a> Begin<'a> {
#[inline]
pub fn emit(emit: Emit<'a>, shape: ContainerShape, needs_finish: bool) -> Begin<'a> {
Begin {
kind: BeginKind::Emit(emit),
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: SerializeRef<'a>, 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,
}
}
#[inline]
pub(crate) unsafe fn indexed_seq_unbounded<S: IndexedSeq>(
value: *const S,
shape: ContainerShape,
) -> Begin<'a> {
Begin::indexed_seq(unsafe { indexed_unbounded(value) }, shape)
}
}
#[inline(always)]
pub(crate) unsafe fn indexed_unbounded<'a, S: IndexedSeq>(
value: *const S,
) -> &'a (dyn IndexedSeq + 'a) {
let value: *const (dyn IndexedSeq + '_) = value;
unsafe {
&*core::mem::transmute::<*const (dyn IndexedSeq + '_), *const (dyn IndexedSeq + 'a)>(value)
}
}
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 !T::__private_is_plain_value(value) {
return Ok(false);
}
if bounded && T::__private_plain_cost(value, PLAIN_BUDGET).is_none() {
return Ok(false);
}
sink.field(name)?;
T::__private_emit_plain(value, sink)?;
Ok(true)
}
#[cfg(feature = "derive")]
struct IndexedStructEmitter<'a> {
fields: &'a dyn IndexedStruct,
index: usize,
}
#[cfg(feature = "derive")]
impl<'a> IndexedStructEmitter<'a> {
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<Emit<'a>, Error> {
Ok(Emit::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: $ty:ty| $atom:expr) => {
#[inline]
fn __private_is_plain() -> bool {
true
}
#[inline]
fn __private_emit_plain(
$this: &$ty,
sink: &mut dyn crate::ser::PlainSink,
) -> Result<(), crate::Error> {
sink.atom($atom)
}
#[inline]
fn __private_plain_cost($this: &$ty, budget: usize) -> Option<usize> {
budget.checked_sub(crate::ser::atom_cost(&$atom))
}
};
(|$this:ident| $atom:expr) => {
plain_atom!(|$this: Self| $atom);
};
}
pub(crate) use plain_atom;