Skip to main content

xso/
dynxso.rs

1// Copyright (c) 2025 Jonas Schäfer <jonas@zombofant.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! # Dynamically-typed XSOs
8//!
9//! This module provides the utilities to make dynamically-typed XSOs work.
10//! Dynamically typed XSOs are for example contained in
11//! [`Xso<dyn Trait>`][`Xso`] or [`XsoVec<dyn Trait>`][`XsoVec`], where
12//! `Trait` is a trait provided and defined by the user.
13//!
14//! The given `Trait` constrains the specific types which can be used in the
15//! `Xso<dyn Trait>` box. This allows users to provide additional methods on
16//! the trait which are available on all `Xso<dyn Trait>` objects via the
17//! [`Deref`][`core::ops::Deref`] and [`DerefMut`][`core::ops::DerefMut`]
18//! implementations.
19//!
20//! `Xso<dyn Trait>` (and also [`XsoVec<dyn Trait>`][`XsoVec`]) can be parsed
21//! from XML and serialised to XML, provided some constraints are fulfilled.
22//!
23//! For serialisation, the `Trait` must have a bound on `AsXmlDyn`, requiring
24//! *all* implementors of the trait to implement `AsXml`.
25//!
26//! For parsing, all implementations of the trait must register themselves
27//! with the trait so that the `FromXml` implementation knows about them and
28//! can use them to parse the XML data. How this is done is depends on the way
29//! the trait is declared.
30//!
31//! XSO supports three ways of doing so:
32//!
33//! 1. Using the [`linktime`] macro (requiring the `linktime` crate feature)
34//!    strictly at compile-time / linking-time of the final application
35//!    binary.
36//!
37//!    This is the recommended way as it incurs a very low runtime overhead and
38//!    does not depend on `std` either.
39//!
40//! 2. Using the `std`-based [`BuilderRegistry`] through the [`xso_trait`]
41//!    macro.
42//!
43//! 3. Using a custom registry through the [`xso_trait`] macro.
44//!
45//! Please refer to the linked macros for usage details and examples.
46//!
47//! ## Dynamically-typed XSOs vs. enums
48//!
49//! One key question you should ask yourself when looking at this module and
50//! before going down the route of dynamically-typed XSOs is: "Is an enum
51//! enough for my use-case?"
52//!
53//! The key difference between dynamically-typed XSOs and enums is that enums
54//! cannot be extended by other crates, or even outside the source file they
55//! are declared in. Dynamically-typed XSOs can be extended by any code place
56//! where a trait implementation of that dynamic XSO trait is possible, which
57//! is virtually anywhere.
58//!
59//! Dynamically-typed XSOs are thus more useful in plugin-like situations or
60//! when providing an extension point for other crates. Enums are more useful
61//! when you know the exact variants of acceptable XML data. Enums are
62//! generally likely to be more performant, as the lookups needed can be
63//! hardcoded and arbitrarily optimized by the compiler.
64
65use alloc::{
66    boxed::Box,
67    collections::{
68        btree_map::{self, Entry},
69        BTreeMap,
70    },
71    vec::{self, Vec},
72};
73use core::{
74    any::{Any, TypeId},
75    fmt,
76    ops::{Deref, DerefMut},
77    slice,
78};
79
80use crate::{
81    asxml::AsXmlDyn,
82    error::{Error, FromEventsError},
83    AsXml, Context, FromEventsBuilder, FromXml, Item,
84};
85
86/// **NOT** part of the public API -- only exposed for use by macros.
87#[doc(hidden)]
88#[cfg(feature = "linktime")]
89pub mod linktime;
90
91#[cfg(feature = "std")]
92mod stdreg;
93
94#[cfg(feature = "std")]
95pub use stdreg::*;
96
97#[doc(inline)]
98#[cfg(feature = "linktime")]
99pub use crate::__linktime as linktime;
100
101/// Make a trait usable as dynamic XSO trait.
102///
103/// This macro generates [`DynXso`] and [`MayContain`] trait implementations
104/// for `dyn Trait` for a given `Trait`. For more background information on
105/// when that is a useful thing to have, see the [`dynxso`][`crate::dynxso`]
106/// module.
107///
108/// ## Syntax
109///
110/// This macro can be called in two forms:
111///
112/// - `xso_trait!(Trait)` uses the default [`BuilderRegistry`]
113///    as [`DynXso::Registry`] type and is only available if `xso` is built
114///    with the `"std"` feature.
115/// - `xso_trait!(Trait use Type = expr)` where `Type` is used as
116///   [`DynXso::Registry`], initialized with `expr`. This form is available
117///   for any set of crate features.
118///
119/// ## Example
120///
121#[cfg_attr(
122    not(all(feature = "macros", feature = "std")),
123    doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
124)]
125#[cfg_attr(all(feature = "macros", feature = "std"), doc = "\n```\n")]
126/// # use core::any::Any;
127/// # use xso::{dynxso::{Xso, BuilderRegistry, xso_trait}, FromXml, from_bytes};
128/// trait MyPayload: Any {}
129///
130/// xso_trait!(MyPayload);
131///
132/// #[derive(FromXml, Debug, PartialEq)]
133/// #[xml(namespace = "urn:example", name = "foo")]
134/// struct Foo;
135/// impl MyPayload for Foo {}
136/// Xso::<dyn MyPayload>::register_type::<Foo>();
137///
138/// #[derive(FromXml, Debug, PartialEq)]
139/// #[xml(namespace = "urn:example", name = "bar")]
140/// struct Bar;
141/// impl MyPayload for Bar {}
142/// Xso::<dyn MyPayload>::register_type::<Bar>();
143///
144/// let x: Xso<dyn MyPayload> = from_bytes("<foo xmlns='urn:example'/>".as_bytes()).unwrap();
145/// assert_eq!(Foo, *x.downcast::<Foo>().unwrap());
146///
147/// let x: Xso<dyn MyPayload> = from_bytes("<bar xmlns='urn:example'/>".as_bytes()).unwrap();
148/// assert_eq!(Bar, *x.downcast::<Bar>().unwrap());
149/// ```
150///
151/// Note that the trait this macro is called on **must** have a bound on
152/// `Any`, otherwise the generated code will not compile:
153///
154#[cfg_attr(
155    not(feature = "std"),
156    doc = "Because the std feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
157)]
158#[cfg_attr(feature = "std", doc = "\n```compile_fail\n")]
159/// use xso::dynxso::xso_trait;
160/// trait Foo {}
161/// xso_trait!(Foo);
162/// // ↑ will generate a bunch of errors about incompatible types
163/// ```
164///
165/// If the `std` feature is not enabled or if you want to use another
166/// `Registry` for whichever reason, the explicit form can be used:
167///
168/// ```
169/// # use core::any::Any;
170/// use xso::dynxso::xso_trait;
171/// trait Foo: Any {}
172/// struct Registry { /* .. */ }
173/// xso_trait!(Foo use Registry = Registry { /* .. */ });
174/// ```
175///
176/// In that case, you should review the trait requirements of the
177/// [`DynXso::Registry`] associated type.
178#[doc(hidden)]
179#[macro_export]
180macro_rules! __xso_trait {
181    ($trait:ident use $registry:ty = $reginit:expr) => {
182        impl $crate::dynxso::DynXso for dyn $trait {
183            type Registry = $registry;
184
185            fn registry() -> &'static Self::Registry {
186                static DATA: $registry = $reginit;
187                &DATA
188            }
189
190            fn try_downcast<T: 'static>(
191                self: $crate::exports::alloc::boxed::Box<Self>,
192            ) -> Result<
193                $crate::exports::alloc::boxed::Box<T>,
194                $crate::exports::alloc::boxed::Box<Self>,
195            >
196            where
197                Self: $crate::dynxso::MayContain<T>,
198            {
199                if (&*self as &dyn core::any::Any).is::<T>() {
200                    match (self as $crate::exports::alloc::boxed::Box<dyn core::any::Any>)
201                        .downcast()
202                    {
203                        Ok(v) => Ok(v),
204                        Err(_) => unreachable!("Any::is and Any::downcast disagree!"),
205                    }
206                } else {
207                    Err(self)
208                }
209            }
210
211            fn try_downcast_ref<T: 'static>(&self) -> Option<&T>
212            where
213                Self: $crate::dynxso::MayContain<T>,
214            {
215                (&*self as &dyn core::any::Any).downcast_ref()
216            }
217
218            fn try_downcast_mut<T: 'static>(&mut self) -> Option<&mut T>
219            where
220                Self: $crate::dynxso::MayContain<T>,
221            {
222                (&mut *self as &mut dyn core::any::Any).downcast_mut()
223            }
224
225            fn is<T: 'static>(&self) -> bool
226            where
227                Self: $crate::dynxso::MayContain<T>,
228            {
229                (&*self as &dyn core::any::Any).is::<T>()
230            }
231
232            fn type_id(&self) -> core::any::TypeId {
233                (&*self as &dyn core::any::Any).type_id()
234            }
235        }
236
237        impl<T: $trait> $crate::dynxso::MayContain<T> for dyn $trait {
238            fn upcast_into(other: T) -> Box<Self> {
239                Box::new(other)
240            }
241        }
242    };
243    ($trait:ident) => {
244        $crate::_internal_xso_trait_std_only!($trait);
245    };
246}
247
248#[doc(inline)]
249pub use crate::__xso_trait as xso_trait;
250
251#[macro_export]
252#[doc(hidden)]
253#[cfg(feature = "std")]
254macro_rules! _internal_xso_trait_std_only {
255    ($trait:ident) => {
256        $crate::__xso_trait!($trait use $crate::dynxso::BuilderRegistry<dyn $trait> = $crate::dynxso::BuilderRegistry::new());
257    };
258}
259
260#[macro_export]
261#[doc(hidden)]
262#[cfg(not(feature = "std"))]
263macro_rules! _internal_xso_trait_std_only {
264    ($trait:ident) => {
265        compile_error!(concat!("xso_trait!(", stringify!($trait), ") can only be used if the xso crate has been built with the \"std\" feature enabled. Without \"std\", the explicit form of xso_trait!(", stringify!($trait), " use .. = ..) must be used (see docs)."));
266    };
267}
268
269/// # Helper traits for dynamic XSO builder registries.
270///
271/// Builder registries hold type-erased [`FromXml::from_events`]
272/// implementations. Registries can be used to dynamically dispatch to a set
273/// of `FromXml` implementations which is not known at compile time.
274///
275/// Under the hood, they are used by the `FromXml` implementation on
276/// [`Xso<T>`][`Xso`], via the [`DynXso::Registry`] type.
277///
278/// Note that registries generally do not allow to add arbitrary builders. All
279/// builders must originate in a [`FromXml`] implementation and their output
280/// must be convertible to the specific type the registry is defined for.
281///
282/// The default implementation is [`BuilderRegistry`], which is only available
283/// if `xso` is built with the `"std"` feature due to the inherent need for a
284/// `Mutex`.
285pub mod registry {
286    use super::*;
287
288    /// Trait for a builder registry supports constructing elements.
289    pub trait DynXsoRegistryLookup<T: ?Sized> {
290        /// Make a builder for the given element header.
291        ///
292        /// This tries all applicable `FromXml` implementations which have
293        /// previously been added via [`add`][`DynXsoRegistryAdd::add`] in
294        /// unspecified order. The first implementation to either fail or
295        /// succeed at constructing a builder determines the result.
296        /// Implementations which return a
297        /// [`FromEventsError::Mismatch`][`crate::error::FromEventsError::Mismatch`]
298        /// are ignored.
299        ///
300        /// If all applicable implementations return `Mismatch`, this function
301        /// returns `Mismatch`, too.
302        fn make_builder(
303            &self,
304            name: rxml::QName,
305            attrs: rxml::AttrMap,
306            ctx: &Context<'_>,
307        ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError>;
308    }
309
310    /// Trait for a builder registry supports registering new builders at
311    /// runtime.
312    pub trait DynXsoRegistryAdd<T: ?Sized> {
313        /// Add a new builder to the registry.
314        ///
315        /// This allows to add any `FromXml` implementation whose output can be
316        /// converted to `T`.
317        fn add<U: Any + FromXml>(&self)
318        where
319            T: MayContain<U>;
320    }
321}
322
323use registry::*;
324
325/// Dynamic XSO type
326///
327/// This trait is normally implemented only on trait-object types, i.e. on
328/// `dyn Trait` for some `Trait`. It provides the infrastructure for dynamic
329/// XSO types. In particular:
330///
331/// - Access to a registry which allows constructing an instance of the
332///   dynamic XSO type from XML.
333/// - Downcasts to specific types.
334///
335/// Implementations of this trait are best generated using the [`linktime`]
336/// or [`xso_trait`] macros.
337///
338/// This trait explicitly provides the methods also provided by [`Any`]. The
339/// reason for this duplication is that with `DynXso` being intended to be
340/// implemented on `dyn Trait`, code using this trait cannot cast the value
341/// to `dyn Any` to access the `downcast`-related methods (`type_id` would,
342/// in fact, work if `DynXso` had a bound on `Any`, but not the downcasts).
343///
344/// *Hint*: It should not be necessary for user code to directly interact
345/// with this trait.
346pub trait DynXso: 'static {
347    /// Builder registry type for this dynamic type.
348    ///
349    /// The `Registry` type *should* implement the following traits:
350    ///
351    /// - [`DynXsoRegistryAdd`] is required to make
352    ///   [`Xso::<Self>::register_type()`][`Xso::register_type`] available.
353    /// - [`DynXsoRegistryLookup`] is required to make [`FromXml`] available
354    ///   on [`Xso<Self>`][`Xso`] (and, by extension, on
355    ///   [`XsoVec<Self>`][`XsoVec`]).
356    ///
357    /// However, any type with static lifetime can be used, even without the
358    /// trait implementations above, if the limitations are acceptable.
359    type Registry: 'static;
360
361    /// Return the builder registry for this dynamic type.
362    ///
363    /// See [`Registry`][`Self::Registry`] for details.
364    fn registry() -> &'static Self::Registry;
365
366    /// Try to downcast a boxed dynamic XSO to a specific type.
367    ///
368    /// If `self` contains a `T` (and thus, the downcast succeeds), `Ok(_)`
369    /// is returned. Otherwise, `Err(self)` is returned, allowing to chain
370    /// this function with other downcast attempts.
371    ///
372    /// This is similar to `downcast` on [`dyn Any`][`core::any::Any`].
373    fn try_downcast<T: 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>>
374    where
375        Self: MayContain<T>;
376
377    /// Try to downcast a dynamic XSO to a reference to a specific type.
378    ///
379    /// If `self` contains a `T` (and thus, the downcast succeeds), `Some(_)`
380    /// is returned. Otherwise, `None`.
381    ///
382    /// This is similar to `downcast_ref` on [`dyn Any`][`core::any::Any`].
383    fn try_downcast_ref<T: 'static>(&self) -> Option<&T>
384    where
385        Self: MayContain<T>;
386
387    /// Try to downcast a dynamic XSO to a mutable reference to a specific
388    /// type.
389    ///
390    /// If `self` contains a `T` (and thus, the downcast succeeds), `Some(_)`
391    /// is returned. Otherwise, `None`.
392    ///
393    /// This is similar to `downcast_mut` on [`dyn Any`][`core::any::Any`].
394    fn try_downcast_mut<T: 'static>(&mut self) -> Option<&mut T>
395    where
396        Self: MayContain<T>;
397
398    /// Return true if `self` contains a `T`.
399    ///
400    /// This is similar to `is` on [`dyn Any`][`core::any::Any`].
401    fn is<T: 'static>(&self) -> bool
402    where
403        Self: MayContain<T>;
404
405    /// Return the [`TypeId`] of `self`.
406    ///
407    /// This is similar to `type_id` on [`dyn Any`][`core::any::Any`].
408    fn type_id(&self) -> TypeId;
409}
410
411/// Declare that `T` may be held by `Box<Self>`
412///
413/// This trait is used to constrain which types can be put in
414/// [`Xso<Self>`][`Xso`]. It is typically implemented on `dyn Trait` for all
415/// `T: Trait`.
416///
417/// To automatically generate suitable implementations of this trait, see
418/// the [`linktime`] and [`xso_trait`] macros.
419///
420/// Implementation-wise, this trait is very similar to `Box<Self>: From<T>`.
421/// However, `From` is also used in many different circumstances and it cannot
422/// be suitably overloaded on `Box<_>`, so a new trait was introduced for this
423/// particular purpose.
424pub trait MayContain<T> {
425    /// Convert a value of `T` into `Box<Self>`.
426    fn upcast_into(other: T) -> Box<Self>;
427}
428
429/// # Dynamic XSO container
430///
431/// This container is very similar to `Box<_>`, but geared specifically toward
432/// the use with `T` being a `dyn Trait`. It also implements [`FromXml`] (if
433/// `T` implements [`DynXso`] with a Registry implementing
434/// [`DynXsoRegistryLookup`]) and [`AsXml`] (if `T` implements [`AsXmlDyn`]).
435///
436/// In order to provide these features, `T` must implement [`DynXso`] and
437/// [`MayContain`]. Implementations for these traits can be generated using
438/// [`xso_trait`].
439///
440/// Most methods on `Xso<dyn Trait>` which take type parameters are only
441/// available for types `U` implementing `Trait` (or, more precisely, where
442/// `dyn Trait` implements `MayContain<U>`).
443#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
444#[repr(transparent)]
445pub struct Xso<T: ?Sized> {
446    inner: Box<T>,
447}
448
449impl<T: ?Sized> Deref for Xso<T> {
450    type Target = T;
451
452    fn deref(&self) -> &Self::Target {
453        self.inner.deref()
454    }
455}
456
457impl<T: ?Sized> DerefMut for Xso<T> {
458    fn deref_mut(&mut self) -> &mut Self::Target {
459        self.inner.deref_mut()
460    }
461}
462
463impl<T: DynXso + ?Sized> fmt::Debug for Xso<T> {
464    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
465        f.debug_struct("Xso")
466            .field("inner", &self.inner_type_id())
467            .finish()
468    }
469}
470
471impl<T: ?Sized> Xso<T> {
472    /// Wrap a value into a `Xso<dyn Trait>`.
473    ///
474    /// ```
475    /// # use core::any::Any;
476    /// # use xso::dynxso::{Xso, xso_trait};
477    /// trait Trait: Any {}
478    #[cfg_attr(feature = "std", doc = "xso_trait!(Trait);")]
479    #[cfg_attr(not(feature = "std"), doc = "xso_trait!(Trait use () = ());")]
480    ///
481    /// struct Foo;
482    /// impl Trait for Foo {}
483    ///
484    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
485    /// ```
486    pub fn wrap<U: 'static>(value: U) -> Self
487    where
488        T: MayContain<U>,
489    {
490        Self {
491            inner: T::upcast_into(value),
492        }
493    }
494
495    /// Convert `Xso<T>` into `Box<T>`.
496    ///
497    /// ```
498    /// # use core::any::Any;
499    /// # use xso::dynxso::{Xso, xso_trait};
500    /// trait Trait: Any {}
501    #[cfg_attr(feature = "std", doc = "xso_trait!(Trait);")]
502    #[cfg_attr(not(feature = "std"), doc = "xso_trait!(Trait use () = ());")]
503    ///
504    /// struct Foo;
505    /// impl Trait for Foo {}
506    ///
507    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
508    /// let x: Box<dyn Trait> = x.into_boxed();
509    /// ```
510    pub fn into_boxed(self) -> Box<T> {
511        self.inner
512    }
513}
514
515impl<T: DynXso + ?Sized + 'static> Xso<T> {
516    /// Downcast `self` to `Box<U>`.
517    ///
518    /// If the downcast fails, `self` is returned without change.
519    ///
520    /// ```
521    /// # use core::any::Any;
522    /// # use xso::dynxso::{Xso, xso_trait};
523    /// trait Trait: Any {}
524    #[cfg_attr(feature = "std", doc = "xso_trait!(Trait);")]
525    #[cfg_attr(not(feature = "std"), doc = "xso_trait!(Trait use () = ());")]
526    ///
527    /// struct Foo;
528    /// impl Trait for Foo {}
529    ///
530    /// struct Bar;
531    /// impl Trait for Bar {}
532    ///
533    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
534    /// // Does not contain a Bar, so downcast fails.
535    /// let x: Xso<dyn Trait> = x.downcast::<Bar>().err().unwrap();
536    /// // *Does* contain a Foo, so downcast succeeds.
537    /// let f: Foo = *x.downcast().unwrap();
538    /// ```
539    pub fn downcast<U: 'static>(self) -> Result<Box<U>, Self>
540    where
541        T: MayContain<U>,
542    {
543        match self.inner.try_downcast() {
544            Ok(v) => Ok(v),
545            Err(inner) => Err(Self { inner }),
546        }
547    }
548
549    fn force_downcast<U: 'static>(self) -> Box<U>
550    where
551        T: MayContain<U>,
552    {
553        match self.downcast::<U>() {
554            Ok(v) => v,
555            Err(v) => panic!(
556                "force_downcast called on mismatching types: requested {:?} ({}) != actual {:?}",
557                TypeId::of::<U>(),
558                core::any::type_name::<U>(),
559                v.inner_type_id()
560            ),
561        }
562    }
563
564    /// Downcast `&self` to `&U`.
565    ///
566    /// ```
567    /// # use core::any::Any;
568    /// # use xso::dynxso::{Xso, xso_trait};
569    /// trait Trait: Any {}
570    #[cfg_attr(feature = "std", doc = "xso_trait!(Trait);")]
571    #[cfg_attr(not(feature = "std"), doc = "xso_trait!(Trait use () = ());")]
572    ///
573    /// struct Foo;
574    /// impl Trait for Foo {}
575    ///
576    /// struct Bar;
577    /// impl Trait for Bar {}
578    ///
579    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
580    /// // Does not contain a Bar, so downcast fails.
581    /// assert!(x.downcast_ref::<Bar>().is_none());
582    /// // *Does* contain a Foo, so downcast succeeds.
583    /// let f: &Foo = x.downcast_ref().unwrap();
584    /// ```
585    pub fn downcast_ref<U: 'static>(&self) -> Option<&U>
586    where
587        T: MayContain<U>,
588    {
589        self.inner.try_downcast_ref()
590    }
591
592    /// Downcast `&mut self` to `&mut U`.
593    ///
594    /// ```
595    /// # use core::any::Any;
596    /// # use xso::dynxso::{Xso, xso_trait};
597    /// trait Trait: Any {}
598    #[cfg_attr(feature = "std", doc = "xso_trait!(Trait);")]
599    #[cfg_attr(not(feature = "std"), doc = "xso_trait!(Trait use () = ());")]
600    ///
601    /// struct Foo;
602    /// impl Trait for Foo {}
603    ///
604    /// struct Bar;
605    /// impl Trait for Bar {}
606    ///
607    /// let mut x: Xso<dyn Trait> = Xso::wrap(Foo);
608    /// // Does not contain a Bar, so downcast fails.
609    /// assert!(x.downcast_mut::<Bar>().is_none());
610    /// // *Does* contain a Foo, so downcast succeeds.
611    /// let f: &mut Foo = x.downcast_mut().unwrap();
612    /// ```
613    pub fn downcast_mut<U: 'static>(&mut self) -> Option<&mut U>
614    where
615        T: MayContain<U>,
616    {
617        self.inner.try_downcast_mut()
618    }
619
620    fn inner_type_id(&self) -> TypeId {
621        DynXso::type_id(&*self.inner)
622    }
623}
624
625impl<R: DynXsoRegistryAdd<T> + 'static, T: DynXso<Registry = R> + ?Sized + 'static> Xso<T> {
626    /// Register a new type to be constructible.
627    ///
628    /// Only types registered through this function or through
629    /// [`linktime`] can be parsed from XML via the [`FromXml`]
630    /// implementation on `Xso<T>`. See [`dynxso`][`crate::dynxso`] for
631    /// details.
632    ///
633    #[cfg_attr(
634        not(all(feature = "macros", feature = "std")),
635        doc = "Because the macros and std features were not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
636    )]
637    #[cfg_attr(all(feature = "macros", feature = "std"), doc = "\n```\n")]
638    /// # use core::any::Any;
639    /// # use xso::{dynxso::{Xso, xso_trait}, from_bytes, FromXml};
640    /// trait Trait: Any {}
641    /// xso_trait!(Trait);
642    ///
643    /// #[derive(FromXml, PartialEq, Debug)]
644    /// #[xml(namespace = "urn:example", name = "foo")]
645    /// struct Foo;
646    /// impl Trait for Foo {}
647    ///
648    /// // Parsing fails, because register_type() has not been called for
649    /// // Foo:
650    /// assert!(from_bytes::<Xso<dyn Trait>>("<foo xmlns='urn:example'/>".as_bytes()).is_err());
651    ///
652    /// Xso::<dyn Trait>::register_type::<Foo>();
653    /// // After registering Foo with Xso<dyn Trait>, parsing succeeds and
654    /// // we can downcast to Foo:
655    /// let x: Xso<dyn Trait> = from_bytes("<foo xmlns='urn:example'/>".as_bytes()).unwrap();
656    /// assert_eq!(Foo, *x.downcast().unwrap());
657    /// ```
658    pub fn register_type<U: FromXml + 'static>()
659    where
660        T: MayContain<U>,
661    {
662        T::registry().add::<U>()
663    }
664}
665
666/// Wrapper around a `FromEventsBuilder` to convert a `Box<T>` output to a
667/// `Xso<T>` output.
668///
669/// Not constructible by users, only for internal use.
670pub struct DynBuilder<B> {
671    inner: B,
672}
673
674impl<T: DynXso + ?Sized + 'static, B: FromEventsBuilder<Output = Box<T>>> FromEventsBuilder
675    for DynBuilder<B>
676{
677    type Output = Xso<T>;
678
679    fn feed(&mut self, ev: rxml::Event, ctx: &Context) -> Result<Option<Self::Output>, Error> {
680        self.inner
681            .feed(ev, ctx)
682            .map(|x| x.map(|inner| Xso { inner }))
683    }
684}
685
686/// Wrapper around a `FromEventsBuilder` to convert a `Box<T>` output to a
687/// `T` output.
688pub struct UnboxBuilder<T> {
689    inner: T,
690}
691
692impl<O, T: FromEventsBuilder<Output = Box<O>>> UnboxBuilder<T> {
693    /// Wrap a `FromEventsBuilder` which generates `Box<O>`.
694    pub fn wrap(inner: T) -> Self {
695        Self { inner }
696    }
697}
698
699impl<O, T: FromEventsBuilder<Output = Box<O>>> FromEventsBuilder for UnboxBuilder<T> {
700    type Output = O;
701
702    fn feed(&mut self, ev: rxml::Event, ctx: &Context) -> Result<Option<Self::Output>, Error> {
703        self.inner.feed(ev, ctx).map(|x| x.map(|inner| *inner))
704    }
705}
706
707impl<R: DynXsoRegistryLookup<T> + 'static, T: DynXso<Registry = R> + ?Sized + 'static> FromXml
708    for Xso<T>
709{
710    type Builder = DynBuilder<Box<dyn FromEventsBuilder<Output = Box<T>>>>;
711
712    fn from_events(
713        name: rxml::QName,
714        attrs: rxml::AttrMap,
715        ctx: &Context<'_>,
716    ) -> Result<Self::Builder, FromEventsError> {
717        T::registry()
718            .make_builder(name, attrs, ctx)
719            .map(|inner| DynBuilder { inner })
720    }
721}
722
723impl<T: DynXso + AsXmlDyn + ?Sized + 'static> AsXml for Xso<T> {
724    type ItemIter<'x> = Box<dyn Iterator<Item = Result<Item<'x>, Error>> + 'x>;
725
726    fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
727        self.inner.as_xml_dyn_iter()
728    }
729
730    fn as_xml_dyn_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
731        self.inner.as_xml_dyn_iter()
732    }
733}
734
735/// Error type for retrieving a single item from `XsoVec`.
736#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
737pub enum TakeOneError {
738    /// More than one item was found.
739    MultipleEntries,
740}
741
742impl fmt::Display for TakeOneError {
743    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
744        match self {
745            Self::MultipleEntries => f.write_str("multiple entries found"),
746        }
747    }
748}
749
750/// # Container for dynamically-typed XSOs optimized for type-keyed access
751///
752/// This container holds dynamically typed XSOs (see
753/// [`Xso<dyn Trait>`][`Xso`]). It allows efficient access to its contents
754/// based on the actual type.
755///
756/// Like `Xso<dyn Trait>` itself, `XsoVec<dyn Trait>` requires that
757/// `MayContain` is implemented by `dyn Trait` for all items which are added
758/// to the container. This is automatically the case for all `T: Trait`
759/// if [`xso_trait`] has been used on `Trait`.
760///
761/// Note that `XsoVec` has a non-obvious iteration order, which is described
762/// in [`XsoVec::iter()`][`Self::iter`].
763pub struct XsoVec<T: ?Sized> {
764    inner: BTreeMap<TypeId, Vec<Xso<T>>>,
765}
766
767impl<T: ?Sized> fmt::Debug for XsoVec<T> {
768    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
769        write!(
770            f,
771            "XsoVec[{} types, {} items]",
772            self.inner.len(),
773            self.len()
774        )
775    }
776}
777
778impl<T: ?Sized> Default for XsoVec<T> {
779    fn default() -> Self {
780        Self {
781            inner: BTreeMap::default(),
782        }
783    }
784}
785
786impl<T: DynXso + ?Sized + 'static> XsoVec<T> {
787    /// Construct a new, empty `XsoVec`.
788    ///
789    /// ```
790    #[doc = include_str!("xso_vec_test_prelude.rs")]
791    /// let mut vec = XsoVec::<dyn Trait>::new();
792    /// ```
793    pub const fn new() -> Self {
794        Self {
795            inner: BTreeMap::new(),
796        }
797    }
798
799    /// Return a reference to the first item of type `U`.
800    ///
801    /// If the container does not hold any item of type `U`, return `None`.
802    ///
803    /// ```
804    #[doc = include_str!("xso_vec_test_prelude.rs")]
805    /// #[derive(PartialEq, Debug)]
806    /// struct Foo(u8);
807    /// impl Trait for Foo {}
808    ///
809    /// #[derive(PartialEq, Debug)]
810    /// struct Bar(u16);
811    /// impl Trait for Bar {}
812    ///
813    /// #[derive(PartialEq, Debug)]
814    /// struct Baz(u32);
815    /// impl Trait for Baz {}
816    ///
817    /// let mut vec = XsoVec::<dyn Trait>::new();
818    /// vec.push(Bar(1));
819    /// vec.push(Foo(2));
820    /// vec.push(Foo(1));
821    /// assert_eq!(vec.get_first::<Foo>(), Some(&Foo(2)));
822    /// assert_eq!(vec.get_first::<Bar>(), Some(&Bar(1)));
823    /// assert_eq!(vec.get_first::<Baz>(), None);
824    ///
825    /// ```
826    pub fn get_first<U: 'static>(&self) -> Option<&U>
827    where
828        T: MayContain<U>,
829    {
830        self.iter_typed::<U>().next()
831    }
832
833    /// Return a mutable reference to the first item of type `U`.
834    ///
835    /// If the container does not hold any item of type `U`, return `None`.
836    ///
837    /// ```
838    #[doc = include_str!("xso_vec_test_prelude.rs")]
839    /// #[derive(PartialEq, Debug)]
840    /// struct Foo(u8);
841    /// impl Trait for Foo {}
842    ///
843    /// let mut vec = XsoVec::<dyn Trait>::new();
844    /// vec.push(Foo(1));
845    /// vec.get_first_mut::<Foo>().unwrap().0 = 2;
846    /// assert_eq!(vec.get_first::<Foo>(), Some(&Foo(2)));
847    /// ```
848    pub fn get_first_mut<U: 'static>(&mut self) -> Option<&mut U>
849    where
850        T: MayContain<U>,
851    {
852        self.iter_typed_mut::<U>().next()
853    }
854
855    /// Take and return exactly one item of type `U`.
856    ///
857    /// If no item of type `U` is present in the container, return Ok(None).
858    /// If more than one item of type `U` is present in the container,
859    /// return an error.
860    /// ```
861    #[doc = include_str!("xso_vec_test_prelude.rs")]
862    /// #[derive(PartialEq, Debug)]
863    /// struct Foo(u8);
864    /// impl Trait for Foo {}
865    ///
866    /// #[derive(PartialEq, Debug)]
867    /// struct Bar(u16);
868    /// impl Trait for Bar {}
869    ///
870    /// #[derive(PartialEq, Debug)]
871    /// struct Baz(u32);
872    /// impl Trait for Baz {}
873    ///
874    /// let mut vec = XsoVec::<dyn Trait>::new();
875    /// vec.push(Bar(1));
876    /// vec.push(Foo(2));
877    /// vec.push(Foo(1));
878    /// assert_eq!(vec.take_one::<Foo>(), Err(TakeOneError::MultipleEntries));
879    /// assert_eq!(*vec.take_one::<Bar>().unwrap().unwrap(), Bar(1));
880    /// assert_eq!(vec.take_one::<Bar>(), Ok(None));
881    /// assert_eq!(vec.take_one::<Baz>(), Ok(None));
882    /// ```
883    pub fn take_one<U: 'static>(&mut self) -> Result<Option<Box<U>>, TakeOneError>
884    where
885        T: MayContain<U>,
886    {
887        let source = match self.inner.get_mut(&TypeId::of::<U>()) {
888            Some(v) => v,
889            None => return Ok(None),
890        };
891        if source.len() > 1 {
892            return Err(TakeOneError::MultipleEntries);
893        }
894        Ok(source.pop().map(Xso::force_downcast))
895    }
896
897    /// Take and return the first item of type `U`.
898    ///
899    /// If no item of type `U` is present in the container, return None.
900    /// ```
901    #[doc = include_str!("xso_vec_test_prelude.rs")]
902    /// #[derive(PartialEq, Debug)]
903    /// struct Foo(u8);
904    /// impl Trait for Foo {}
905    ///
906    /// #[derive(PartialEq, Debug)]
907    /// struct Bar(u16);
908    /// impl Trait for Bar {}
909    ///
910    /// #[derive(PartialEq, Debug)]
911    /// struct Baz(u32);
912    /// impl Trait for Baz {}
913    ///
914    /// let mut vec = XsoVec::<dyn Trait>::new();
915    /// vec.push(Bar(1));
916    /// vec.push(Foo(2));
917    /// vec.push(Foo(1));
918    /// assert_eq!(*vec.take_first::<Foo>().unwrap(), Foo(2));
919    /// assert_eq!(*vec.take_first::<Foo>().unwrap(), Foo(1));
920    /// assert_eq!(*vec.take_first::<Bar>().unwrap(), Bar(1));
921    /// assert_eq!(vec.take_first::<Bar>(), None);
922    /// assert_eq!(vec.take_first::<Baz>(), None);
923    /// ```
924    pub fn take_first<U: 'static>(&mut self) -> Option<Box<U>>
925    where
926        T: MayContain<U>,
927    {
928        let source = self.inner.get_mut(&TypeId::of::<U>())?;
929        if source.len() == 0 {
930            return None;
931        }
932        Some(source.remove(0).force_downcast())
933    }
934
935    /// Take and return the last item of type `U`.
936    ///
937    /// If no item of type `U` is present in the container, return None.
938    /// ```
939    #[doc = include_str!("xso_vec_test_prelude.rs")]
940    /// #[derive(PartialEq, Debug)]
941    /// struct Foo(u8);
942    /// impl Trait for Foo {}
943    ///
944    /// #[derive(PartialEq, Debug)]
945    /// struct Bar(u16);
946    /// impl Trait for Bar {}
947    ///
948    /// #[derive(PartialEq, Debug)]
949    /// struct Baz(u32);
950    /// impl Trait for Baz {}
951    ///
952    /// let mut vec = XsoVec::<dyn Trait>::new();
953    /// vec.push(Bar(1));
954    /// vec.push(Foo(2));
955    /// vec.push(Foo(1));
956    /// assert_eq!(*vec.take_last::<Foo>().unwrap(), Foo(1));
957    /// assert_eq!(*vec.take_last::<Foo>().unwrap(), Foo(2));
958    /// assert_eq!(*vec.take_last::<Bar>().unwrap(), Bar(1));
959    /// assert_eq!(vec.take_last::<Bar>(), None);
960    /// assert_eq!(vec.take_last::<Baz>(), None);
961    /// ```
962    pub fn take_last<U: 'static>(&mut self) -> Option<Box<U>>
963    where
964        T: MayContain<U>,
965    {
966        let source = self.inner.get_mut(&TypeId::of::<U>())?;
967        source.pop().map(Xso::force_downcast)
968    }
969
970    /// Iterate all items of type `U` as references.
971    ///
972    /// ```
973    #[doc = include_str!("xso_vec_test_prelude.rs")]
974    /// #[derive(PartialEq, Debug)]
975    /// struct Foo(u8);
976    /// impl Trait for Foo {}
977    ///
978    /// #[derive(PartialEq, Debug)]
979    /// struct Bar(u16);
980    /// impl Trait for Bar {}
981    ///
982    /// #[derive(PartialEq, Debug)]
983    /// struct Baz(u32);
984    /// impl Trait for Baz {}
985    ///
986    /// let mut vec = XsoVec::<dyn Trait>::new();
987    /// vec.push(Bar(1));
988    /// vec.push(Foo(2));
989    /// vec.push(Foo(1));
990    ///
991    /// let foos: Vec<_> = vec.iter_typed::<Foo>().collect();
992    /// assert_eq!(&foos[..], &[&Foo(2), &Foo(1)]);
993    /// ```
994    pub fn iter_typed<U: 'static>(&self) -> impl Iterator<Item = &U>
995    where
996        T: MayContain<U>,
997    {
998        let iter = match self.inner.get(&TypeId::of::<U>()) {
999            Some(v) => v.deref().iter(),
1000            None => [].iter(),
1001        };
1002        // UNWRAP: We group the values by TypeId, so the downcast should never
1003        // fail, but I am too chicken to use the unchecked variants :).
1004        iter.map(|x| x.downcast_ref::<U>().unwrap())
1005    }
1006
1007    /// Iterate all items of type `U` as mutable references.
1008    ///
1009    /// ```
1010    #[doc = include_str!("xso_vec_test_prelude.rs")]
1011    /// #[derive(PartialEq, Debug)]
1012    /// struct Foo(u8);
1013    /// impl Trait for Foo {}
1014    ///
1015    /// #[derive(PartialEq, Debug)]
1016    /// struct Bar(u16);
1017    /// impl Trait for Bar {}
1018    ///
1019    /// #[derive(PartialEq, Debug)]
1020    /// struct Baz(u32);
1021    /// impl Trait for Baz {}
1022    ///
1023    /// let mut vec = XsoVec::<dyn Trait>::new();
1024    /// vec.push(Bar(1));
1025    /// vec.push(Foo(2));
1026    /// vec.push(Foo(1));
1027    ///
1028    /// let foos: Vec<_> = vec.iter_typed_mut::<Foo>().collect();
1029    /// assert_eq!(&foos[..], &[&mut Foo(2), &mut Foo(1)]);
1030    /// ```
1031    pub fn iter_typed_mut<U: 'static>(&mut self) -> impl Iterator<Item = &mut U>
1032    where
1033        T: MayContain<U>,
1034    {
1035        let iter = match self.inner.get_mut(&TypeId::of::<U>()) {
1036            Some(v) => v.deref_mut().iter_mut(),
1037            None => [].iter_mut(),
1038        };
1039        // UNWRAP: We group the values by TypeId, so the downcast should never
1040        // fail, but I am too chicken to use the unchecked variants :).
1041        iter.map(|x| x.downcast_mut::<U>().unwrap())
1042    }
1043
1044    /// Drain all items of type `U` out of the container.
1045    ///
1046    /// If the result is dropped before the end of the iterator has been
1047    /// reached, the remaining items are still dropped out of the container.
1048    ///
1049    /// ```
1050    #[doc = include_str!("xso_vec_test_prelude.rs")]
1051    /// #[derive(PartialEq, Debug)]
1052    /// struct Foo(u8);
1053    /// impl Trait for Foo {}
1054    ///
1055    /// #[derive(PartialEq, Debug)]
1056    /// struct Bar(u16);
1057    /// impl Trait for Bar {}
1058    ///
1059    /// #[derive(PartialEq, Debug)]
1060    /// struct Baz(u32);
1061    /// impl Trait for Baz {}
1062    ///
1063    /// let mut vec = XsoVec::<dyn Trait>::new();
1064    /// vec.push(Bar(1));
1065    /// vec.push(Foo(2));
1066    /// vec.push(Foo(1));
1067    ///
1068    /// let foos: Vec<_> = vec.drain_typed::<Foo>().map(|x| *x).collect();
1069    /// //                             converts Box<T> to T ↑
1070    /// assert_eq!(&foos[..], &[Foo(2), Foo(1)]);
1071    /// ```
1072    pub fn drain_typed<U: 'static>(&mut self) -> impl Iterator<Item = Box<U>>
1073    where
1074        T: MayContain<U>,
1075    {
1076        let iter = match self.inner.remove(&TypeId::of::<U>()) {
1077            Some(v) => v.into_iter(),
1078            None => Vec::new().into_iter(),
1079        };
1080        // UNWRAP: We group the values by TypeId, so the downcast should never
1081        // fail, but I am too chicken to use the unchecked variants :).
1082        iter.map(|x| match x.downcast::<U>() {
1083            Ok(v) => v,
1084            Err(_) => {
1085                unreachable!("TypeId disagrees with Xso<_>::downcast, or internal state corruption")
1086            }
1087        })
1088    }
1089
1090    fn ensure_vec_mut_for(&mut self, type_id: TypeId) -> &mut Vec<Xso<T>> {
1091        match self.inner.entry(type_id) {
1092            Entry::Vacant(v) => v.insert(Vec::new()),
1093            Entry::Occupied(o) => o.into_mut(),
1094        }
1095    }
1096
1097    /// Push a new item of type `U` to the end of the section of `U` inside
1098    /// the container.
1099    ///
1100    /// Please note the information about iteration order of the `XsoVec`
1101    /// at [`XsoVec::iter`][`Self::iter`].
1102    ///
1103    /// ```
1104    #[doc = include_str!("xso_vec_test_prelude.rs")]
1105    /// #[derive(PartialEq, Debug)]
1106    /// struct Foo(u8);
1107    /// impl Trait for Foo {}
1108    ///
1109    /// let mut vec = XsoVec::<dyn Trait>::new();
1110    /// vec.push(Foo(1));
1111    /// ```
1112    pub fn push<U: 'static>(&mut self, value: U)
1113    where
1114        T: MayContain<U>,
1115    {
1116        self.ensure_vec_mut_for(TypeId::of::<U>())
1117            .push(Xso::wrap(value));
1118    }
1119
1120    /// Push a new dynamically typed item to the end of the section of values
1121    /// with the same type inside the container.
1122    ///
1123    /// Please note the information about iteration order of the `XsoVec`
1124    /// at [`XsoVec::iter`][`Self::iter`].
1125    ///
1126    /// ```
1127    /// # use xso::dynxso::Xso;
1128    #[doc = include_str!("xso_vec_test_prelude.rs")]
1129    /// #[derive(PartialEq, Debug)]
1130    /// struct Foo(u8);
1131    /// impl Trait for Foo {}
1132    ///
1133    /// #[derive(PartialEq, Debug)]
1134    /// struct Bar(u8);
1135    /// impl Trait for Bar {}
1136    ///
1137    /// let mut vec = XsoVec::<dyn Trait>::new();
1138    /// vec.push(Foo(1));
1139    /// vec.push_dyn(Xso::wrap(Foo(2)));
1140    /// vec.push_dyn(Xso::wrap(Bar(1)));
1141    /// vec.push(Bar(2));
1142    ///
1143    /// let foos: Vec<_> = vec.iter_typed::<Foo>().collect();
1144    /// assert_eq!(&foos[..], &[&Foo(1), &Foo(2)]);
1145    ///
1146    /// let bars: Vec<_> = vec.iter_typed::<Bar>().collect();
1147    /// assert_eq!(&bars[..], &[&Bar(1), &Bar(2)]);
1148    /// ```
1149    pub fn push_dyn(&mut self, value: Xso<T>) {
1150        self.ensure_vec_mut_for(value.inner_type_id()).push(value);
1151    }
1152}
1153
1154impl<T: ?Sized> XsoVec<T> {
1155    /// Clear all contents, without deallocating memory.
1156    ///
1157    /// ```
1158    #[doc = include_str!("xso_vec_test_prelude.rs")]
1159    /// #[derive(PartialEq, Debug)]
1160    /// struct Foo(u8);
1161    /// impl Trait for Foo {}
1162    ///
1163    /// let mut vec = XsoVec::<dyn Trait>::new();
1164    /// vec.push(Foo(1));
1165    /// vec.push(Foo(2));
1166    /// vec.clear();
1167    /// assert_eq!(vec.len(), 0);
1168    /// ```
1169    pub fn clear(&mut self) {
1170        self.inner.values_mut().for_each(|x| x.clear());
1171    }
1172
1173    /// Return true if there are no items in the container.
1174    ///
1175    /// ```
1176    #[doc = include_str!("xso_vec_test_prelude.rs")]
1177    /// #[derive(PartialEq, Debug)]
1178    /// struct Foo(u8);
1179    /// impl Trait for Foo {}
1180    ///
1181    /// let mut vec = XsoVec::<dyn Trait>::new();
1182    /// assert!(vec.is_empty());
1183    /// vec.push(Foo(1));
1184    /// assert!(!vec.is_empty());
1185    /// ```
1186    pub fn is_empty(&self) -> bool {
1187        self.inner.values().all(|x| x.is_empty())
1188    }
1189
1190    /// Reduce memory use of the container to the minimum required to hold
1191    /// the current data.
1192    ///
1193    /// This may be expensive if lots of data needs to be shuffled.
1194    pub fn shrink_to_fit(&mut self) {
1195        self.inner.retain(|_, x| {
1196            if x.is_empty() {
1197                return false;
1198            }
1199            x.shrink_to_fit();
1200            true
1201        });
1202    }
1203
1204    /// Return the total amount of items in the container.
1205    ///
1206    /// ```
1207    #[doc = include_str!("xso_vec_test_prelude.rs")]
1208    /// #[derive(PartialEq, Debug)]
1209    /// struct Foo(u8);
1210    /// impl Trait for Foo {}
1211    ///
1212    /// let mut vec = XsoVec::<dyn Trait>::new();
1213    /// assert_eq!(vec.len(), 0);
1214    /// vec.push(Foo(1));
1215    /// assert_eq!(vec.len(), 1);
1216    /// ```
1217    pub fn len(&self) -> usize {
1218        self.inner.values().map(|x| x.len()).sum()
1219    }
1220
1221    /// Iterate the items inside the container.
1222    ///
1223    /// This iterator (unlike the iterator returned by
1224    /// [`iter_typed()`][`Self::iter_typed`]) yields references to **untyped**
1225    /// [`Xso<dyn Trait>`][`Xso`].
1226    ///
1227    /// # Iteration order
1228    ///
1229    /// Items which have the same concrete type are grouped and their ordering
1230    /// with respect to one another is preserved. However, the ordering of
1231    /// items with *different* concrete types is unspecified.
1232    ///
1233    /// # Example
1234    ///
1235    /// ```
1236    #[doc = include_str!("xso_vec_test_prelude.rs")]
1237    /// #[derive(PartialEq, Debug)]
1238    /// struct Foo(u8);
1239    /// impl Trait for Foo {}
1240    ///
1241    /// #[derive(PartialEq, Debug)]
1242    /// struct Bar(u16);
1243    /// impl Trait for Bar {}
1244    ///
1245    /// let mut vec = XsoVec::<dyn Trait>::new();
1246    /// vec.push(Foo(1));
1247    /// vec.push(Bar(1));
1248    /// vec.push(Foo(2));
1249    ///
1250    /// for item in vec.iter() {
1251    ///     println!("{:?}", item);
1252    /// }
1253    /// ```
1254    pub fn iter(&self) -> XsoVecIter<'_, T> {
1255        XsoVecIter {
1256            remaining: self.len(),
1257            outer: self.inner.values(),
1258            inner: None,
1259        }
1260    }
1261
1262    /// Iterate the items inside the container, mutably.
1263    ///
1264    /// This iterator (unlike the iterator returned by
1265    /// [`iter_typed_mut()`][`Self::iter_typed_mut`]) yields mutable
1266    /// references to **untyped** [`Xso<dyn Trait>`][`Xso`].
1267    ///
1268    /// Please note the information about iteration order of the `XsoVec`
1269    /// at [`XsoVec::iter`][`Self::iter`].
1270    pub fn iter_mut(&mut self) -> XsoVecIterMut<'_, T> {
1271        XsoVecIterMut {
1272            remaining: self.len(),
1273            outer: self.inner.values_mut(),
1274            inner: None,
1275        }
1276    }
1277}
1278
1279impl<T: ?Sized> IntoIterator for XsoVec<T> {
1280    type Item = Xso<T>;
1281    type IntoIter = XsoVecIntoIter<T>;
1282
1283    fn into_iter(self) -> Self::IntoIter {
1284        XsoVecIntoIter {
1285            remaining: self.len(),
1286            outer: self.inner.into_values(),
1287            inner: None,
1288        }
1289    }
1290}
1291
1292impl<'x, T: ?Sized> IntoIterator for &'x XsoVec<T> {
1293    type Item = &'x Xso<T>;
1294    type IntoIter = XsoVecIter<'x, T>;
1295
1296    fn into_iter(self) -> Self::IntoIter {
1297        self.iter()
1298    }
1299}
1300
1301impl<'x, T: ?Sized> IntoIterator for &'x mut XsoVec<T> {
1302    type Item = &'x mut Xso<T>;
1303    type IntoIter = XsoVecIterMut<'x, T>;
1304
1305    fn into_iter(self) -> Self::IntoIter {
1306        self.iter_mut()
1307    }
1308}
1309
1310impl<T: DynXso + ?Sized + 'static> Extend<Xso<T>> for XsoVec<T> {
1311    fn extend<I: IntoIterator<Item = Xso<T>>>(&mut self, iter: I) {
1312        for item in iter {
1313            self.ensure_vec_mut_for(item.inner_type_id()).push(item);
1314        }
1315    }
1316}
1317
1318/// Helper types for [`XsoVec`].
1319pub mod xso_vec {
1320    use super::*;
1321
1322    /// Iterator over the contents of an [`XsoVec`].
1323    pub struct XsoVecIter<'x, T: ?Sized> {
1324        pub(super) outer: btree_map::Values<'x, TypeId, Vec<Xso<T>>>,
1325        pub(super) inner: Option<slice::Iter<'x, Xso<T>>>,
1326        pub(super) remaining: usize,
1327    }
1328
1329    impl<'x, T: ?Sized> Iterator for XsoVecIter<'x, T> {
1330        type Item = &'x Xso<T>;
1331
1332        fn next(&mut self) -> Option<Self::Item> {
1333            loop {
1334                if let Some(inner) = self.inner.as_mut() {
1335                    if let Some(item) = inner.next() {
1336                        self.remaining = self.remaining.saturating_sub(1);
1337                        return Some(item);
1338                    }
1339                    // Inner is exhausted, so equivalent to None, fall through.
1340                }
1341                // The `?` in there is our exit condition.
1342                self.inner = Some(self.outer.next()?.deref().iter())
1343            }
1344        }
1345
1346        fn size_hint(&self) -> (usize, Option<usize>) {
1347            (self.remaining, Some(self.remaining))
1348        }
1349    }
1350
1351    /// Mutable iterator over the contents of an [`XsoVec`].
1352    pub struct XsoVecIterMut<'x, T: ?Sized> {
1353        pub(super) outer: btree_map::ValuesMut<'x, TypeId, Vec<Xso<T>>>,
1354        pub(super) inner: Option<slice::IterMut<'x, Xso<T>>>,
1355        pub(super) remaining: usize,
1356    }
1357
1358    impl<'x, T: ?Sized> Iterator for XsoVecIterMut<'x, T> {
1359        type Item = &'x mut Xso<T>;
1360
1361        fn next(&mut self) -> Option<Self::Item> {
1362            loop {
1363                if let Some(inner) = self.inner.as_mut() {
1364                    if let Some(item) = inner.next() {
1365                        self.remaining = self.remaining.saturating_sub(1);
1366                        return Some(item);
1367                    }
1368                    // Inner is exhausted, so equivalent to None, fall through.
1369                }
1370                // The `?` in there is our exit condition.
1371                self.inner = Some(self.outer.next()?.deref_mut().iter_mut())
1372            }
1373        }
1374
1375        fn size_hint(&self) -> (usize, Option<usize>) {
1376            (self.remaining, Some(self.remaining))
1377        }
1378    }
1379
1380    /// Iterator over the owned contents of an [`XsoVec`].
1381    pub struct XsoVecIntoIter<T: ?Sized> {
1382        pub(super) outer: btree_map::IntoValues<TypeId, Vec<Xso<T>>>,
1383        pub(super) inner: Option<vec::IntoIter<Xso<T>>>,
1384        pub(super) remaining: usize,
1385    }
1386
1387    impl<T: ?Sized> Iterator for XsoVecIntoIter<T> {
1388        type Item = Xso<T>;
1389
1390        fn next(&mut self) -> Option<Self::Item> {
1391            loop {
1392                if let Some(inner) = self.inner.as_mut() {
1393                    if let Some(item) = inner.next() {
1394                        self.remaining = self.remaining.saturating_sub(1);
1395                        return Some(item);
1396                    }
1397                    // Inner is exhausted, so equivalent to None, fall through.
1398                }
1399                // The `?` in there is our exit condition.
1400                self.inner = Some(self.outer.next()?.into_iter())
1401            }
1402        }
1403
1404        fn size_hint(&self) -> (usize, Option<usize>) {
1405            (self.remaining, Some(self.remaining))
1406        }
1407    }
1408}
1409
1410use xso_vec::*;
1411
1412#[cfg(test)]
1413mod tests {
1414    use super::*;
1415
1416    #[test]
1417    fn xso_inner_type_id_is_correct() {
1418        trait Trait: Any {}
1419        xso_trait!(Trait use () = ());
1420        struct Foo;
1421        impl Trait for Foo {}
1422
1423        let ty_id = TypeId::of::<Foo>();
1424        let x: Xso<dyn Trait> = Xso::wrap(Foo);
1425        assert_eq!(x.inner_type_id(), ty_id);
1426    }
1427}