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 contained in [`Xso<dyn Trait>`][`Xso`], where
11//! `Trait` is a trait provided by the user.
12//!
13//! The given `Trait` constrains the specific types which can be used in the
14//! `Xso<dyn Trait>` box. This allows users to provide additional methods on
15//! the trait which are available on all `Xso<dyn Trait>` objects via the
16//! [`Deref`][`core::ops::Deref`] and [`DerefMut`][`core::ops::DerefMut`]
17//! implementations.
18//!
19//! ## Creating a new `Trait`
20//!
21//! In order to be usable within `Xso<dyn Trait>`, a trait must satisfy the
22//! following constraints:
23//!
24//! - `dyn Trait` must implement [`DynXso`].
25//! - `dyn Trait` must implement [`MayContain<T>`] for all `T` which implement
26//!   `Trait`.
27//!
28//! The easiest and most forward-compatible way of providing these
29//! implementations is the [`derive_dyn_traits`][`crate::derive_dyn_traits`]
30//! macro.
31//!
32//! ## Example
33//!
34#![cfg_attr(
35    not(all(feature = "macros", feature = "std")),
36    doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
37)]
38#![cfg_attr(all(feature = "macros", feature = "std"), doc = "\n```\n")]
39//! # use core::any::Any;
40//! # use xso::{dynxso::{Xso, BuilderRegistry}, FromXml, from_bytes, derive_dyn_traits};
41//! trait MyPayload: Any {}
42//!
43//! derive_dyn_traits!(MyPayload);
44//!
45//! #[derive(FromXml, Debug, PartialEq)]
46//! #[xml(namespace = "urn:example", name = "foo")]
47//! struct Foo;
48//! impl MyPayload for Foo {}
49//! Xso::<dyn MyPayload>::register_type::<Foo>();
50//!
51//! #[derive(FromXml, Debug, PartialEq)]
52//! #[xml(namespace = "urn:example", name = "bar")]
53//! struct Bar;
54//! impl MyPayload for Bar {}
55//! Xso::<dyn MyPayload>::register_type::<Bar>();
56//!
57//! let x: Xso<dyn MyPayload> = from_bytes("<foo xmlns='urn:example'/>".as_bytes()).unwrap();
58//! assert_eq!(Foo, *x.downcast::<Foo>().unwrap());
59//!
60//! let x: Xso<dyn MyPayload> = from_bytes("<bar xmlns='urn:example'/>".as_bytes()).unwrap();
61//! assert_eq!(Bar, *x.downcast::<Bar>().unwrap());
62//! ```
63
64use alloc::{
65    boxed::Box,
66    collections::{
67        btree_map::{self, Entry},
68        BTreeMap,
69    },
70    vec::{self, Vec},
71};
72#[cfg(feature = "std")]
73use core::marker::PhantomData;
74use core::{
75    any::{Any, TypeId},
76    fmt,
77    ops::{Deref, DerefMut},
78    slice,
79};
80#[cfg(feature = "std")]
81use std::sync::Mutex;
82
83#[cfg(feature = "std")]
84use crate::fromxml::XmlNameMatcher;
85use crate::{
86    asxml::AsXmlDyn,
87    error::{Error, FromEventsError},
88    AsXml, Context, FromEventsBuilder, FromXml, Item,
89};
90
91/// # Generate `DynXso` and `MayContain` trait implementations
92///
93/// This macro generates trait [`DynXso`] and [`MayContain`] trait
94/// implementations for a given trait. For more background information on when
95/// that is a useful thing to have, see the [`dynxso`][`crate::dynxso`]
96/// module.
97///
98/// ## Syntax
99///
100/// This macro can be called in two forms:
101///
102/// - `derive_dyn_traits!(Trait)` uses the default [`BuilderRegistry`]
103///    as [`DynXso::Registry`] type and is only available if `xso` is built
104///    with the `"std"` feature.
105/// - `derive_dyn_traits!(Trait use Type = expr)` where `Type` is used as
106///   [`DynXso::Registry`], initialized with `expr`. This form is available
107///   for any set of crate features.
108///
109/// ## Example
110///
111/// When `std` is enabled, the simple syntax can be used.
112#[cfg_attr(
113    not(feature = "std"),
114    doc = "Because the std feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
115)]
116#[cfg_attr(feature = "std", doc = "\n```\n")]
117/// # use core::any::Any;
118/// use xso::derive_dyn_traits;
119/// trait Foo: Any {}
120/// derive_dyn_traits!(Foo);
121/// ```
122///
123/// Note that the trait this macro is called on **must** have a bound on
124/// `Any`, otherwise the generated code will not compile:
125///
126#[cfg_attr(
127    not(feature = "std"),
128    doc = "Because the std feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
129)]
130#[cfg_attr(feature = "std", doc = "\n```compile_fail\n")]
131/// use xso::derive_dyn_traits;
132/// trait Foo {}
133/// derive_dyn_traits!(Foo);
134/// // ↑ will generate a bunch of errors about incompatible types
135/// ```
136///
137/// If the `std` feature is not enabled or if you want to use another
138/// `Registry` for whichever reason, the explicit form can be used:
139///
140/// ```
141/// # use core::any::Any;
142/// use xso::derive_dyn_traits;
143/// trait Foo: Any {}
144/// struct Registry { /* .. */ }
145/// derive_dyn_traits!(Foo use Registry = Registry { /* .. */ });
146/// ```
147///
148/// In that case, you should review the trait requirements of the
149/// [`DynXso::Registry`] associated type.
150#[macro_export]
151macro_rules! derive_dyn_traits {
152    ($trait:ident use $registry:ty = $reginit:expr) => {
153        impl $crate::dynxso::DynXso for dyn $trait {
154            type Registry = $registry;
155
156            fn registry() -> &'static Self::Registry {
157                static DATA: $registry = $reginit;
158                &DATA
159            }
160
161            fn try_downcast<T: 'static>(
162                self: $crate::exports::alloc::boxed::Box<Self>,
163            ) -> Result<
164                $crate::exports::alloc::boxed::Box<T>,
165                $crate::exports::alloc::boxed::Box<Self>,
166            >
167            where
168                Self: $crate::dynxso::MayContain<T>,
169            {
170                if (&*self as &dyn core::any::Any).is::<T>() {
171                    match (self as $crate::exports::alloc::boxed::Box<dyn core::any::Any>)
172                        .downcast()
173                    {
174                        Ok(v) => Ok(v),
175                        Err(_) => unreachable!("Any::is and Any::downcast disagree!"),
176                    }
177                } else {
178                    Err(self)
179                }
180            }
181
182            fn try_downcast_ref<T: 'static>(&self) -> Option<&T>
183            where
184                Self: $crate::dynxso::MayContain<T>,
185            {
186                (&*self as &dyn core::any::Any).downcast_ref()
187            }
188
189            fn try_downcast_mut<T: 'static>(&mut self) -> Option<&mut T>
190            where
191                Self: $crate::dynxso::MayContain<T>,
192            {
193                (&mut *self as &mut dyn core::any::Any).downcast_mut()
194            }
195
196            fn is<T: 'static>(&self) -> bool
197            where
198                Self: $crate::dynxso::MayContain<T>,
199            {
200                (&*self as &dyn core::any::Any).is::<T>()
201            }
202
203            fn type_id(&self) -> core::any::TypeId {
204                (&*self as &dyn core::any::Any).type_id()
205            }
206        }
207
208        impl<T: $trait> $crate::dynxso::MayContain<T> for dyn $trait {
209            fn upcast_into(other: T) -> Box<Self> {
210                Box::new(other)
211            }
212        }
213    };
214    ($trait:ident) => {
215        $crate::_internal_derive_dyn_traits_std_only!($trait);
216    };
217}
218
219#[macro_export]
220#[doc(hidden)]
221#[cfg(feature = "std")]
222macro_rules! _internal_derive_dyn_traits_std_only {
223    ($trait:ident) => {
224        $crate::derive_dyn_traits!($trait use $crate::dynxso::BuilderRegistry<dyn $trait> = $crate::dynxso::BuilderRegistry::new());
225    };
226}
227
228#[macro_export]
229#[doc(hidden)]
230#[cfg(not(feature = "std"))]
231macro_rules! _internal_derive_dyn_traits_std_only {
232    ($trait:ident) => {
233        compile_error!(concat!("derive_dyn_traits!(", stringify!($trait), ") can only be used if the xso crate has been built with the \"std\" feature enabled. Without \"std\", the explicit form of derive_dyn_traits!(", stringify!($trait), " use .. = ..) must be used (see docs)."));
234    };
235}
236
237#[cfg(feature = "std")]
238type BuilderRegistryBuilder<T> = Box<
239    dyn Fn(
240            rxml::QName,
241            rxml::AttrMap,
242            &Context<'_>,
243        ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError>
244        + Send
245        + Sync
246        + 'static,
247>;
248
249#[cfg(feature = "std")]
250struct BuilderRegistryEntry<T: ?Sized> {
251    matcher: XmlNameMatcher<'static>,
252    ty: TypeId,
253    builder: BuilderRegistryBuilder<T>,
254}
255
256#[cfg(feature = "std")]
257impl<T: ?Sized> fmt::Debug for BuilderRegistryEntry<T> {
258    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259        f.debug_struct("BuilderRegistryEntry")
260            .field("matcher", &self.matcher)
261            .field("ty", &self.ty)
262            .finish_non_exhaustive()
263    }
264}
265
266/// # Registry for type-erased [`FromXml`] builders which construct `T`
267///
268/// For general information on builder registries, see [`registry`].
269///
270/// ## Performance trade-offs
271///
272/// The implementation of the `BuilderRegistry` is optimized toward specific
273/// usages. Other usages may see negative performance impacts. The following
274/// assumptions are made:
275///
276/// - Types are added only once at startup and a matching
277///   [`reserve`][`Self::reserve`] call is made beforehands.
278/// - There are many different types.
279/// - [`FromXml::xml_name_matcher`] returns a different value for most of the
280///   types which are added.
281///
282/// The lookup algorithms in particular are geared toward the implications of
283/// the last two assumptions and may be rather inefficient otherwise.
284///
285/// ## Example
286///
287/// This example illustrates the manual usage of the `BuilderRegistry`.
288///
289#[cfg_attr(
290    not(feature = "macros"),
291    doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
292)]
293#[cfg_attr(feature = "macros", doc = "\n```\n")]
294/// # use xso::{dynxso::{BuilderRegistry, MayContain, registry::{DynXsoRegistryAdd, DynXsoRegistryLookup}}, FromXml, from_bytes, exports::rxml::{Namespace, AttrMap, QName, Event, parser::EventMetrics, xml_ncname}, Context, FromEventsBuilder, error::FromEventsError};
295/// #[derive(FromXml, Debug, PartialEq)]
296/// #[xml(namespace = "urn:example", name = "foo")]
297/// struct Foo;
298///
299/// #[derive(FromXml, Debug, PartialEq)]
300/// #[xml(namespace = "urn:example", name = "bar")]
301/// struct Bar;
302///
303/// #[derive(Debug, PartialEq)]
304/// enum Either {
305///    A(Foo),
306///    B(Bar),
307/// }
308///
309/// // BuilderRegistry::add::<U> requires that Either: MayContain<U>, in order
310/// // to be able to wrap the U::Builder such that it outputs a Xso<Either>
311/// // instead.
312/// impl MayContain<Foo> for Either {
313///     fn upcast_into(other: Foo) -> Box<Self> { Box::new(Self::A(other)) }
314/// }
315///
316/// impl MayContain<Bar> for Either {
317///     fn upcast_into(other: Bar) -> Box<Self> { Box::new(Self::B(other)) }
318/// }
319///
320/// let registry = BuilderRegistry::<Either>::new();
321/// registry.add::<Foo>();
322/// registry.add::<Bar>();
323///
324/// let mut builder = registry.make_builder(
325///     (
326///         Namespace::from_str("urn:example"),
327///         xml_ncname!("foo").to_owned(),   // <- Selects the Foo variant
328///     ),
329///     AttrMap::new(),
330///     &Context::empty(),
331/// ).unwrap();
332/// let x = builder.feed(Event::EndElement(EventMetrics::zero()), &Context::empty()).unwrap().unwrap();
333/// assert_eq!(Either::A(Foo), *x);
334///
335/// let mut builder = registry.make_builder(
336///     (
337///         Namespace::from_str("urn:example"),
338///         xml_ncname!("bar").to_owned(),   // <- Selects the Bar variant
339///     ),
340///     AttrMap::new(),
341///     &Context::empty(),
342/// ).unwrap();
343/// let x = builder.feed(Event::EndElement(EventMetrics::zero()), &Context::empty()).unwrap().unwrap();
344/// assert_eq!(Either::B(Bar), *x);
345/// ```
346///
347/// Implementing `FromXml` on the `Either` type in the above example would
348/// be trivial and look like this:
349///
350#[cfg_attr(
351    not(feature = "macros"),
352    doc = "Because the macros feature was not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
353)]
354#[cfg_attr(feature = "macros", doc = "\n```\n")]
355/// # use xso::{dynxso::{BuilderRegistry, MayContain, registry::{DynXsoRegistryAdd, DynXsoRegistryLookup}}, FromXml, from_bytes, exports::rxml::{Namespace, AttrMap, QName, Event, parser::EventMetrics}, Context, FromEventsBuilder, error::FromEventsError};
356/// # #[derive(FromXml, Debug, PartialEq)]
357/// # #[xml(namespace = "urn:example", name = "foo")]
358/// # struct Foo;
359/// #
360/// # #[derive(FromXml, Debug, PartialEq)]
361/// # #[xml(namespace = "urn:example", name = "bar")]
362/// # struct Bar;
363/// #
364/// # #[derive(Debug, PartialEq)]
365/// # enum Either {
366/// #    A(Foo),
367/// #    B(Bar),
368/// # }
369/// #
370/// # impl MayContain<Foo> for Either {
371/// #     fn upcast_into(other: Foo) -> Box<Self> { Box::new(Self::A(other)) }
372/// # }
373/// #
374/// # impl MayContain<Bar> for Either {
375/// #     fn upcast_into(other: Bar) -> Box<Self> { Box::new(Self::B(other)) }
376/// # }
377/// #
378/// // ... code from the previous example ...
379/// use xso::dynxso::UnboxBuilder;
380/// // In order to be able to use the registry from the FromXml implementation,
381/// // it must be a static (as opposed to a local variable as in the previous
382/// // example).
383/// static REGISTRY: BuilderRegistry<Either> = BuilderRegistry::new();
384/// REGISTRY.add::<Foo>();
385/// REGISTRY.add::<Bar>();
386///
387/// impl FromXml for Either {
388///     type Builder = UnboxBuilder<Box<dyn FromEventsBuilder<Output = Box<Either>>>>;
389///
390///     fn from_events(name: QName, attrs: AttrMap, ctx: &Context<'_>) -> Result<Self::Builder, FromEventsError> {
391///         REGISTRY.make_builder(name, attrs, ctx).map(UnboxBuilder::wrap)
392///     }
393/// }
394///
395/// assert_eq!(
396///     Either::A(Foo),
397///     from_bytes("<foo xmlns='urn:example'/>".as_bytes()).unwrap(),
398/// );
399///
400/// assert_eq!(
401///     Either::B(Bar),
402///     from_bytes("<bar xmlns='urn:example'/>".as_bytes()).unwrap(),
403/// );
404/// ```
405#[derive(Debug)]
406#[cfg(feature = "std")]
407pub struct BuilderRegistry<T: ?Sized> {
408    inner: Mutex<Vec<BuilderRegistryEntry<T>>>,
409}
410
411#[cfg(feature = "std")]
412impl<T: ?Sized + 'static> BuilderRegistry<T> {
413    /// Create an empty registry.
414    pub const fn new() -> Self {
415        Self {
416            inner: Mutex::new(Vec::new()),
417        }
418    }
419
420    fn insert(
421        &self,
422        matcher: XmlNameMatcher<'static>,
423        type_id: TypeId,
424        builder: BuilderRegistryBuilder<T>,
425    ) {
426        let mut registry = self.inner.lock().unwrap();
427        let start_scan_at = registry.partition_point(|entry| entry.matcher < matcher);
428        let insert_at = 'outer: {
429            let mut i = start_scan_at;
430            while i < registry.len() {
431                let entry = &registry[i];
432                if entry.matcher == matcher {
433                    if entry.ty == type_id {
434                        // Already inserted.
435                        return;
436                    }
437                    // Still entries with the same matcher -> continue.
438                    i += 1;
439                    continue;
440                }
441
442                // Found insertion point;
443                break 'outer i;
444            }
445
446            // The entire (rest of the) registry contains items matching
447            // `matcher`, but none matching the given `type_id` -> insert at
448            // the end.
449            registry.len()
450        };
451
452        registry.insert(
453            insert_at,
454            BuilderRegistryEntry {
455                matcher,
456                ty: type_id,
457                builder,
458            },
459        );
460    }
461
462    /// Reserve space for at least `n` additional types.
463    pub fn reserve(&self, n: usize) {
464        self.inner.lock().unwrap().reserve(n);
465    }
466
467    fn try_build(
468        inner: &mut Vec<BuilderRegistryEntry<T>>,
469        mut name: rxml::QName,
470        mut attrs: rxml::AttrMap,
471        ctx: &Context<'_>,
472        matcher_builder: impl for<'x> FnOnce(&'x rxml::QName) -> XmlNameMatcher<'x>,
473    ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError> {
474        let matcher = matcher_builder(&name);
475        let start_scan_at = inner.partition_point(|entry| entry.matcher < matcher);
476
477        for entry in &inner[start_scan_at..] {
478            if !entry.matcher.matches(&name) {
479                return Err(FromEventsError::Mismatch { name, attrs });
480            }
481
482            match (entry.builder)(name, attrs, ctx) {
483                Ok(v) => return Ok(v),
484                Err(FromEventsError::Invalid(e)) => return Err(FromEventsError::Invalid(e)),
485                Err(FromEventsError::Mismatch {
486                    name: new_name,
487                    attrs: new_attrs,
488                }) => {
489                    name = new_name;
490                    attrs = new_attrs;
491                }
492            }
493        }
494
495        Err(FromEventsError::Mismatch { name, attrs })
496    }
497}
498
499#[cfg(feature = "std")]
500impl<T: ?Sized + 'static> DynXsoRegistryAdd<T> for BuilderRegistry<T> {
501    fn add<U: Any + FromXml>(&self)
502    where
503        T: MayContain<U>,
504    {
505        struct Wrapper<B, X: ?Sized> {
506            inner: B,
507            output: PhantomData<X>,
508        }
509
510        impl<X: ?Sized, O, B: FromEventsBuilder<Output = O>> FromEventsBuilder for Wrapper<B, X>
511        where
512            X: MayContain<O>,
513        {
514            type Output = Box<X>;
515
516            fn feed(
517                &mut self,
518                ev: rxml::Event,
519                ctx: &Context<'_>,
520            ) -> Result<Option<Self::Output>, Error> {
521                self.inner
522                    .feed(ev, ctx)
523                    .map(|x| x.map(|x| <X as MayContain<O>>::upcast_into(x)))
524            }
525        }
526
527        self.insert(
528            U::xml_name_matcher(),
529            TypeId::of::<U>(),
530            Box::new(|name, attrs, ctx| {
531                U::from_events(name, attrs, ctx).map(|builder| {
532                    Box::new(Wrapper {
533                        inner: builder,
534                        output: PhantomData,
535                    }) as Box<dyn FromEventsBuilder<Output = Box<T>>>
536                })
537            }),
538        )
539    }
540}
541
542#[cfg(feature = "std")]
543impl<T: ?Sized + 'static> DynXsoRegistryLookup<T> for BuilderRegistry<T> {
544    fn make_builder(
545        &self,
546        name: rxml::QName,
547        attrs: rxml::AttrMap,
548        ctx: &Context<'_>,
549    ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError> {
550        let mut inner = self.inner.lock().unwrap();
551        let (name, attrs) = match Self::try_build(&mut *inner, name, attrs, ctx, |qname| {
552            XmlNameMatcher::Specific(qname.0.as_str(), qname.1.as_str())
553        }) {
554            Ok(v) => return Ok(v),
555            Err(FromEventsError::Invalid(e)) => return Err(FromEventsError::Invalid(e)),
556            Err(FromEventsError::Mismatch { name, attrs }) => (name, attrs),
557        };
558
559        let (name, attrs) = match Self::try_build(&mut *inner, name, attrs, ctx, |qname| {
560            XmlNameMatcher::InNamespace(qname.0.as_str())
561        }) {
562            Ok(v) => return Ok(v),
563            Err(FromEventsError::Invalid(e)) => return Err(FromEventsError::Invalid(e)),
564            Err(FromEventsError::Mismatch { name, attrs }) => (name, attrs),
565        };
566
567        Self::try_build(&mut *inner, name, attrs, ctx, |_| XmlNameMatcher::Any)
568    }
569}
570
571/// # Helper traits for dynamic XSO builder registries.
572///
573/// Builder registries hold type-erased [`FromXml::from_events`]
574/// implementations. Registries can be used to dynamically dispatch to a set
575/// of `FromXml` implementations which is not known at compile time.
576///
577/// Under the hood, they are used by the `FromXml` implementation on
578/// [`Xso<T>`][`Xso`], via the [`DynXso::Registry`] type.
579///
580/// Note that registries generally do not allow to add arbitrary builders. All
581/// builders must originate in a [`FromXml`] implementation and their output
582/// must be convertible to the specific type the registry is defined for.
583///
584/// The default implementation is [`BuilderRegistry`], which is only available
585/// if `xso` is built with the `"std"` feature due to the inherent need for a
586/// `Mutex`.
587pub mod registry {
588    use super::*;
589
590    /// Trait for a builder registry supports constructing elements.
591    pub trait DynXsoRegistryLookup<T: ?Sized> {
592        /// Make a builder for the given element header.
593        ///
594        /// This tries all applicable `FromXml` implementations which have
595        /// previously been added via [`add`][`DynXsoRegistryAdd::add`] in
596        /// unspecified order. The first implementation to either fail or
597        /// succeed at constructing a builder determines the result.
598        /// Implementations which return a
599        /// [`FromEventsError::Mismatch`][`crate::error::FromEventsError::Mismatch`]
600        /// are ignored.
601        ///
602        /// If all applicable implementations return `Mismatch`, this function
603        /// returns `Mismatch`, too.
604        fn make_builder(
605            &self,
606            name: rxml::QName,
607            attrs: rxml::AttrMap,
608            ctx: &Context<'_>,
609        ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError>;
610    }
611
612    /// Trait for a builder registry supports registering new builders at
613    /// runtime.
614    pub trait DynXsoRegistryAdd<T: ?Sized> {
615        /// Add a new builder to the registry.
616        ///
617        /// This allows to add any `FromXml` implementation whose output can be
618        /// converted to `T`.
619        fn add<U: Any + FromXml>(&self)
620        where
621            T: MayContain<U>;
622    }
623}
624
625use registry::*;
626
627/// # Dynamic XSO type
628///
629/// This trait provides the infrastructure for dynamic XSO types. In
630/// particular, it provides:
631///
632/// - Access to a [`BuilderRegistry`] which allows constructing an instance of
633///   the dynamic XSO type from XML.
634/// - Downcasts to specific types.
635///
636/// Like [`MayContain`], it is typically implemented on `dyn Trait` for some
637/// `Trait` and it is best generated using
638/// [`derive_dyn_traits`][`crate::derive_dyn_traits`].
639///
640/// This trait explicitly provides the methods provided by [`Any`]. The reason
641/// for this duplication is that with `DynXso` being intended to be
642/// implemented on `dyn Trait`, code using this trait cannot cast the value
643/// to `dyn Any` to access the `downcast`-related methods (`type_id` would,
644/// in fact, work if `DynXso` had a bound on `Any`, but not the downcasts).
645///
646/// *Hint*: It should not be necessary for user code to directly interact
647/// with this trait.
648pub trait DynXso: 'static {
649    /// Builder registry type for this dynamic type.
650    ///
651    /// The `Registry` type *should* implement the following traits:
652    ///
653    /// - [`DynXsoRegistryAdd`] is required to make
654    ///   [`Xso::<Self>::register_type()`][`Xso::register_type`] available.
655    /// - [`DynXsoRegistryLookup`] is required to make [`FromXml`] available
656    ///   on [`Xso<Self>`][`Xso`] (and, by extension, on
657    ///   [`XsoVec<Self>`][`XsoVec`]).
658    ///
659    /// However, any type with static lifetime can be used, even without the
660    /// trait implementations above, if the limitations are acceptable.
661    type Registry: 'static;
662
663    /// Return the builder registry for this dynamic type.
664    ///
665    /// See [`Registry`][`Self::Registry`] for details.
666    fn registry() -> &'static Self::Registry;
667
668    /// Try to downcast a boxed dynamic XSO to a specific type.
669    ///
670    /// If `self` contains a `T` (and thus, the downcast succeeds), `Ok(_)`
671    /// is returned. Otherwise, `Err(self)` is returned, allowing to chain
672    /// this function with other downcast attempts.
673    ///
674    /// This is similar to `downcast` on [`dyn Any`][`core::any::Any`].
675    fn try_downcast<T: 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>>
676    where
677        Self: MayContain<T>;
678
679    /// Try to downcast a dynamic XSO to a reference to a specific type.
680    ///
681    /// If `self` contains a `T` (and thus, the downcast succeeds), `Some(_)`
682    /// is returned. Otherwise, `None`.
683    ///
684    /// This is similar to `downcast_ref` on [`dyn Any`][`core::any::Any`].
685    fn try_downcast_ref<T: 'static>(&self) -> Option<&T>
686    where
687        Self: MayContain<T>;
688
689    /// Try to downcast a dynamic XSO to a mutable reference to a specific
690    /// type.
691    ///
692    /// If `self` contains a `T` (and thus, the downcast succeeds), `Some(_)`
693    /// is returned. Otherwise, `None`.
694    ///
695    /// This is similar to `downcast_mut` on [`dyn Any`][`core::any::Any`].
696    fn try_downcast_mut<T: 'static>(&mut self) -> Option<&mut T>
697    where
698        Self: MayContain<T>;
699
700    /// Return true if `self` contains a `T`.
701    ///
702    /// This is similar to `is` on [`dyn Any`][`core::any::Any`].
703    fn is<T: 'static>(&self) -> bool
704    where
705        Self: MayContain<T>;
706
707    /// Return the [`TypeId`] of `self`.
708    ///
709    /// This is similar to `type_id` on [`dyn Any`][`core::any::Any`].
710    fn type_id(&self) -> TypeId;
711}
712
713/// # Declare that `T` may be held by `Box<Self>`
714///
715/// This trait is used to constrain which types can be put in
716/// [`Xso<Self>`][`Xso`]. It is typically implemented on `dyn Trait` for all
717/// `T: Trait`.
718///
719/// To automatically generate suitable implementations of this trait, see
720/// [`derive_dyn_traits`][`crate::derive_dyn_traits`].
721///
722/// Implementation-wise, this trait is very similar to `Box<Self>: From<T>`.
723/// However, `From` is also used in many different circumstances and it cannot
724/// be suitably overloaded on `Box<_>`, so a new trait was introduced for this
725/// particular purpose.
726pub trait MayContain<T> {
727    /// Convert a value of `T` into `Box<Self>`.
728    fn upcast_into(other: T) -> Box<Self>;
729}
730
731/// # Dynamic XSO container
732///
733/// This container is very similar to `Box<_>`, but geared specifically toward
734/// the use with `T` being a `dyn Trait`. It also implements [`FromXml`]
735/// (unconditionally) and [`AsXml`] if `T` implements [`AsXmlDyn`].
736///
737/// In order to provide these features, `T` must implement [`DynXso`] and
738/// [`MayContain`]. Implementations for these traits can be generated using
739/// [`derive_dyn_traits`][`crate::derive_dyn_traits`].
740///
741/// Most methods on `Xso<dyn Trait>` which take type parameters are only
742/// available for types `U` implementing `Trait` (or, more precisely, where
743/// `dyn Trait` implements `MayContain<U>`).
744#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
745#[repr(transparent)]
746pub struct Xso<T: ?Sized> {
747    inner: Box<T>,
748}
749
750impl<T: ?Sized> Deref for Xso<T> {
751    type Target = T;
752
753    fn deref(&self) -> &Self::Target {
754        self.inner.deref()
755    }
756}
757
758impl<T: ?Sized> DerefMut for Xso<T> {
759    fn deref_mut(&mut self) -> &mut Self::Target {
760        self.inner.deref_mut()
761    }
762}
763
764impl<T: DynXso + ?Sized> fmt::Debug for Xso<T> {
765    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
766        f.debug_struct("Xso")
767            .field("inner", &self.inner_type_id())
768            .finish()
769    }
770}
771
772impl<T: ?Sized> Xso<T> {
773    /// Wrap a value into a `Xso<dyn Trait>`.
774    ///
775    /// ```
776    /// # use core::any::Any;
777    /// # use xso::{dynxso::Xso, derive_dyn_traits};
778    /// trait Trait: Any {}
779    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
780    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
781    ///
782    /// struct Foo;
783    /// impl Trait for Foo {}
784    ///
785    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
786    /// ```
787    pub fn wrap<U: 'static>(value: U) -> Self
788    where
789        T: MayContain<U>,
790    {
791        Self {
792            inner: T::upcast_into(value),
793        }
794    }
795
796    /// Convert `Xso<T>` into `Box<T>`.
797    ///
798    /// ```
799    /// # use core::any::Any;
800    /// # use xso::{dynxso::Xso, derive_dyn_traits};
801    /// trait Trait: Any {}
802    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
803    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
804    ///
805    /// struct Foo;
806    /// impl Trait for Foo {}
807    ///
808    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
809    /// let x: Box<dyn Trait> = x.into_boxed();
810    /// ```
811    pub fn into_boxed(self) -> Box<T> {
812        self.inner
813    }
814}
815
816impl<T: DynXso + ?Sized + 'static> Xso<T> {
817    /// Downcast `self` to `Box<U>`.
818    ///
819    /// If the downcast fails, `self` is returned without change.
820    ///
821    /// ```
822    /// # use core::any::Any;
823    /// # use xso::{dynxso::Xso, derive_dyn_traits};
824    /// trait Trait: Any {}
825    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
826    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
827    ///
828    /// struct Foo;
829    /// impl Trait for Foo {}
830    ///
831    /// struct Bar;
832    /// impl Trait for Bar {}
833    ///
834    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
835    /// // Does not contain a Bar, so downcast fails.
836    /// let x: Xso<dyn Trait> = x.downcast::<Bar>().err().unwrap();
837    /// // *Does* contain a Foo, so downcast succeeds.
838    /// let f: Foo = *x.downcast().unwrap();
839    /// ```
840    pub fn downcast<U: 'static>(self) -> Result<Box<U>, Self>
841    where
842        T: MayContain<U>,
843    {
844        match self.inner.try_downcast() {
845            Ok(v) => Ok(v),
846            Err(inner) => Err(Self { inner }),
847        }
848    }
849
850    fn force_downcast<U: 'static>(self) -> Box<U>
851    where
852        T: MayContain<U>,
853    {
854        match self.downcast::<U>() {
855            Ok(v) => v,
856            Err(v) => panic!(
857                "force_downcast called on mismatching types: requested {:?} ({}) != actual {:?}",
858                TypeId::of::<U>(),
859                core::any::type_name::<U>(),
860                v.inner_type_id()
861            ),
862        }
863    }
864
865    /// Downcast `&self` to `&U`.
866    ///
867    /// ```
868    /// # use core::any::Any;
869    /// # use xso::{dynxso::Xso, derive_dyn_traits};
870    /// trait Trait: Any {}
871    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
872    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
873    ///
874    /// struct Foo;
875    /// impl Trait for Foo {}
876    ///
877    /// struct Bar;
878    /// impl Trait for Bar {}
879    ///
880    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
881    /// // Does not contain a Bar, so downcast fails.
882    /// assert!(x.downcast_ref::<Bar>().is_none());
883    /// // *Does* contain a Foo, so downcast succeeds.
884    /// let f: &Foo = x.downcast_ref().unwrap();
885    /// ```
886    pub fn downcast_ref<U: 'static>(&self) -> Option<&U>
887    where
888        T: MayContain<U>,
889    {
890        self.inner.try_downcast_ref()
891    }
892
893    /// Downcast `&mut self` to `&mut U`.
894    ///
895    /// ```
896    /// # use core::any::Any;
897    /// # use xso::{dynxso::Xso, derive_dyn_traits};
898    /// trait Trait: Any {}
899    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
900    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
901    ///
902    /// struct Foo;
903    /// impl Trait for Foo {}
904    ///
905    /// struct Bar;
906    /// impl Trait for Bar {}
907    ///
908    /// let mut x: Xso<dyn Trait> = Xso::wrap(Foo);
909    /// // Does not contain a Bar, so downcast fails.
910    /// assert!(x.downcast_mut::<Bar>().is_none());
911    /// // *Does* contain a Foo, so downcast succeeds.
912    /// let f: &mut Foo = x.downcast_mut().unwrap();
913    /// ```
914    pub fn downcast_mut<U: 'static>(&mut self) -> Option<&mut U>
915    where
916        T: MayContain<U>,
917    {
918        self.inner.try_downcast_mut()
919    }
920
921    fn inner_type_id(&self) -> TypeId {
922        DynXso::type_id(&*self.inner)
923    }
924}
925
926impl<R: DynXsoRegistryAdd<T> + 'static, T: DynXso<Registry = R> + ?Sized + 'static> Xso<T> {
927    /// Register a new type to be constructible.
928    ///
929    /// Only types registered through this function can be parsed from XML via
930    /// the [`FromXml`] implementation on `Xso<T>`. See
931    /// [`dynxso`][`crate::dynxso`] for details.
932    ///
933    #[cfg_attr(
934        not(all(feature = "macros", feature = "std")),
935        doc = "Because the macros and std features were not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
936    )]
937    #[cfg_attr(all(feature = "macros", feature = "std"), doc = "\n```\n")]
938    /// # use core::any::Any;
939    /// # use xso::{dynxso::Xso, derive_dyn_traits, from_bytes, FromXml};
940    /// trait Trait: Any {}
941    /// derive_dyn_traits!(Trait);
942    ///
943    /// #[derive(FromXml, PartialEq, Debug)]
944    /// #[xml(namespace = "urn:example", name = "foo")]
945    /// struct Foo;
946    /// impl Trait for Foo {}
947    ///
948    /// // Parsing fails, because register_type() has not been called for
949    /// // Foo:
950    /// assert!(from_bytes::<Xso<dyn Trait>>("<foo xmlns='urn:example'/>".as_bytes()).is_err());
951    ///
952    /// Xso::<dyn Trait>::register_type::<Foo>();
953    /// // After registering Foo with Xso<dyn Trait>, parsing succeeds and
954    /// // we can downcast to Foo:
955    /// let x: Xso<dyn Trait> = from_bytes("<foo xmlns='urn:example'/>".as_bytes()).unwrap();
956    /// assert_eq!(Foo, *x.downcast().unwrap());
957    /// ```
958    pub fn register_type<U: FromXml + 'static>()
959    where
960        T: MayContain<U>,
961    {
962        T::registry().add::<U>()
963    }
964}
965
966/// Wrapper around a `FromEventsBuilder` to convert a `Box<T>` output to a
967/// `Xso<T>` output.
968///
969/// Not constructible by users, only for internal use.
970pub struct DynBuilder<B> {
971    inner: B,
972}
973
974impl<T: DynXso + ?Sized + 'static, B: FromEventsBuilder<Output = Box<T>>> FromEventsBuilder
975    for DynBuilder<B>
976{
977    type Output = Xso<T>;
978
979    fn feed(&mut self, ev: rxml::Event, ctx: &Context) -> Result<Option<Self::Output>, Error> {
980        self.inner
981            .feed(ev, ctx)
982            .map(|x| x.map(|inner| Xso { inner }))
983    }
984}
985
986/// Wrapper around a `FromEventsBuilder` to convert a `Box<T>` output to a
987/// `T` output.
988pub struct UnboxBuilder<T> {
989    inner: T,
990}
991
992impl<O, T: FromEventsBuilder<Output = Box<O>>> UnboxBuilder<T> {
993    /// Wrap a `FromEventsBuilder` which generates `Box<O>`.
994    pub fn wrap(inner: T) -> Self {
995        Self { inner }
996    }
997}
998
999impl<O, T: FromEventsBuilder<Output = Box<O>>> FromEventsBuilder for UnboxBuilder<T> {
1000    type Output = O;
1001
1002    fn feed(&mut self, ev: rxml::Event, ctx: &Context) -> Result<Option<Self::Output>, Error> {
1003        self.inner.feed(ev, ctx).map(|x| x.map(|inner| *inner))
1004    }
1005}
1006
1007impl<R: DynXsoRegistryLookup<T> + 'static, T: DynXso<Registry = R> + ?Sized + 'static> FromXml
1008    for Xso<T>
1009{
1010    type Builder = DynBuilder<Box<dyn FromEventsBuilder<Output = Box<T>>>>;
1011
1012    fn from_events(
1013        name: rxml::QName,
1014        attrs: rxml::AttrMap,
1015        ctx: &Context<'_>,
1016    ) -> Result<Self::Builder, FromEventsError> {
1017        T::registry()
1018            .make_builder(name, attrs, ctx)
1019            .map(|inner| DynBuilder { inner })
1020    }
1021}
1022
1023impl<T: DynXso + AsXmlDyn + ?Sized + 'static> AsXml for Xso<T> {
1024    type ItemIter<'x> = Box<dyn Iterator<Item = Result<Item<'x>, Error>> + 'x>;
1025
1026    fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
1027        self.inner.as_xml_dyn_iter()
1028    }
1029
1030    fn as_xml_dyn_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
1031        self.inner.as_xml_dyn_iter()
1032    }
1033}
1034
1035/// Error type for retrieving a single item from `XsoVec`.
1036#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1037pub enum TakeOneError {
1038    /// More than one item was found.
1039    MultipleEntries,
1040}
1041
1042impl fmt::Display for TakeOneError {
1043    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1044        match self {
1045            Self::MultipleEntries => f.write_str("multiple entries found"),
1046        }
1047    }
1048}
1049
1050/// # Container for dynamically-typed XSOs optimized for type-keyed access
1051///
1052/// This container holds dynamically typed XSOs (see
1053/// [`Xso<dyn Trait>`][`Xso`]). It allows efficient access to its contents
1054/// based on the actual type.
1055///
1056/// Like `Xso<dyn Trait>` itself, `XsoVec<dyn Trait>` requires that
1057/// `MayContain` is implemented by `dyn Trait` for all items which are added
1058/// to the container. This is automatically the case for all `T: Trait`
1059/// if [`derive_dyn_traits`][`crate::derive_dyn_traits`] has been used on
1060/// `Trait`.
1061///
1062/// Note that `XsoVec` has a non-obvious iteration order, which is described
1063/// in [`XsoVec::iter()`][`Self::iter`].
1064pub struct XsoVec<T: ?Sized> {
1065    inner: BTreeMap<TypeId, Vec<Xso<T>>>,
1066}
1067
1068impl<T: ?Sized> fmt::Debug for XsoVec<T> {
1069    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1070        write!(
1071            f,
1072            "XsoVec[{} types, {} items]",
1073            self.inner.len(),
1074            self.len()
1075        )
1076    }
1077}
1078
1079impl<T: ?Sized> Default for XsoVec<T> {
1080    fn default() -> Self {
1081        Self {
1082            inner: BTreeMap::default(),
1083        }
1084    }
1085}
1086
1087impl<T: DynXso + ?Sized + 'static> XsoVec<T> {
1088    /// Construct a new, empty `XsoVec`.
1089    ///
1090    /// ```
1091    #[doc = include_str!("xso_vec_test_prelude.rs")]
1092    /// let mut vec = XsoVec::<dyn Trait>::new();
1093    /// ```
1094    pub const fn new() -> Self {
1095        Self {
1096            inner: BTreeMap::new(),
1097        }
1098    }
1099
1100    /// Return a reference to the first item of type `U`.
1101    ///
1102    /// If the container does not hold any item of type `U`, return `None`.
1103    ///
1104    /// ```
1105    #[doc = include_str!("xso_vec_test_prelude.rs")]
1106    /// #[derive(PartialEq, Debug)]
1107    /// struct Foo(u8);
1108    /// impl Trait for Foo {}
1109    ///
1110    /// #[derive(PartialEq, Debug)]
1111    /// struct Bar(u16);
1112    /// impl Trait for Bar {}
1113    ///
1114    /// #[derive(PartialEq, Debug)]
1115    /// struct Baz(u32);
1116    /// impl Trait for Baz {}
1117    ///
1118    /// let mut vec = XsoVec::<dyn Trait>::new();
1119    /// vec.push(Bar(1));
1120    /// vec.push(Foo(2));
1121    /// vec.push(Foo(1));
1122    /// assert_eq!(vec.get_first::<Foo>(), Some(&Foo(2)));
1123    /// assert_eq!(vec.get_first::<Bar>(), Some(&Bar(1)));
1124    /// assert_eq!(vec.get_first::<Baz>(), None);
1125    ///
1126    /// ```
1127    pub fn get_first<U: 'static>(&self) -> Option<&U>
1128    where
1129        T: MayContain<U>,
1130    {
1131        self.iter_typed::<U>().next()
1132    }
1133
1134    /// Return a mutable reference to the first item of type `U`.
1135    ///
1136    /// If the container does not hold any item of type `U`, return `None`.
1137    ///
1138    /// ```
1139    #[doc = include_str!("xso_vec_test_prelude.rs")]
1140    /// #[derive(PartialEq, Debug)]
1141    /// struct Foo(u8);
1142    /// impl Trait for Foo {}
1143    ///
1144    /// let mut vec = XsoVec::<dyn Trait>::new();
1145    /// vec.push(Foo(1));
1146    /// vec.get_first_mut::<Foo>().unwrap().0 = 2;
1147    /// assert_eq!(vec.get_first::<Foo>(), Some(&Foo(2)));
1148    /// ```
1149    pub fn get_first_mut<U: 'static>(&mut self) -> Option<&mut U>
1150    where
1151        T: MayContain<U>,
1152    {
1153        self.iter_typed_mut::<U>().next()
1154    }
1155
1156    /// Take and return exactly one item of type `U`.
1157    ///
1158    /// If no item of type `U` is present in the container, return Ok(None).
1159    /// If more than one item of type `U` is present in the container,
1160    /// return an error.
1161    /// ```
1162    #[doc = include_str!("xso_vec_test_prelude.rs")]
1163    /// #[derive(PartialEq, Debug)]
1164    /// struct Foo(u8);
1165    /// impl Trait for Foo {}
1166    ///
1167    /// #[derive(PartialEq, Debug)]
1168    /// struct Bar(u16);
1169    /// impl Trait for Bar {}
1170    ///
1171    /// #[derive(PartialEq, Debug)]
1172    /// struct Baz(u32);
1173    /// impl Trait for Baz {}
1174    ///
1175    /// let mut vec = XsoVec::<dyn Trait>::new();
1176    /// vec.push(Bar(1));
1177    /// vec.push(Foo(2));
1178    /// vec.push(Foo(1));
1179    /// assert_eq!(vec.take_one::<Foo>(), Err(TakeOneError::MultipleEntries));
1180    /// assert_eq!(*vec.take_one::<Bar>().unwrap().unwrap(), Bar(1));
1181    /// assert_eq!(vec.take_one::<Bar>(), Ok(None));
1182    /// assert_eq!(vec.take_one::<Baz>(), Ok(None));
1183    /// ```
1184    pub fn take_one<U: 'static>(&mut self) -> Result<Option<Box<U>>, TakeOneError>
1185    where
1186        T: MayContain<U>,
1187    {
1188        let source = match self.inner.get_mut(&TypeId::of::<U>()) {
1189            Some(v) => v,
1190            None => return Ok(None),
1191        };
1192        if source.len() > 1 {
1193            return Err(TakeOneError::MultipleEntries);
1194        }
1195        Ok(source.pop().map(Xso::force_downcast))
1196    }
1197
1198    /// Take and return the first item of type `U`.
1199    ///
1200    /// If no item of type `U` is present in the container, return None.
1201    /// ```
1202    #[doc = include_str!("xso_vec_test_prelude.rs")]
1203    /// #[derive(PartialEq, Debug)]
1204    /// struct Foo(u8);
1205    /// impl Trait for Foo {}
1206    ///
1207    /// #[derive(PartialEq, Debug)]
1208    /// struct Bar(u16);
1209    /// impl Trait for Bar {}
1210    ///
1211    /// #[derive(PartialEq, Debug)]
1212    /// struct Baz(u32);
1213    /// impl Trait for Baz {}
1214    ///
1215    /// let mut vec = XsoVec::<dyn Trait>::new();
1216    /// vec.push(Bar(1));
1217    /// vec.push(Foo(2));
1218    /// vec.push(Foo(1));
1219    /// assert_eq!(*vec.take_first::<Foo>().unwrap(), Foo(2));
1220    /// assert_eq!(*vec.take_first::<Foo>().unwrap(), Foo(1));
1221    /// assert_eq!(*vec.take_first::<Bar>().unwrap(), Bar(1));
1222    /// assert_eq!(vec.take_first::<Bar>(), None);
1223    /// assert_eq!(vec.take_first::<Baz>(), None);
1224    /// ```
1225    pub fn take_first<U: 'static>(&mut self) -> Option<Box<U>>
1226    where
1227        T: MayContain<U>,
1228    {
1229        let source = self.inner.get_mut(&TypeId::of::<U>())?;
1230        if source.len() == 0 {
1231            return None;
1232        }
1233        Some(source.remove(0).force_downcast())
1234    }
1235
1236    /// Take and return the last item of type `U`.
1237    ///
1238    /// If no item of type `U` is present in the container, return None.
1239    /// ```
1240    #[doc = include_str!("xso_vec_test_prelude.rs")]
1241    /// #[derive(PartialEq, Debug)]
1242    /// struct Foo(u8);
1243    /// impl Trait for Foo {}
1244    ///
1245    /// #[derive(PartialEq, Debug)]
1246    /// struct Bar(u16);
1247    /// impl Trait for Bar {}
1248    ///
1249    /// #[derive(PartialEq, Debug)]
1250    /// struct Baz(u32);
1251    /// impl Trait for Baz {}
1252    ///
1253    /// let mut vec = XsoVec::<dyn Trait>::new();
1254    /// vec.push(Bar(1));
1255    /// vec.push(Foo(2));
1256    /// vec.push(Foo(1));
1257    /// assert_eq!(*vec.take_last::<Foo>().unwrap(), Foo(1));
1258    /// assert_eq!(*vec.take_last::<Foo>().unwrap(), Foo(2));
1259    /// assert_eq!(*vec.take_last::<Bar>().unwrap(), Bar(1));
1260    /// assert_eq!(vec.take_last::<Bar>(), None);
1261    /// assert_eq!(vec.take_last::<Baz>(), None);
1262    /// ```
1263    pub fn take_last<U: 'static>(&mut self) -> Option<Box<U>>
1264    where
1265        T: MayContain<U>,
1266    {
1267        let source = self.inner.get_mut(&TypeId::of::<U>())?;
1268        source.pop().map(Xso::force_downcast)
1269    }
1270
1271    /// Iterate all items of type `U` as references.
1272    ///
1273    /// ```
1274    #[doc = include_str!("xso_vec_test_prelude.rs")]
1275    /// #[derive(PartialEq, Debug)]
1276    /// struct Foo(u8);
1277    /// impl Trait for Foo {}
1278    ///
1279    /// #[derive(PartialEq, Debug)]
1280    /// struct Bar(u16);
1281    /// impl Trait for Bar {}
1282    ///
1283    /// #[derive(PartialEq, Debug)]
1284    /// struct Baz(u32);
1285    /// impl Trait for Baz {}
1286    ///
1287    /// let mut vec = XsoVec::<dyn Trait>::new();
1288    /// vec.push(Bar(1));
1289    /// vec.push(Foo(2));
1290    /// vec.push(Foo(1));
1291    ///
1292    /// let foos: Vec<_> = vec.iter_typed::<Foo>().collect();
1293    /// assert_eq!(&foos[..], &[&Foo(2), &Foo(1)]);
1294    /// ```
1295    pub fn iter_typed<U: 'static>(&self) -> impl Iterator<Item = &U>
1296    where
1297        T: MayContain<U>,
1298    {
1299        let iter = match self.inner.get(&TypeId::of::<U>()) {
1300            Some(v) => v.deref().iter(),
1301            None => (&[]).iter(),
1302        };
1303        // UNWRAP: We group the values by TypeId, so the downcast should never
1304        // fail, but I am too chicken to use the unchecked variants :).
1305        iter.map(|x| x.downcast_ref::<U>().unwrap())
1306    }
1307
1308    /// Iterate all items of type `U` as mutable references.
1309    ///
1310    /// ```
1311    #[doc = include_str!("xso_vec_test_prelude.rs")]
1312    /// #[derive(PartialEq, Debug)]
1313    /// struct Foo(u8);
1314    /// impl Trait for Foo {}
1315    ///
1316    /// #[derive(PartialEq, Debug)]
1317    /// struct Bar(u16);
1318    /// impl Trait for Bar {}
1319    ///
1320    /// #[derive(PartialEq, Debug)]
1321    /// struct Baz(u32);
1322    /// impl Trait for Baz {}
1323    ///
1324    /// let mut vec = XsoVec::<dyn Trait>::new();
1325    /// vec.push(Bar(1));
1326    /// vec.push(Foo(2));
1327    /// vec.push(Foo(1));
1328    ///
1329    /// let foos: Vec<_> = vec.iter_typed_mut::<Foo>().collect();
1330    /// assert_eq!(&foos[..], &[&mut Foo(2), &mut Foo(1)]);
1331    /// ```
1332    pub fn iter_typed_mut<U: 'static>(&mut self) -> impl Iterator<Item = &mut U>
1333    where
1334        T: MayContain<U>,
1335    {
1336        let iter = match self.inner.get_mut(&TypeId::of::<U>()) {
1337            Some(v) => v.deref_mut().iter_mut(),
1338            None => (&mut []).iter_mut(),
1339        };
1340        // UNWRAP: We group the values by TypeId, so the downcast should never
1341        // fail, but I am too chicken to use the unchecked variants :).
1342        iter.map(|x| x.downcast_mut::<U>().unwrap())
1343    }
1344
1345    /// Drain all items of type `U` out of the container.
1346    ///
1347    /// If the result is dropped before the end of the iterator has been
1348    /// reached, the remaining items are still dropped out of the container.
1349    ///
1350    /// ```
1351    #[doc = include_str!("xso_vec_test_prelude.rs")]
1352    /// #[derive(PartialEq, Debug)]
1353    /// struct Foo(u8);
1354    /// impl Trait for Foo {}
1355    ///
1356    /// #[derive(PartialEq, Debug)]
1357    /// struct Bar(u16);
1358    /// impl Trait for Bar {}
1359    ///
1360    /// #[derive(PartialEq, Debug)]
1361    /// struct Baz(u32);
1362    /// impl Trait for Baz {}
1363    ///
1364    /// let mut vec = XsoVec::<dyn Trait>::new();
1365    /// vec.push(Bar(1));
1366    /// vec.push(Foo(2));
1367    /// vec.push(Foo(1));
1368    ///
1369    /// let foos: Vec<_> = vec.drain_typed::<Foo>().map(|x| *x).collect();
1370    /// //                             converts Box<T> to T ↑
1371    /// assert_eq!(&foos[..], &[Foo(2), Foo(1)]);
1372    /// ```
1373    pub fn drain_typed<U: 'static>(&mut self) -> impl Iterator<Item = Box<U>>
1374    where
1375        T: MayContain<U>,
1376    {
1377        let iter = match self.inner.remove(&TypeId::of::<U>()) {
1378            Some(v) => v.into_iter(),
1379            None => Vec::new().into_iter(),
1380        };
1381        // UNWRAP: We group the values by TypeId, so the downcast should never
1382        // fail, but I am too chicken to use the unchecked variants :).
1383        iter.map(|x| match x.downcast::<U>() {
1384            Ok(v) => v,
1385            Err(_) => {
1386                unreachable!("TypeId disagrees with Xso<_>::downcast, or internal state corruption")
1387            }
1388        })
1389    }
1390
1391    fn ensure_vec_mut_for(&mut self, type_id: TypeId) -> &mut Vec<Xso<T>> {
1392        match self.inner.entry(type_id) {
1393            Entry::Vacant(v) => v.insert(Vec::new()),
1394            Entry::Occupied(o) => o.into_mut(),
1395        }
1396    }
1397
1398    /// Push a new item of type `U` to the end of the section of `U` inside
1399    /// the container.
1400    ///
1401    /// Please note the information about iteration order of the `XsoVec`
1402    /// at [`XsoVec::iter`][`Self::iter`].
1403    ///
1404    /// ```
1405    #[doc = include_str!("xso_vec_test_prelude.rs")]
1406    /// #[derive(PartialEq, Debug)]
1407    /// struct Foo(u8);
1408    /// impl Trait for Foo {}
1409    ///
1410    /// let mut vec = XsoVec::<dyn Trait>::new();
1411    /// vec.push(Foo(1));
1412    /// ```
1413    pub fn push<U: 'static>(&mut self, value: U)
1414    where
1415        T: MayContain<U>,
1416    {
1417        self.ensure_vec_mut_for(TypeId::of::<U>())
1418            .push(Xso::wrap(value));
1419    }
1420
1421    /// Push a new dynamically typed item to the end of the section of values
1422    /// with the same type inside the container.
1423    ///
1424    /// Please note the information about iteration order of the `XsoVec`
1425    /// at [`XsoVec::iter`][`Self::iter`].
1426    ///
1427    /// ```
1428    /// # use xso::dynxso::Xso;
1429    #[doc = include_str!("xso_vec_test_prelude.rs")]
1430    /// #[derive(PartialEq, Debug)]
1431    /// struct Foo(u8);
1432    /// impl Trait for Foo {}
1433    ///
1434    /// #[derive(PartialEq, Debug)]
1435    /// struct Bar(u8);
1436    /// impl Trait for Bar {}
1437    ///
1438    /// let mut vec = XsoVec::<dyn Trait>::new();
1439    /// vec.push(Foo(1));
1440    /// vec.push_dyn(Xso::wrap(Foo(2)));
1441    /// vec.push_dyn(Xso::wrap(Bar(1)));
1442    /// vec.push(Bar(2));
1443    ///
1444    /// let foos: Vec<_> = vec.iter_typed::<Foo>().collect();
1445    /// assert_eq!(&foos[..], &[&Foo(1), &Foo(2)]);
1446    ///
1447    /// let bars: Vec<_> = vec.iter_typed::<Bar>().collect();
1448    /// assert_eq!(&bars[..], &[&Bar(1), &Bar(2)]);
1449    /// ```
1450    pub fn push_dyn(&mut self, value: Xso<T>) {
1451        self.ensure_vec_mut_for(value.inner_type_id()).push(value);
1452    }
1453}
1454
1455impl<T: ?Sized> XsoVec<T> {
1456    /// Clear all contents, without deallocating memory.
1457    ///
1458    /// ```
1459    #[doc = include_str!("xso_vec_test_prelude.rs")]
1460    /// #[derive(PartialEq, Debug)]
1461    /// struct Foo(u8);
1462    /// impl Trait for Foo {}
1463    ///
1464    /// let mut vec = XsoVec::<dyn Trait>::new();
1465    /// vec.push(Foo(1));
1466    /// vec.push(Foo(2));
1467    /// vec.clear();
1468    /// assert_eq!(vec.len(), 0);
1469    /// ```
1470    pub fn clear(&mut self) {
1471        self.inner.values_mut().for_each(|x| x.clear());
1472    }
1473
1474    /// Return true if there are no items in the container.
1475    ///
1476    /// ```
1477    #[doc = include_str!("xso_vec_test_prelude.rs")]
1478    /// #[derive(PartialEq, Debug)]
1479    /// struct Foo(u8);
1480    /// impl Trait for Foo {}
1481    ///
1482    /// let mut vec = XsoVec::<dyn Trait>::new();
1483    /// assert!(vec.is_empty());
1484    /// vec.push(Foo(1));
1485    /// assert!(!vec.is_empty());
1486    /// ```
1487    pub fn is_empty(&self) -> bool {
1488        self.inner.values().all(|x| x.is_empty())
1489    }
1490
1491    /// Reduce memory use of the container to the minimum required to hold
1492    /// the current data.
1493    ///
1494    /// This may be expensive if lots of data needs to be shuffled.
1495    pub fn shrink_to_fit(&mut self) {
1496        self.inner.retain(|_, x| {
1497            if x.is_empty() {
1498                return false;
1499            }
1500            x.shrink_to_fit();
1501            true
1502        });
1503    }
1504
1505    /// Return the total amount of items in the container.
1506    ///
1507    /// ```
1508    #[doc = include_str!("xso_vec_test_prelude.rs")]
1509    /// #[derive(PartialEq, Debug)]
1510    /// struct Foo(u8);
1511    /// impl Trait for Foo {}
1512    ///
1513    /// let mut vec = XsoVec::<dyn Trait>::new();
1514    /// assert_eq!(vec.len(), 0);
1515    /// vec.push(Foo(1));
1516    /// assert_eq!(vec.len(), 1);
1517    /// ```
1518    pub fn len(&self) -> usize {
1519        self.inner.values().map(|x| x.len()).sum()
1520    }
1521
1522    /// Iterate the items inside the container.
1523    ///
1524    /// This iterator (unlike the iterator returned by
1525    /// [`iter_typed()`][`Self::iter_typed`]) yields references to **untyped**
1526    /// [`Xso<dyn Trait>`][`Xso`].
1527    ///
1528    /// # Iteration order
1529    ///
1530    /// Items which have the same concrete type are grouped and their ordering
1531    /// with respect to one another is preserved. However, the ordering of
1532    /// items with *different* concrete types is unspecified.
1533    ///
1534    /// # Example
1535    ///
1536    /// ```
1537    #[doc = include_str!("xso_vec_test_prelude.rs")]
1538    /// #[derive(PartialEq, Debug)]
1539    /// struct Foo(u8);
1540    /// impl Trait for Foo {}
1541    ///
1542    /// #[derive(PartialEq, Debug)]
1543    /// struct Bar(u16);
1544    /// impl Trait for Bar {}
1545    ///
1546    /// let mut vec = XsoVec::<dyn Trait>::new();
1547    /// vec.push(Foo(1));
1548    /// vec.push(Bar(1));
1549    /// vec.push(Foo(2));
1550    ///
1551    /// for item in vec.iter() {
1552    ///     println!("{:?}", item);
1553    /// }
1554    /// ```
1555    pub fn iter(&self) -> XsoVecIter<'_, T> {
1556        XsoVecIter {
1557            remaining: self.len(),
1558            outer: self.inner.values(),
1559            inner: None,
1560        }
1561    }
1562
1563    /// Iterate the items inside the container, mutably.
1564    ///
1565    /// This iterator (unlike the iterator returned by
1566    /// [`iter_typed_mut()`][`Self::iter_typed_mut`]) yields mutable
1567    /// references to **untyped** [`Xso<dyn Trait>`][`Xso`].
1568    ///
1569    /// Please note the information about iteration order of the `XsoVec`
1570    /// at [`XsoVec::iter`][`Self::iter`].
1571    pub fn iter_mut(&mut self) -> XsoVecIterMut<'_, T> {
1572        XsoVecIterMut {
1573            remaining: self.len(),
1574            outer: self.inner.values_mut(),
1575            inner: None,
1576        }
1577    }
1578}
1579
1580impl<T: ?Sized> IntoIterator for XsoVec<T> {
1581    type Item = Xso<T>;
1582    type IntoIter = XsoVecIntoIter<T>;
1583
1584    fn into_iter(self) -> Self::IntoIter {
1585        XsoVecIntoIter {
1586            remaining: self.len(),
1587            outer: self.inner.into_values(),
1588            inner: None,
1589        }
1590    }
1591}
1592
1593impl<'x, T: ?Sized> IntoIterator for &'x XsoVec<T> {
1594    type Item = &'x Xso<T>;
1595    type IntoIter = XsoVecIter<'x, T>;
1596
1597    fn into_iter(self) -> Self::IntoIter {
1598        self.iter()
1599    }
1600}
1601
1602impl<'x, T: ?Sized> IntoIterator for &'x mut XsoVec<T> {
1603    type Item = &'x mut Xso<T>;
1604    type IntoIter = XsoVecIterMut<'x, T>;
1605
1606    fn into_iter(self) -> Self::IntoIter {
1607        self.iter_mut()
1608    }
1609}
1610
1611impl<T: DynXso + ?Sized + 'static> Extend<Xso<T>> for XsoVec<T> {
1612    fn extend<I: IntoIterator<Item = Xso<T>>>(&mut self, iter: I) {
1613        for item in iter {
1614            self.ensure_vec_mut_for(item.inner_type_id()).push(item);
1615        }
1616    }
1617}
1618
1619/// Helper types for [`XsoVec`].
1620pub mod xso_vec {
1621    use super::*;
1622
1623    /// Iterator over the contents of an [`XsoVec`].
1624    pub struct XsoVecIter<'x, T: ?Sized> {
1625        pub(super) outer: btree_map::Values<'x, TypeId, Vec<Xso<T>>>,
1626        pub(super) inner: Option<slice::Iter<'x, Xso<T>>>,
1627        pub(super) remaining: usize,
1628    }
1629
1630    impl<'x, T: ?Sized> Iterator for XsoVecIter<'x, T> {
1631        type Item = &'x Xso<T>;
1632
1633        fn next(&mut self) -> Option<Self::Item> {
1634            loop {
1635                if let Some(inner) = self.inner.as_mut() {
1636                    if let Some(item) = inner.next() {
1637                        self.remaining = self.remaining.saturating_sub(1);
1638                        return Some(item);
1639                    }
1640                    // Inner is exhausted, so equivalent to None, fall through.
1641                }
1642                // The `?` in there is our exit condition.
1643                self.inner = Some(self.outer.next()?.deref().iter())
1644            }
1645        }
1646
1647        fn size_hint(&self) -> (usize, Option<usize>) {
1648            (self.remaining, Some(self.remaining))
1649        }
1650    }
1651
1652    /// Mutable iterator over the contents of an [`XsoVec`].
1653    pub struct XsoVecIterMut<'x, T: ?Sized> {
1654        pub(super) outer: btree_map::ValuesMut<'x, TypeId, Vec<Xso<T>>>,
1655        pub(super) inner: Option<slice::IterMut<'x, Xso<T>>>,
1656        pub(super) remaining: usize,
1657    }
1658
1659    impl<'x, T: ?Sized> Iterator for XsoVecIterMut<'x, T> {
1660        type Item = &'x mut Xso<T>;
1661
1662        fn next(&mut self) -> Option<Self::Item> {
1663            loop {
1664                if let Some(inner) = self.inner.as_mut() {
1665                    if let Some(item) = inner.next() {
1666                        self.remaining = self.remaining.saturating_sub(1);
1667                        return Some(item);
1668                    }
1669                    // Inner is exhausted, so equivalent to None, fall through.
1670                }
1671                // The `?` in there is our exit condition.
1672                self.inner = Some(self.outer.next()?.deref_mut().iter_mut())
1673            }
1674        }
1675
1676        fn size_hint(&self) -> (usize, Option<usize>) {
1677            (self.remaining, Some(self.remaining))
1678        }
1679    }
1680
1681    /// Iterator over the owned contents of an [`XsoVec`].
1682    pub struct XsoVecIntoIter<T: ?Sized> {
1683        pub(super) outer: btree_map::IntoValues<TypeId, Vec<Xso<T>>>,
1684        pub(super) inner: Option<vec::IntoIter<Xso<T>>>,
1685        pub(super) remaining: usize,
1686    }
1687
1688    impl<T: ?Sized> Iterator for XsoVecIntoIter<T> {
1689        type Item = Xso<T>;
1690
1691        fn next(&mut self) -> Option<Self::Item> {
1692            loop {
1693                if let Some(inner) = self.inner.as_mut() {
1694                    if let Some(item) = inner.next() {
1695                        self.remaining = self.remaining.saturating_sub(1);
1696                        return Some(item);
1697                    }
1698                    // Inner is exhausted, so equivalent to None, fall through.
1699                }
1700                // The `?` in there is our exit condition.
1701                self.inner = Some(self.outer.next()?.into_iter())
1702            }
1703        }
1704
1705        fn size_hint(&self) -> (usize, Option<usize>) {
1706            (self.remaining, Some(self.remaining))
1707        }
1708    }
1709}
1710
1711use xso_vec::*;
1712
1713#[cfg(test)]
1714mod tests {
1715    use super::*;
1716
1717    #[test]
1718    fn xso_inner_type_id_is_correct() {
1719        trait Trait: Any {}
1720        crate::derive_dyn_traits!(Trait use () = ());
1721        struct Foo;
1722        impl Trait for Foo {}
1723
1724        let ty_id = TypeId::of::<Foo>();
1725        let x: Xso<dyn Trait> = Xso::wrap(Foo);
1726        assert_eq!(x.inner_type_id(), ty_id);
1727    }
1728}