//! # Generic iterator type implementations //! //! This module contains [`AsXml`] iterator implementations for types from //! foreign libraries (such as the standard library). //! //! In order to not clutter the `xso` crate's main namespace, they are //! stashed away in a separate module. // Copyright (c) 2024 Jonas Schäfer // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. use crate::error::Error; use crate::rxml_util::Item; use crate::AsXml; /// Helper iterator to convert an `Option` to XML. pub struct OptionAsXml(Option); impl OptionAsXml { /// Construct a new iterator, wrapping the given iterator. /// /// If `inner` is `None`, this iterator terminates immediately. Otherwise, /// it yields the elements yielded by `inner` until `inner` finishes, /// after which this iterator completes, too. pub fn new(inner: Option) -> Self { Self(inner) } } impl<'x, T: Iterator, Error>>> Iterator for OptionAsXml { type Item = Result, Error>; fn next(&mut self) -> Option { self.0.as_mut()?.next() } } impl AsXml for Option { type ItemIter<'x> = OptionAsXml> where T: 'x; fn as_xml_iter(&self) -> Result, Error> { match self { Some(ref value) => Ok(OptionAsXml(Some(T::as_xml_iter(value)?))), None => Ok(OptionAsXml(None)), } } } /// Helper iterator to convert an `Box` to XML. pub struct BoxAsXml(Box); impl<'x, T: Iterator, Error>>> Iterator for BoxAsXml { type Item = Result, Error>; fn next(&mut self) -> Option { self.0.next() } } impl AsXml for Box { type ItemIter<'x> = BoxAsXml> where T: 'x; fn as_xml_iter(&self) -> Result, Error> { Ok(BoxAsXml(Box::new(T::as_xml_iter(&self)?))) } } /// Emits the items of `T` if `Ok(.)` or returns the error from `E` otherwise. impl AsXml for Result where for<'a> Error: From<&'a E>, { type ItemIter<'x> = T::ItemIter<'x> where Self: 'x; fn as_xml_iter(&self) -> Result, Error> { match self { Self::Ok(v) => Ok(v.as_xml_iter()?), Self::Err(e) => Err(e.into()), } } } #[cfg(test)] mod tests { use super::*; use std::borrow::Cow; #[test] fn option_as_xml_terminates_immediately_for_none() { let mut iter = OptionAsXml::>(None); match iter.next() { None => (), other => panic!("unexpected item: {:?}", other), } } #[test] fn option_as_xml_passes_values_from_inner_some() { let inner = vec![ Ok(Item::Text(Cow::Borrowed("hello world"))), Ok(Item::ElementFoot), ]; let mut iter = OptionAsXml(Some(inner.into_iter())); match iter.next() { Some(Ok(Item::Text(text))) => { assert_eq!(text, "hello world"); } other => panic!("unexpected item: {:?}", other), } match iter.next() { Some(Ok(Item::ElementFoot)) => (), other => panic!("unexpected item: {:?}", other), } match iter.next() { None => (), other => panic!("unexpected item: {:?}", other), } } #[test] fn box_as_xml_passes_values_from_inner() { let inner = vec![ Ok(Item::Text(Cow::Borrowed("hello world"))), Ok(Item::ElementFoot), ]; let mut iter = BoxAsXml(Box::new(inner.into_iter())); match iter.next() { Some(Ok(Item::Text(text))) => { assert_eq!(text, "hello world"); } other => panic!("unexpected item: {:?}", other), } match iter.next() { Some(Ok(Item::ElementFoot)) => (), other => panic!("unexpected item: {:?}", other), } match iter.next() { None => (), other => panic!("unexpected item: {:?}", other), } } }