diff --git a/xso/ChangeLog b/xso/ChangeLog index 693d8a2a3eaa20af70b50ce85e9cf4b627d0c329..1d34987a368767a75ca28062bd4cd726a9dd324b 100644 --- a/xso/ChangeLog +++ b/xso/ChangeLog @@ -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 diff --git a/xso/src/asxml.rs b/xso/src/asxml.rs index 4e9fe7e2c6fc66ec1c03e6811d0382688bcae504..14ba3933d9267ee80abeca08bda7a72e8c1b7cd3 100644 --- a/xso/src/asxml.rs +++ b/xso/src/asxml.rs @@ -127,6 +127,28 @@ impl 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, Error>> + 'x>, Error>; +} + +impl 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, Error>> + 'x>, Error> { + ::as_xml_dyn_iter(self) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/xso/src/lib.rs b/xso/src/lib.rs index 04365d3895eb364557d592a29003933c3f6d4681..d32d9286f54b1928de1f95ad5264a5168e225e1c 100644 --- a/xso/src/lib.rs +++ b/xso/src/lib.rs @@ -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::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, 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