use alloc::borrow::Cow;
use alloc::collections::{BTreeSet, VecDeque};
use alloc::format;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
#[cfg(feature = "std")]
use core::hash::{BuildHasher, Hash};
use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::collections::HashSet;
use crate::State;
use crate::Text;
use crate::adapters::Same;
use crate::de::{Deserialize, Sink, SinkHandle};
use crate::error::{Error, ErrorKind};
use crate::event::{Atom, ContainerShape};
use crate::ext::Number;
use crate::ser::{Begin, Describe, Emit, Serialize};
pub struct Separated<const SEP: char = ',', A = Same>(PhantomData<fn() -> A>);
pub struct TrimWhitespace<A = Same>(PhantomData<fn() -> A>);
pub struct SkipBlank<A = Same>(PhantomData<fn() -> A>);
#[derive(Clone, Copy)]
enum TextOp {
Split(char),
Trim,
}
struct TextSink<'a, 'de> {
inner: SinkHandle<'a, 'de>,
op: TextOp,
}
impl<'a, 'de> TextSink<'a, 'de> {
fn handle(inner: SinkHandle<'a, 'de>, op: TextOp, state: &mut State) -> SinkHandle<'a, 'de> {
SinkHandle::arena(TextSink { inner, op }, state)
}
}
fn trimmed_range(text: &str) -> (usize, usize) {
let start = text.len() - text.trim_start().len();
let end = text.trim_end().len().max(start);
(start, end)
}
fn with_text<'x>(atom: &Atom<'_>, text: Text<'x>) -> Atom<'x> {
match atom {
Atom::Str(_) => Atom::Str(text),
_ => Atom::Lexical(text),
}
}
fn trim_atom(atom: Atom<'_>) -> Atom<'_> {
match atom {
Atom::Str(ref text) | Atom::Lexical(ref text) => {
let (start, end) = trimmed_range(text);
if start == 0 && end == text.len() {
return atom;
}
let trimmed = match text.borrowed_str() {
Some(text) => Text::borrowed(&text[start..end]),
None => Text::owned(&text[start..end]),
};
with_text(&atom, trimmed)
}
atom => atom,
}
}
fn split_into<'de>(
sink: &mut SinkHandle<'_, 'de>,
text: &str,
sep: char,
state: &mut State,
) -> Result<(), Error> {
sink.seq(state)?;
if !text.is_empty() {
for piece in text.split(sep) {
let rv = sink.__private_value_atom(Atom::Lexical(Text::borrowed(piece)), state);
recover_element(sink, rv, state)?;
}
}
Ok(())
}
#[inline]
fn recover_element(
sink: &mut SinkHandle<'_, '_>,
rv: Result<(), Error>,
state: &mut State,
) -> Result<(), Error> {
match rv {
Ok(()) => Ok(()),
Err(err) if state.discards_errors => Err(err),
Err(err) => sink.recover(state.error_in_context(err), state),
}
}
fn split_borrowed_into<'de>(
sink: &mut SinkHandle<'_, 'de>,
text: &'de str,
sep: char,
state: &mut State,
) -> Result<(), Error> {
sink.seq(state)?;
if !text.is_empty() {
for piece in text.split(sep) {
let rv =
sink.__private_borrowed_value_atom(Atom::Lexical(Text::borrowed(piece)), state);
recover_element(sink, rv, state)?;
}
}
Ok(())
}
impl<'a, 'de> Sink<'de> for TextSink<'a, 'de> {
fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
match (self.op, atom) {
(TextOp::Split(sep), Atom::Str(text) | Atom::Lexical(text)) => {
split_into(&mut self.inner, &text, sep, state)
}
(TextOp::Trim, atom) => self.inner.atom(trim_atom(atom), state),
(_, atom) => self.inner.atom(atom, state),
}
}
fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
match (self.op, atom) {
(TextOp::Split(sep), Atom::Str(ref text) | Atom::Lexical(ref text))
if text.is_borrowed() =>
{
let text = text.borrowed_str().unwrap_or_default();
split_borrowed_into(&mut self.inner, text, sep, state)
}
(TextOp::Split(sep), Atom::Str(text) | Atom::Lexical(text)) => {
split_into(&mut self.inner, &text, sep, state)
}
(TextOp::Trim, atom) => self.inner.borrowed_atom(trim_atom(atom), state),
(_, atom) => self.inner.borrowed_atom(atom, state),
}
}
fn map(&mut self, state: &mut State) -> Result<(), Error> {
self.inner.map(state)
}
fn seq(&mut self, state: &mut State) -> Result<(), Error> {
self.inner.seq(state)
}
fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
self.inner.next_key(state)
}
fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
self.inner.next_value(state)
}
fn __private_key_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
self.inner.__private_key_atom(atom, state)
}
fn __private_value_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
self.inner.__private_value_atom(atom, state)
}
fn __private_borrowed_key_atom(
&mut self,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
self.inner.__private_borrowed_key_atom(atom, state)
}
fn __private_borrowed_value_atom(
&mut self,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
self.inner.__private_borrowed_value_atom(atom, state)
}
fn value_for_key(
&mut self,
key: &str,
state: &mut State,
) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
self.inner.value_for_key(key, state)
}
fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
self.inner.recover(err, state)
}
fn finish(&mut self, state: &mut State) -> Result<(), Error> {
self.inner.finish(state)
}
fn expecting(&self) -> Cow<'_, str> {
self.inner.expecting()
}
}
#[inline]
fn is_blank(atom: &Atom) -> bool {
matches!(atom, Atom::Str(text) | Atom::Lexical(text) if text.trim().is_empty())
}
enum SkipBlankSink<'a, 'de, T, A> {
Pending(&'a mut Option<T>, PhantomData<fn() -> A>),
Active(SinkHandle<'a, 'de>),
}
impl<'a, 'de, T: Send, A: Deserialize<'de, T>> SkipBlankSink<'a, 'de, T, A> {
fn active(&mut self, state: &mut State) -> &mut SinkHandle<'a, 'de> {
if let SkipBlankSink::Pending(..) = self
&& let SkipBlankSink::Pending(out, _) =
core::mem::replace(self, SkipBlankSink::Active(SinkHandle::null()))
{
*self = SkipBlankSink::Active(A::deserialize_into(out, state));
}
match self {
SkipBlankSink::Active(sink) => sink,
SkipBlankSink::Pending(..) => unreachable!(),
}
}
fn skip(&mut self, atom: &Atom) -> bool {
if matches!(self, SkipBlankSink::Pending(..)) && is_blank(atom) {
*self = SkipBlankSink::Active(SinkHandle::null());
return true;
}
false
}
}
impl<'a, 'de, T: Send, A: Deserialize<'de, T>> Sink<'de> for SkipBlankSink<'a, 'de, T, A> {
fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
if self.skip(&atom) {
return Ok(());
}
self.active(state).atom(atom, state)
}
fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
if self.skip(&atom) {
return Ok(());
}
self.active(state).borrowed_atom(atom, state)
}
fn map(&mut self, state: &mut State) -> Result<(), Error> {
self.active(state).map(state)
}
fn seq(&mut self, state: &mut State) -> Result<(), Error> {
self.active(state).seq(state)
}
fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
self.active(state).next_key(state)
}
fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
self.active(state).next_value(state)
}
fn __private_key_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
self.active(state).__private_key_atom(atom, state)
}
fn __private_value_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
self.active(state).__private_value_atom(atom, state)
}
fn __private_borrowed_key_atom(
&mut self,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
self.active(state).__private_borrowed_key_atom(atom, state)
}
fn __private_borrowed_value_atom(
&mut self,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
self.active(state)
.__private_borrowed_value_atom(atom, state)
}
fn value_for_key(
&mut self,
key: &str,
state: &mut State,
) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
self.active(state).value_for_key(key, state)
}
fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
self.active(state).recover(err, state)
}
fn finish(&mut self, state: &mut State) -> Result<(), Error> {
self.active(state).finish(state)
}
fn expecting(&self) -> Cow<'_, str> {
match self {
SkipBlankSink::Active(sink) => sink.expecting(),
SkipBlankSink::Pending(..) => A::expecting(),
}
}
}
impl<'de, T: Send, A: Deserialize<'de, T>> Deserialize<'de, T> for SkipBlank<A> {
fn deserialize_into<'out>(
out: &'out mut Option<T>,
state: &mut State,
) -> SinkHandle<'out, 'de> {
unsafe {
SinkHandle::arena_unbounded(SkipBlankSink::<T, A>::Pending(out, PhantomData), state)
}
}
fn expecting() -> Cow<'static, str> {
A::expecting()
}
fn describe_type(d: &mut dyn Describe) {
A::describe_type(d)
}
fn initial_value() -> Option<T> {
A::initial_value()
}
#[inline]
fn __private_atom_into(
out: &mut Option<T>,
atom: Atom,
state: &mut State,
) -> Result<(), Error> {
if is_blank(&atom) {
return Ok(());
}
A::__private_atom_into(out, atom, state)
}
#[inline]
fn __private_borrowed_atom_into(
out: &mut Option<T>,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
if is_blank(&atom) {
return Ok(());
}
A::__private_borrowed_atom_into(out, atom, state)
}
fn __private_is_bytes() -> bool {
A::__private_is_bytes()
}
fn __private_vec_from_bytes(bytes: Vec<u8>) -> Option<Vec<T>> {
A::__private_vec_from_bytes(bytes)
}
fn __private_array_from_bytes<const N: usize>(bytes: &[u8]) -> Option<[T; N]> {
A::__private_array_from_bytes::<N>(bytes)
}
}
impl<'de, T: Send, A: Deserialize<'de, T>> Deserialize<'de, T> for TrimWhitespace<A> {
fn deserialize_into<'out>(
out: &'out mut Option<T>,
state: &mut State,
) -> SinkHandle<'out, 'de> {
TextSink::handle(A::deserialize_into(out, state), TextOp::Trim, state)
}
fn expecting() -> Cow<'static, str> {
A::expecting()
}
fn describe_type(d: &mut dyn Describe) {
A::describe_type(d)
}
fn initial_value() -> Option<T> {
A::initial_value()
}
#[inline]
fn __private_atom_into(
out: &mut Option<T>,
atom: Atom,
state: &mut State,
) -> Result<(), Error> {
A::__private_atom_into(out, trim_atom(atom), state)
}
#[inline]
fn __private_borrowed_atom_into(
out: &mut Option<T>,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
A::__private_borrowed_atom_into(out, trim_atom(atom), state)
}
fn __private_is_bytes() -> bool {
A::__private_is_bytes()
}
fn __private_vec_from_bytes(bytes: Vec<u8>) -> Option<Vec<T>> {
A::__private_vec_from_bytes(bytes)
}
fn __private_array_from_bytes<const N: usize>(bytes: &[u8]) -> Option<[T; N]> {
A::__private_array_from_bytes::<N>(bytes)
}
}
impl<T: ?Sized, A: Serialize<T>> Serialize<T> for TrimWhitespace<A> {
fn serialize<'a>(value: &'a T, state: &mut State) -> Result<Emit<'a>, Error> {
A::serialize(value, state)
}
fn finish(value: &T, state: &mut State) -> Result<(), Error> {
A::finish(value, state)
}
fn is_optional(value: &T) -> bool {
A::is_optional(value)
}
fn container_shape(value: &T) -> ContainerShape {
A::container_shape(value)
}
fn describe(value: &T, d: &mut dyn Describe) {
A::describe(value, d)
}
#[inline]
fn __private_begin<'a>(value: &'a T, state: &mut State) -> Result<Begin<'a>, Error> {
A::__private_begin(value, state)
}
fn __private_slice_as_bytes(val: &[T]) -> Option<Cow<'_, [u8]>>
where
T: Sized,
{
A::__private_slice_as_bytes(val)
}
}
impl<T: ?Sized, A: Serialize<T>> Serialize<T> for SkipBlank<A> {
fn serialize<'a>(value: &'a T, state: &mut State) -> Result<Emit<'a>, Error> {
A::serialize(value, state)
}
fn finish(value: &T, state: &mut State) -> Result<(), Error> {
A::finish(value, state)
}
fn is_optional(value: &T) -> bool {
A::is_optional(value)
}
fn container_shape(value: &T) -> ContainerShape {
A::container_shape(value)
}
fn describe(value: &T, d: &mut dyn Describe) {
A::describe(value, d)
}
#[inline]
fn __private_begin<'a>(value: &'a T, state: &mut State) -> Result<Begin<'a>, Error> {
A::__private_begin(value, state)
}
fn __private_slice_as_bytes(val: &[T]) -> Option<Cow<'_, [u8]>>
where
T: Sized,
{
A::__private_slice_as_bytes(val)
}
}
#[cold]
fn unsupported_element(what: &str) -> Error {
Error::new(
ErrorKind::UnsupportedType,
format!(
"cannot join {}, elements must be strings, numbers, booleans or chars",
what
),
)
}
fn atom_text<'a>(atom: &'a Atom<'_>) -> Result<Cow<'a, str>, Error> {
Ok(match *atom {
Atom::Bool(value) => Cow::Borrowed(if value { "true" } else { "false" }),
Atom::Str(ref value) | Atom::Lexical(ref value) => Cow::Borrowed(value),
Atom::Char(value) => Cow::Owned(value.to_string()),
Atom::U64(value) => Cow::Owned(value.to_string()),
Atom::I64(value) => Cow::Owned(value.to_string()),
Atom::F32(value) => Cow::Owned(value.to_string()),
Atom::F64(value) => Cow::Owned(value.to_string()),
Atom::Ext(ref ext) => {
if let Some(number) = ext.downcast_value_ref::<Number>() {
Cow::Owned(number.as_str().to_string())
} else if let Some(value) = ext.downcast_ref::<u128>() {
Cow::Owned(value.to_string())
} else if let Some(value) = ext.downcast_ref::<i128>() {
Cow::Owned(value.to_string())
} else {
match ext.fallback() {
Atom::Ext(_) => return Err(unsupported_element(ext.name())),
fallback => Cow::Owned(atom_text(&fallback)?.into_owned()),
}
}
}
ref atom => return Err(unsupported_element(atom.name())),
})
}
fn push_emit(emit: Emit<'_>, state: &mut State, out: &mut String) -> Result<(), Error> {
match emit {
Emit::Atom(ref atom) => out.push_str(&atom_text(atom)?),
Emit::Forward(handle) => {
push_emit(handle.get().serialize(state)?, state, out)?;
handle.get().finish(state)?;
}
Emit::Struct(_) | Emit::Map(_) => return Err(unsupported_element("map")),
Emit::Seq(_) => return Err(unsupported_element("sequence")),
}
Ok(())
}
fn join<'v, T: 'v, A: Serialize<T>>(
values: impl Iterator<Item = &'v T>,
sep: char,
state: &mut State,
) -> Result<String, Error> {
let mut out = String::new();
let mut count = 0;
for value in values {
if count > 0 {
out.push(sep);
}
count += 1;
let start = out.len();
push_emit(A::serialize(value, state)?, state, &mut out)?;
A::finish(value, state)?;
if out[start..].contains(sep) {
return Err(Error::new(
ErrorKind::InvalidValue,
format!(
"cannot join {:?}, it contains the separator {:?}",
&out[start..],
sep
),
));
}
}
if count == 1 && out.is_empty() {
return Err(Error::new(
ErrorKind::InvalidValue,
"cannot join a single empty string, it would read back as no elements",
));
}
Ok(out)
}
macro_rules! separated_impls {
($([$($bound:tt)*] [$($ser_bound:tt)*] $target:ty => $adapter:ty;)*) => {
$(
impl<'de, $($bound)*, A: Deserialize<'de, T>, const SEP: char>
Deserialize<'de, $target> for Separated<SEP, A>
{
fn deserialize_into<'out>(out: &'out mut Option<$target>, state: &mut State) -> SinkHandle<'out, 'de> {
TextSink::handle(
<$adapter as Deserialize<'de, $target>>::deserialize_into(out, state),
TextOp::Split(SEP), state)
}
fn expecting() -> Cow<'static, str> {
<$adapter as Deserialize<'de, $target>>::expecting()
}
}
impl<$($ser_bound)*, A: Serialize<T>, const SEP: char> Serialize<$target>
for Separated<SEP, A>
{
fn serialize<'a>(
value: &'a $target,
state: &mut State,
) -> Result<Emit<'a>, Error> {
let text = join::<T, A>(value.iter(), SEP, state)?;
Ok(Emit::Atom(Atom::Str(Text::owned(text))))
}
#[inline]
fn __private_begin<'a>(
value: &'a $target,
state: &mut State,
) -> Result<Begin<'a>, Error> {
Ok(Begin::emit(
Self::serialize(value, state)?,
ContainerShape::new(),
false,
))
}
}
)*
};
}
separated_impls! {
[T: Send] [T] Vec<T> => Vec<A>;
[T: Send] [T] VecDeque<T> => VecDeque<A>;
[T: Ord + Send] [T] BTreeSet<T> => BTreeSet<A>;
}
#[cfg(feature = "std")]
separated_impls! {
[T: Hash + Eq + Send, H: BuildHasher + Default + Send] [T, H] HashSet<T, H> => HashSet<A>;
}