xso: add type-erased and dyn-compatible variant of AsXml

That way, we don't need to know the specific type of iterator or even
iteree anymore. This can turn out useful when working with `Box<dyn _>`,
that is, in contexts where we don't know the (possible or actual) types
at compile time.
This commit is contained in:
Jonas Schäfer 2025-05-01 10:30:46 +02:00 committed by Link Mauve
commit d7b62488dc
3 changed files with 40 additions and 1 deletions

View file

@ -53,6 +53,7 @@ Version NEXT:
- `xso::convert_via_fromstr_and_display`, a declarative macro to provide
`AsXmlText` and `FromXmlText` implementations based on the standard
library's `Display` and `FromStr` traits.
- `AsXmlDyn`, a dyn-compatible variant of `AsXml` (!573).
* Changes
- Generated AsXml iterator and FromXml builder types are now
doc(hidden), to not clutter hand-written documentation with auto

View file

@ -127,6 +127,28 @@ impl<T: AsXml> fmt::Display for PrintRawXml<'_, T> {
}
}
/// Dyn-compatible version of [`AsXml`].
///
/// This trait is automatically implemented for all types which implement
/// `AsXml`.
pub trait AsXmlDyn {
/// Return an iterator which emits the contents of the struct or enum as
/// serialisable [`Item`] items.
fn as_xml_dyn_iter<'x>(
&'x self,
) -> Result<Box<dyn Iterator<Item = Result<Item<'x>, Error>> + 'x>, Error>;
}
impl<T: AsXml> AsXmlDyn for T {
/// Return an iterator which emits the contents of the struct or enum as
/// serialisable [`Item`] items by calling [`AsXml::as_xml_dyn_iter`].
fn as_xml_dyn_iter<'x>(
&'x self,
) -> Result<Box<dyn Iterator<Item = Result<Item<'x>, Error>> + 'x>, Error> {
<T as AsXml>::as_xml_dyn_iter(self)
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -100,7 +100,7 @@ pub mod exports {
}
}
use alloc::{borrow::Cow, string::String, vec::Vec};
use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
#[doc(inline)]
pub use fromxml::Context;
@ -150,6 +150,22 @@ pub trait AsXml {
/// Return an iterator which emits the contents of the struct or enum as
/// serialisable [`Item`] items.
fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, self::error::Error>;
/// Return the same iterator as [`as_xml_iter`][`Self::as_xml_iter`], but
/// boxed to erase the concrete iterator type.
///
/// The provided implementation uses a simple cast. In most cases, it does
/// not make sense to override the implementation. The only exception is
/// if [`Self::ItemIter`] is already a boxed type, in which case
/// overriding this method can avoid double-boxing the iterator.
fn as_xml_dyn_iter<'x>(
&'x self,
) -> Result<
Box<dyn Iterator<Item = Result<Item<'x>, self::error::Error>> + 'x>,
self::error::Error,
> {
self.as_xml_iter().map(|x| Box::new(x) as Box<_>)
}
}
/// Trait for a temporary object allowing to construct a struct from