use std::borrow::{BorrowMut, Cow};
use std::fmt::Debug;
use std::io::Write;
use std::marker::PhantomData;
use std::mem::replace;
use std::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
};
use std::ops::{Deref, DerefMut};
use quick_xml::{
escape::escape,
events::{BytesEnd, BytesStart, BytesText, Event},
Writer,
};
use crate::misc::{Namespace, NamespacePrefix};
use crate::xml::QName;
use super::{Error, ErrorKind, RawByteStr};
pub trait WithSerializer {
type Serializer<'x>: Serializer<'x>
where
Self: 'x;
fn serializer<'ser>(
&'ser self,
name: Option<&'ser str>,
is_root: bool,
) -> Result<Self::Serializer<'ser>, Error>;
}
pub trait Serializer<'ser>: Debug {
fn next(&mut self, helper: &mut SerializeHelper) -> Option<Result<Event<'ser>, Error>>;
fn into_iter(self) -> SerializerIter<'ser, Self, SerializeHelper>
where
Self: Sized,
{
self.into_iter_with(SerializeHelper::default())
}
fn into_iter_with<H>(self, helper: H) -> SerializerIter<'ser, Self, H>
where
Self: Sized,
H: BorrowMut<SerializeHelper>,
{
SerializerIter::new(self, helper)
}
}
impl<'ser, X> Serializer<'ser> for X
where
X: DerefMut + Debug,
X::Target: Serializer<'ser>,
{
fn next(&mut self, helper: &mut SerializeHelper) -> Option<Result<Event<'ser>, Error>> {
self.deref_mut().next(helper)
}
}
pub trait WithBoxedSerializer {
fn serializer<'ser>(
&'ser self,
name: Option<&'ser str>,
is_root: bool,
) -> Result<BoxedSerializer<'ser>, Error>;
}
impl<X> WithBoxedSerializer for X
where
X: WithSerializer,
{
fn serializer<'ser>(
&'ser self,
name: Option<&'ser str>,
is_root: bool,
) -> Result<BoxedSerializer<'ser>, Error> {
Ok(Box::new(WithSerializer::serializer(self, name, is_root)?))
}
}
pub type BoxedSerializer<'ser> = Box<dyn Serializer<'ser> + 'ser>;
pub trait SerializeSync: Sized {
type Error;
fn serialize<W: Write>(&self, root: &str, writer: &mut Writer<W>) -> Result<(), Self::Error>;
}
impl<X> SerializeSync for X
where
X: WithSerializer,
{
type Error = Error;
fn serialize<W: Write>(&self, root: &str, writer: &mut Writer<W>) -> Result<(), Self::Error> {
SerializeImpl::new(self, Some(root), writer)?.serialize_sync()
}
}
#[cfg(feature = "async")]
pub trait SerializeAsync: Sized {
type Future<'x>: std::future::Future<Output = Result<(), Self::Error>> + 'x
where
Self: 'x;
type Error;
fn serialize_async<'a, W: tokio::io::AsyncWrite + Unpin>(
&'a self,
root: &'a str,
writer: &'a mut Writer<W>,
) -> Self::Future<'a>;
}
#[cfg(feature = "async")]
impl<X> SerializeAsync for X
where
X: WithSerializer,
{
type Future<'x>
= std::pin::Pin<Box<dyn std::future::Future<Output = Result<(), Self::Error>> + 'x>>
where
X: 'x;
type Error = Error;
fn serialize_async<'a, W: tokio::io::AsyncWrite + Unpin>(
&'a self,
root: &'a str,
writer: &'a mut Writer<W>,
) -> Self::Future<'a> {
Box::pin(async move {
SerializeImpl::new(self, Some(root), writer)?
.serialize_async()
.await
})
}
}
pub trait SerializeBytes: Sized {
fn serialize_bytes(&self, helper: &mut SerializeHelper) -> Result<Option<Cow<'_, str>>, Error>;
}
pub trait SerializeBytesToString: ToString {}
impl<X> SerializeBytes for X
where
X: SerializeBytesToString,
{
fn serialize_bytes(&self, helper: &mut SerializeHelper) -> Result<Option<Cow<'_, str>>, Error> {
let _helper = helper;
Ok(Some(Cow::Owned(self.to_string())))
}
}
impl SerializeBytesToString for bool {}
impl SerializeBytesToString for String {}
impl SerializeBytesToString for u8 {}
impl SerializeBytesToString for u16 {}
impl SerializeBytesToString for u32 {}
impl SerializeBytesToString for u64 {}
impl SerializeBytesToString for u128 {}
impl SerializeBytesToString for usize {}
impl SerializeBytesToString for i8 {}
impl SerializeBytesToString for i16 {}
impl SerializeBytesToString for i32 {}
impl SerializeBytesToString for i64 {}
impl SerializeBytesToString for i128 {}
impl SerializeBytesToString for isize {}
impl SerializeBytesToString for f32 {}
impl SerializeBytesToString for f64 {}
impl SerializeBytesToString for NonZeroU8 {}
impl SerializeBytesToString for NonZeroU16 {}
impl SerializeBytesToString for NonZeroU32 {}
impl SerializeBytesToString for NonZeroU64 {}
impl SerializeBytesToString for NonZeroU128 {}
impl SerializeBytesToString for NonZeroUsize {}
impl SerializeBytesToString for NonZeroI8 {}
impl SerializeBytesToString for NonZeroI16 {}
impl SerializeBytesToString for NonZeroI32 {}
impl SerializeBytesToString for NonZeroI64 {}
impl SerializeBytesToString for NonZeroI128 {}
impl SerializeBytesToString for NonZeroIsize {}
#[cfg(feature = "num")]
impl SerializeBytesToString for num::BigInt {}
#[cfg(feature = "num")]
impl SerializeBytesToString for num::BigUint {}
pub trait WithSerializeToBytes: SerializeBytes {}
impl<X> WithSerializeToBytes for X where X: SerializeBytesToString {}
impl<X> WithSerializer for X
where
X: WithSerializeToBytes + Debug,
{
type Serializer<'x>
= ContentSerializer<'x, X>
where
Self: 'x;
fn serializer<'ser>(
&'ser self,
name: Option<&'ser str>,
is_root: bool,
) -> Result<Self::Serializer<'ser>, Error> {
Ok(ContentSerializer::new(self, name, is_root))
}
}
#[derive(Debug)]
#[allow(missing_docs)]
pub enum ContentSerializer<'ser, T> {
Begin {
name: Option<&'ser str>,
value: &'ser T,
},
Data {
name: Option<&'ser str>,
data: Cow<'ser, str>,
},
End {
name: &'ser str,
},
Done,
}
impl<'ser, T> ContentSerializer<'ser, T>
where
T: SerializeBytes + Debug,
{
pub fn new(value: &'ser T, name: Option<&'ser str>, is_root: bool) -> Self {
let _is_root = is_root;
Self::Begin { name, value }
}
}
impl<'ser, T> Serializer<'ser> for ContentSerializer<'ser, T>
where
T: SerializeBytes + Debug,
{
fn next(&mut self, helper: &mut SerializeHelper) -> Option<Result<Event<'ser>, Error>> {
loop {
match replace(self, Self::Done) {
Self::Begin { name, value } => match value.serialize_bytes(helper) {
Ok(None) => return name.map(|name| Ok(Event::Empty(BytesStart::new(name)))),
Ok(Some(data)) => {
if data.contains("]]>") {
return Some(Err(ErrorKind::InvalidData(RawByteStr::from_slice(
data.as_bytes(),
))
.into()));
}
*self = Self::Data { name, data };
if let Some(name) = name {
return Some(Ok(Event::Start(BytesStart::new(name))));
}
}
Err(error) => return Some(Err(error)),
},
Self::Data { name, data } => {
if let Some(name) = name {
*self = Self::End { name };
}
if data.is_empty() {
continue;
}
return Some(Ok(Event::Text(BytesText::from_escaped(escape(data)))));
}
Self::End { name } => return Some(Ok(Event::End(BytesEnd::new(name)))),
Self::Done => return None,
}
}
}
}
#[derive(Debug)]
#[allow(missing_docs)]
pub enum IterSerializer<'ser, T, TItem>
where
T: IntoIterator<Item = &'ser TItem> + 'ser,
<T as IntoIterator>::IntoIter: Debug,
TItem: WithSerializer + 'ser,
{
Pending {
name: Option<&'ser str>,
iter: <T as IntoIterator>::IntoIter,
},
Emitting {
name: Option<&'ser str>,
iter: <T as IntoIterator>::IntoIter,
serializer: TItem::Serializer<'ser>,
},
Done,
}
impl<'ser, T, TItem> Serializer<'ser> for IterSerializer<'ser, T, TItem>
where
T: IntoIterator<Item = &'ser TItem> + Debug + 'ser,
<T as IntoIterator>::IntoIter: Debug,
TItem: WithSerializer + Debug + 'ser,
{
fn next(&mut self, helper: &mut SerializeHelper) -> Option<Result<Event<'ser>, Error>> {
loop {
match replace(self, Self::Done) {
Self::Pending { name, mut iter } => {
let item = iter.next()?;
match item.serializer(name, false) {
Ok(serializer) => {
*self = Self::Emitting {
name,
iter,
serializer,
}
}
Err(error) => return Some(Err(error)),
}
}
Self::Emitting {
name,
iter,
mut serializer,
} => {
if let Some(ret) = serializer.next(helper) {
*self = Self::Emitting {
name,
iter,
serializer,
};
return Some(ret);
}
*self = Self::Pending { name, iter };
}
Self::Done => return None,
}
}
}
}
impl<'ser, T, TItem> IterSerializer<'ser, T, TItem>
where
T: IntoIterator<Item = &'ser TItem> + 'ser,
<T as IntoIterator>::IntoIter: Debug,
TItem: WithSerializer + 'ser,
{
pub fn new(value: T, name: Option<&'ser str>, is_root: bool) -> Self {
let _is_root = is_root;
Self::Pending {
name,
iter: value.into_iter(),
}
}
}
#[derive(Debug)]
pub struct DerefIter<T>(pub T::IntoIter)
where
T: IntoIterator;
impl<T> DerefIter<T>
where
T: IntoIterator,
{
pub fn new(inner: T) -> Self {
Self(inner.into_iter())
}
}
impl<'x, T, TItem> Iterator for DerefIter<T>
where
T: IntoIterator,
T::IntoIter: Iterator<Item = &'x TItem>,
TItem: Deref + 'x,
{
type Item = &'x TItem::Target;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(Deref::deref)
}
}
#[derive(Debug)]
pub struct SerializerIter<'ser, S, H>
where
S: Serializer<'ser>,
H: BorrowMut<SerializeHelper>,
{
serializer: S,
helper: H,
lt: PhantomData<&'ser ()>,
}
impl<'ser, S, H> SerializerIter<'ser, S, H>
where
S: Serializer<'ser>,
H: BorrowMut<SerializeHelper>,
{
pub fn new(serializer: S, helper: H) -> Self {
Self {
serializer,
helper,
lt: PhantomData,
}
}
}
impl<'ser, S, H> Iterator for SerializerIter<'ser, S, H>
where
S: Serializer<'ser>,
H: BorrowMut<SerializeHelper>,
{
type Item = Result<Event<'ser>, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.serializer.next(self.helper.borrow_mut())
}
}
pub trait CollectNamespaces {
fn collect_namespaces(&self, helper: &mut SerializeHelper, bytes: &mut BytesStart<'_>);
}
macro_rules! impl_collect_namespaces {
($ident:path) => {
impl CollectNamespaces for $ident {
fn collect_namespaces(&self, _: &mut SerializeHelper, _: &mut BytesStart<'_>) {}
}
};
}
impl_collect_namespaces!(bool);
impl_collect_namespaces!(char);
impl_collect_namespaces!(str);
impl_collect_namespaces!(String);
impl_collect_namespaces!(u8);
impl_collect_namespaces!(u16);
impl_collect_namespaces!(u32);
impl_collect_namespaces!(u64);
impl_collect_namespaces!(u128);
impl_collect_namespaces!(usize);
impl_collect_namespaces!(i8);
impl_collect_namespaces!(i16);
impl_collect_namespaces!(i32);
impl_collect_namespaces!(i64);
impl_collect_namespaces!(i128);
impl_collect_namespaces!(isize);
impl_collect_namespaces!(f32);
impl_collect_namespaces!(f64);
impl_collect_namespaces!(std::num::NonZeroU8);
impl_collect_namespaces!(std::num::NonZeroU16);
impl_collect_namespaces!(std::num::NonZeroU32);
impl_collect_namespaces!(std::num::NonZeroU64);
impl_collect_namespaces!(std::num::NonZeroU128);
impl_collect_namespaces!(std::num::NonZeroUsize);
impl_collect_namespaces!(std::num::NonZeroI8);
impl_collect_namespaces!(std::num::NonZeroI16);
impl_collect_namespaces!(std::num::NonZeroI32);
impl_collect_namespaces!(std::num::NonZeroI64);
impl_collect_namespaces!(std::num::NonZeroI128);
impl_collect_namespaces!(std::num::NonZeroIsize);
#[cfg(feature = "num")]
impl_collect_namespaces!(num::BigInt);
#[cfg(feature = "num")]
impl_collect_namespaces!(num::BigUint);
impl<T: CollectNamespaces> CollectNamespaces for Option<T> {
fn collect_namespaces(&self, helper: &mut SerializeHelper, bytes: &mut BytesStart<'_>) {
if let Some(inner) = self {
inner.collect_namespaces(helper, bytes);
}
}
}
impl<T: CollectNamespaces> CollectNamespaces for Vec<T> {
fn collect_namespaces(&self, helper: &mut SerializeHelper, bytes: &mut BytesStart<'_>) {
for item in self {
item.collect_namespaces(helper, bytes);
}
}
}
impl<T: CollectNamespaces + ?Sized> CollectNamespaces for Box<T> {
fn collect_namespaces(&self, helper: &mut SerializeHelper, bytes: &mut BytesStart<'_>) {
self.as_ref().collect_namespaces(helper, bytes);
}
}
impl<T: CollectNamespaces, const N: usize> CollectNamespaces for [T; N] {
fn collect_namespaces(&self, helper: &mut SerializeHelper, bytes: &mut BytesStart<'_>) {
for item in self {
item.collect_namespaces(helper, bytes);
}
}
}
impl<T: CollectNamespaces> CollectNamespaces for [T] {
fn collect_namespaces(&self, helper: &mut SerializeHelper, bytes: &mut BytesStart<'_>) {
for item in self {
item.collect_namespaces(helper, bytes);
}
}
}
#[derive(Default, Debug)]
pub struct SerializeHelper {
level: usize,
namespaces: Vec<NamespaceEntry>,
}
#[derive(Debug)]
struct NamespaceEntry {
level: usize,
prefix: Option<NamespacePrefix>,
namespace: Namespace,
}
impl SerializeHelper {
pub fn begin_ns_scope(&mut self) {
self.level += 1;
}
pub fn end_ns_scope(&mut self) {
self.level = self.level.saturating_sub(1);
loop {
let is_outdated =
matches!(self.namespaces.last(), Some(entry) if entry.level > self.level);
if is_outdated {
self.namespaces.pop();
} else {
break;
}
}
}
pub fn add_qname_namespace(&mut self, bytes: &mut BytesStart<'_>, mut qname: QName) -> QName {
let Some(ns) = qname.take_namespace() else {
return qname;
};
if let Some(entry) = self
.namespaces
.iter()
.rev()
.find(|entry| entry.namespace == ns)
{
qname = if let Some(prefix) = &entry.prefix {
QName::from_bytes(
prefix
.0
.iter()
.chain(Some(&b':'))
.chain(qname.local_name())
.copied()
.collect::<Vec<u8>>(),
)
} else {
QName::from_bytes(qname.local_name().to_vec())
};
qname = qname.with_namespace(ns);
} else {
self.add_namespace_entry(bytes, qname.prefix(), ns.clone());
}
qname
}
pub fn write_xmlns(
&mut self,
bytes: &mut BytesStart<'_>,
prefix: Option<&NamespacePrefix>,
namespace: &Namespace,
) {
let prefix = prefix.filter(|p| !p.0.is_empty());
for entry in self.namespaces.iter().rev() {
if &entry.namespace == namespace {
if entry.prefix.as_ref() == prefix {
return;
}
break;
}
}
self.add_namespace_entry(bytes, prefix.map(|x| &x.0[..]), namespace.clone());
}
pub fn write_attrib<T>(
&mut self,
bytes: &mut BytesStart<'_>,
name: &str,
attrib: &T,
) -> Result<(), Error>
where
T: SerializeBytes,
{
if let Some(attrib) = SerializeBytes::serialize_bytes(attrib, self)? {
bytes.push_attribute((name, attrib));
}
Ok(())
}
pub fn write_attrib_opt<T>(
&mut self,
bytes: &mut BytesStart<'_>,
name: &str,
attrib: &Option<T>,
) -> Result<(), Error>
where
T: SerializeBytes,
{
let Some(attrib) = attrib else {
return Ok(());
};
self.write_attrib(bytes, name, attrib)
}
pub fn get_namespace_prefix(
&self,
namespace: &Namespace,
) -> Result<Option<NamespacePrefix>, Error> {
for entry in self.namespaces.iter().rev() {
if &entry.namespace == namespace {
return Ok(entry.prefix.clone());
}
}
Err(ErrorKind::UnknownNamespace(namespace.clone()))?
}
fn add_namespace_entry(
&mut self,
bytes: &mut BytesStart<'_>,
prefix: Option<&[u8]>,
namespace: Namespace,
) {
let xmlns = prefix.map(|x| b"xmlns:".iter().chain(x).copied().collect::<Vec<u8>>());
let xmlns = xmlns.as_deref().unwrap_or(b"xmlns");
bytes.push_attribute((xmlns, &**namespace));
self.namespaces.push(NamespaceEntry {
level: self.level,
prefix: prefix.map(|x| NamespacePrefix::new(x.to_vec())),
namespace,
});
}
}
struct SerializeImpl<'a, T, W>
where
T: WithSerializer + 'a,
{
helper: SerializeHelper,
writer: &'a mut Writer<W>,
serializer: T::Serializer<'a>,
}
impl<'a, T, W> SerializeImpl<'a, T, W>
where
T: WithSerializer,
{
fn new(value: &'a T, name: Option<&'a str>, writer: &'a mut Writer<W>) -> Result<Self, Error> {
let helper = SerializeHelper::default();
let serializer = value.serializer(name, true)?;
Ok(Self {
helper,
writer,
serializer,
})
}
}
impl<T, W> SerializeImpl<'_, T, W>
where
T: WithSerializer,
W: Write,
{
fn serialize_sync(&mut self) -> Result<(), Error> {
while let Some(event) = self.serializer.next(&mut self.helper) {
self.writer
.write_event(event?)
.map_err(|error| ErrorKind::XmlError(error.into()))?;
}
Ok(())
}
}
#[cfg(feature = "async")]
impl<T, W> SerializeImpl<'_, T, W>
where
T: WithSerializer,
W: tokio::io::AsyncWrite + Unpin,
{
async fn serialize_async(&mut self) -> Result<(), Error> {
while let Some(event) = self.serializer.next(&mut self.helper) {
self.writer
.write_event_async(event?)
.await
.map_err(ErrorKind::XmlError)?;
}
Ok(())
}
}