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> Default for BuilderRegistry<T> {
413    fn default() -> Self {
414        Self::new()
415    }
416}
417
418#[cfg(feature = "std")]
419impl<T: ?Sized + 'static> BuilderRegistry<T> {
420    /// Create an empty registry.
421    pub const fn new() -> Self {
422        Self {
423            inner: Mutex::new(Vec::new()),
424        }
425    }
426
427    fn insert(
428        &self,
429        matcher: XmlNameMatcher<'static>,
430        type_id: TypeId,
431        builder: BuilderRegistryBuilder<T>,
432    ) {
433        let mut registry = self.inner.lock().unwrap();
434        let start_scan_at = registry.partition_point(|entry| entry.matcher < matcher);
435        let insert_at = 'outer: {
436            let mut i = start_scan_at;
437            while i < registry.len() {
438                let entry = &registry[i];
439                if entry.matcher == matcher {
440                    if entry.ty == type_id {
441                        // Already inserted.
442                        return;
443                    }
444                    // Still entries with the same matcher -> continue.
445                    i += 1;
446                    continue;
447                }
448
449                // Found insertion point;
450                break 'outer i;
451            }
452
453            // The entire (rest of the) registry contains items matching
454            // `matcher`, but none matching the given `type_id` -> insert at
455            // the end.
456            registry.len()
457        };
458
459        registry.insert(
460            insert_at,
461            BuilderRegistryEntry {
462                matcher,
463                ty: type_id,
464                builder,
465            },
466        );
467    }
468
469    /// Reserve space for at least `n` additional types.
470    pub fn reserve(&self, n: usize) {
471        self.inner.lock().unwrap().reserve(n);
472    }
473
474    fn try_build(
475        inner: &mut [BuilderRegistryEntry<T>],
476        mut name: rxml::QName,
477        mut attrs: rxml::AttrMap,
478        ctx: &Context<'_>,
479        matcher_builder: impl for<'x> FnOnce(&'x rxml::QName) -> XmlNameMatcher<'x>,
480    ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError> {
481        let matcher = matcher_builder(&name);
482        let start_scan_at = inner.partition_point(|entry| entry.matcher < matcher);
483
484        for entry in &inner[start_scan_at..] {
485            if !entry.matcher.matches(&name) {
486                return Err(FromEventsError::Mismatch { name, attrs });
487            }
488
489            match (entry.builder)(name, attrs, ctx) {
490                Ok(v) => return Ok(v),
491                Err(FromEventsError::Invalid(e)) => return Err(FromEventsError::Invalid(e)),
492                Err(FromEventsError::Mismatch {
493                    name: new_name,
494                    attrs: new_attrs,
495                }) => {
496                    name = new_name;
497                    attrs = new_attrs;
498                }
499            }
500        }
501
502        Err(FromEventsError::Mismatch { name, attrs })
503    }
504}
505
506#[cfg(feature = "std")]
507impl<T: ?Sized + 'static> DynXsoRegistryAdd<T> for BuilderRegistry<T> {
508    fn add<U: Any + FromXml>(&self)
509    where
510        T: MayContain<U>,
511    {
512        struct Wrapper<B, X: ?Sized> {
513            inner: B,
514            output: PhantomData<X>,
515        }
516
517        impl<X: ?Sized, O, B: FromEventsBuilder<Output = O>> FromEventsBuilder for Wrapper<B, X>
518        where
519            X: MayContain<O>,
520        {
521            type Output = Box<X>;
522
523            fn feed(
524                &mut self,
525                ev: rxml::Event,
526                ctx: &Context<'_>,
527            ) -> Result<Option<Self::Output>, Error> {
528                self.inner
529                    .feed(ev, ctx)
530                    .map(|x| x.map(|x| <X as MayContain<O>>::upcast_into(x)))
531            }
532        }
533
534        self.insert(
535            U::xml_name_matcher(),
536            TypeId::of::<U>(),
537            Box::new(|name, attrs, ctx| {
538                U::from_events(name, attrs, ctx).map(|builder| {
539                    Box::new(Wrapper {
540                        inner: builder,
541                        output: PhantomData,
542                    }) as Box<dyn FromEventsBuilder<Output = Box<T>>>
543                })
544            }),
545        )
546    }
547}
548
549#[cfg(feature = "std")]
550impl<T: ?Sized + 'static> DynXsoRegistryLookup<T> for BuilderRegistry<T> {
551    fn make_builder(
552        &self,
553        name: rxml::QName,
554        attrs: rxml::AttrMap,
555        ctx: &Context<'_>,
556    ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError> {
557        let mut inner = self.inner.lock().unwrap();
558        let (name, attrs) = match Self::try_build(&mut inner, name, attrs, ctx, |qname| {
559            XmlNameMatcher::Specific(qname.0.as_str(), qname.1.as_str())
560        }) {
561            Ok(v) => return Ok(v),
562            Err(FromEventsError::Invalid(e)) => return Err(FromEventsError::Invalid(e)),
563            Err(FromEventsError::Mismatch { name, attrs }) => (name, attrs),
564        };
565
566        let (name, attrs) = match Self::try_build(&mut inner, name, attrs, ctx, |qname| {
567            XmlNameMatcher::InNamespace(qname.0.as_str())
568        }) {
569            Ok(v) => return Ok(v),
570            Err(FromEventsError::Invalid(e)) => return Err(FromEventsError::Invalid(e)),
571            Err(FromEventsError::Mismatch { name, attrs }) => (name, attrs),
572        };
573
574        Self::try_build(&mut inner, name, attrs, ctx, |_| XmlNameMatcher::Any)
575    }
576}
577
578/// # Helper traits for dynamic XSO builder registries.
579///
580/// Builder registries hold type-erased [`FromXml::from_events`]
581/// implementations. Registries can be used to dynamically dispatch to a set
582/// of `FromXml` implementations which is not known at compile time.
583///
584/// Under the hood, they are used by the `FromXml` implementation on
585/// [`Xso<T>`][`Xso`], via the [`DynXso::Registry`] type.
586///
587/// Note that registries generally do not allow to add arbitrary builders. All
588/// builders must originate in a [`FromXml`] implementation and their output
589/// must be convertible to the specific type the registry is defined for.
590///
591/// The default implementation is [`BuilderRegistry`], which is only available
592/// if `xso` is built with the `"std"` feature due to the inherent need for a
593/// `Mutex`.
594pub mod registry {
595    use super::*;
596
597    /// Trait for a builder registry supports constructing elements.
598    pub trait DynXsoRegistryLookup<T: ?Sized> {
599        /// Make a builder for the given element header.
600        ///
601        /// This tries all applicable `FromXml` implementations which have
602        /// previously been added via [`add`][`DynXsoRegistryAdd::add`] in
603        /// unspecified order. The first implementation to either fail or
604        /// succeed at constructing a builder determines the result.
605        /// Implementations which return a
606        /// [`FromEventsError::Mismatch`][`crate::error::FromEventsError::Mismatch`]
607        /// are ignored.
608        ///
609        /// If all applicable implementations return `Mismatch`, this function
610        /// returns `Mismatch`, too.
611        fn make_builder(
612            &self,
613            name: rxml::QName,
614            attrs: rxml::AttrMap,
615            ctx: &Context<'_>,
616        ) -> Result<Box<dyn FromEventsBuilder<Output = Box<T>>>, FromEventsError>;
617    }
618
619    /// Trait for a builder registry supports registering new builders at
620    /// runtime.
621    pub trait DynXsoRegistryAdd<T: ?Sized> {
622        /// Add a new builder to the registry.
623        ///
624        /// This allows to add any `FromXml` implementation whose output can be
625        /// converted to `T`.
626        fn add<U: Any + FromXml>(&self)
627        where
628            T: MayContain<U>;
629    }
630}
631
632use registry::*;
633
634/// # Dynamic XSO type
635///
636/// This trait provides the infrastructure for dynamic XSO types. In
637/// particular, it provides:
638///
639/// - Access to a [`BuilderRegistry`] which allows constructing an instance of
640///   the dynamic XSO type from XML.
641/// - Downcasts to specific types.
642///
643/// Like [`MayContain`], it is typically implemented on `dyn Trait` for some
644/// `Trait` and it is best generated using
645/// [`derive_dyn_traits`][`crate::derive_dyn_traits`].
646///
647/// This trait explicitly provides the methods provided by [`Any`]. The reason
648/// for this duplication is that with `DynXso` being intended to be
649/// implemented on `dyn Trait`, code using this trait cannot cast the value
650/// to `dyn Any` to access the `downcast`-related methods (`type_id` would,
651/// in fact, work if `DynXso` had a bound on `Any`, but not the downcasts).
652///
653/// *Hint*: It should not be necessary for user code to directly interact
654/// with this trait.
655pub trait DynXso: 'static {
656    /// Builder registry type for this dynamic type.
657    ///
658    /// The `Registry` type *should* implement the following traits:
659    ///
660    /// - [`DynXsoRegistryAdd`] is required to make
661    ///   [`Xso::<Self>::register_type()`][`Xso::register_type`] available.
662    /// - [`DynXsoRegistryLookup`] is required to make [`FromXml`] available
663    ///   on [`Xso<Self>`][`Xso`] (and, by extension, on
664    ///   [`XsoVec<Self>`][`XsoVec`]).
665    ///
666    /// However, any type with static lifetime can be used, even without the
667    /// trait implementations above, if the limitations are acceptable.
668    type Registry: 'static;
669
670    /// Return the builder registry for this dynamic type.
671    ///
672    /// See [`Registry`][`Self::Registry`] for details.
673    fn registry() -> &'static Self::Registry;
674
675    /// Try to downcast a boxed dynamic XSO to a specific type.
676    ///
677    /// If `self` contains a `T` (and thus, the downcast succeeds), `Ok(_)`
678    /// is returned. Otherwise, `Err(self)` is returned, allowing to chain
679    /// this function with other downcast attempts.
680    ///
681    /// This is similar to `downcast` on [`dyn Any`][`core::any::Any`].
682    fn try_downcast<T: 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>>
683    where
684        Self: MayContain<T>;
685
686    /// Try to downcast a dynamic XSO to a reference to a specific type.
687    ///
688    /// If `self` contains a `T` (and thus, the downcast succeeds), `Some(_)`
689    /// is returned. Otherwise, `None`.
690    ///
691    /// This is similar to `downcast_ref` on [`dyn Any`][`core::any::Any`].
692    fn try_downcast_ref<T: 'static>(&self) -> Option<&T>
693    where
694        Self: MayContain<T>;
695
696    /// Try to downcast a dynamic XSO to a mutable reference to a specific
697    /// type.
698    ///
699    /// If `self` contains a `T` (and thus, the downcast succeeds), `Some(_)`
700    /// is returned. Otherwise, `None`.
701    ///
702    /// This is similar to `downcast_mut` on [`dyn Any`][`core::any::Any`].
703    fn try_downcast_mut<T: 'static>(&mut self) -> Option<&mut T>
704    where
705        Self: MayContain<T>;
706
707    /// Return true if `self` contains a `T`.
708    ///
709    /// This is similar to `is` on [`dyn Any`][`core::any::Any`].
710    fn is<T: 'static>(&self) -> bool
711    where
712        Self: MayContain<T>;
713
714    /// Return the [`TypeId`] of `self`.
715    ///
716    /// This is similar to `type_id` on [`dyn Any`][`core::any::Any`].
717    fn type_id(&self) -> TypeId;
718}
719
720/// # Declare that `T` may be held by `Box<Self>`
721///
722/// This trait is used to constrain which types can be put in
723/// [`Xso<Self>`][`Xso`]. It is typically implemented on `dyn Trait` for all
724/// `T: Trait`.
725///
726/// To automatically generate suitable implementations of this trait, see
727/// [`derive_dyn_traits`][`crate::derive_dyn_traits`].
728///
729/// Implementation-wise, this trait is very similar to `Box<Self>: From<T>`.
730/// However, `From` is also used in many different circumstances and it cannot
731/// be suitably overloaded on `Box<_>`, so a new trait was introduced for this
732/// particular purpose.
733pub trait MayContain<T> {
734    /// Convert a value of `T` into `Box<Self>`.
735    fn upcast_into(other: T) -> Box<Self>;
736}
737
738/// # Dynamic XSO container
739///
740/// This container is very similar to `Box<_>`, but geared specifically toward
741/// the use with `T` being a `dyn Trait`. It also implements [`FromXml`]
742/// (unconditionally) and [`AsXml`] if `T` implements [`AsXmlDyn`].
743///
744/// In order to provide these features, `T` must implement [`DynXso`] and
745/// [`MayContain`]. Implementations for these traits can be generated using
746/// [`derive_dyn_traits`][`crate::derive_dyn_traits`].
747///
748/// Most methods on `Xso<dyn Trait>` which take type parameters are only
749/// available for types `U` implementing `Trait` (or, more precisely, where
750/// `dyn Trait` implements `MayContain<U>`).
751#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
752#[repr(transparent)]
753pub struct Xso<T: ?Sized> {
754    inner: Box<T>,
755}
756
757impl<T: ?Sized> Deref for Xso<T> {
758    type Target = T;
759
760    fn deref(&self) -> &Self::Target {
761        self.inner.deref()
762    }
763}
764
765impl<T: ?Sized> DerefMut for Xso<T> {
766    fn deref_mut(&mut self) -> &mut Self::Target {
767        self.inner.deref_mut()
768    }
769}
770
771impl<T: DynXso + ?Sized> fmt::Debug for Xso<T> {
772    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
773        f.debug_struct("Xso")
774            .field("inner", &self.inner_type_id())
775            .finish()
776    }
777}
778
779impl<T: ?Sized> Xso<T> {
780    /// Wrap a value into a `Xso<dyn Trait>`.
781    ///
782    /// ```
783    /// # use core::any::Any;
784    /// # use xso::{dynxso::Xso, derive_dyn_traits};
785    /// trait Trait: Any {}
786    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
787    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
788    ///
789    /// struct Foo;
790    /// impl Trait for Foo {}
791    ///
792    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
793    /// ```
794    pub fn wrap<U: 'static>(value: U) -> Self
795    where
796        T: MayContain<U>,
797    {
798        Self {
799            inner: T::upcast_into(value),
800        }
801    }
802
803    /// Convert `Xso<T>` into `Box<T>`.
804    ///
805    /// ```
806    /// # use core::any::Any;
807    /// # use xso::{dynxso::Xso, derive_dyn_traits};
808    /// trait Trait: Any {}
809    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
810    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
811    ///
812    /// struct Foo;
813    /// impl Trait for Foo {}
814    ///
815    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
816    /// let x: Box<dyn Trait> = x.into_boxed();
817    /// ```
818    pub fn into_boxed(self) -> Box<T> {
819        self.inner
820    }
821}
822
823impl<T: DynXso + ?Sized + 'static> Xso<T> {
824    /// Downcast `self` to `Box<U>`.
825    ///
826    /// If the downcast fails, `self` is returned without change.
827    ///
828    /// ```
829    /// # use core::any::Any;
830    /// # use xso::{dynxso::Xso, derive_dyn_traits};
831    /// trait Trait: Any {}
832    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
833    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
834    ///
835    /// struct Foo;
836    /// impl Trait for Foo {}
837    ///
838    /// struct Bar;
839    /// impl Trait for Bar {}
840    ///
841    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
842    /// // Does not contain a Bar, so downcast fails.
843    /// let x: Xso<dyn Trait> = x.downcast::<Bar>().err().unwrap();
844    /// // *Does* contain a Foo, so downcast succeeds.
845    /// let f: Foo = *x.downcast().unwrap();
846    /// ```
847    pub fn downcast<U: 'static>(self) -> Result<Box<U>, Self>
848    where
849        T: MayContain<U>,
850    {
851        match self.inner.try_downcast() {
852            Ok(v) => Ok(v),
853            Err(inner) => Err(Self { inner }),
854        }
855    }
856
857    fn force_downcast<U: 'static>(self) -> Box<U>
858    where
859        T: MayContain<U>,
860    {
861        match self.downcast::<U>() {
862            Ok(v) => v,
863            Err(v) => panic!(
864                "force_downcast called on mismatching types: requested {:?} ({}) != actual {:?}",
865                TypeId::of::<U>(),
866                core::any::type_name::<U>(),
867                v.inner_type_id()
868            ),
869        }
870    }
871
872    /// Downcast `&self` to `&U`.
873    ///
874    /// ```
875    /// # use core::any::Any;
876    /// # use xso::{dynxso::Xso, derive_dyn_traits};
877    /// trait Trait: Any {}
878    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
879    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
880    ///
881    /// struct Foo;
882    /// impl Trait for Foo {}
883    ///
884    /// struct Bar;
885    /// impl Trait for Bar {}
886    ///
887    /// let x: Xso<dyn Trait> = Xso::wrap(Foo);
888    /// // Does not contain a Bar, so downcast fails.
889    /// assert!(x.downcast_ref::<Bar>().is_none());
890    /// // *Does* contain a Foo, so downcast succeeds.
891    /// let f: &Foo = x.downcast_ref().unwrap();
892    /// ```
893    pub fn downcast_ref<U: 'static>(&self) -> Option<&U>
894    where
895        T: MayContain<U>,
896    {
897        self.inner.try_downcast_ref()
898    }
899
900    /// Downcast `&mut self` to `&mut U`.
901    ///
902    /// ```
903    /// # use core::any::Any;
904    /// # use xso::{dynxso::Xso, derive_dyn_traits};
905    /// trait Trait: Any {}
906    #[cfg_attr(feature = "std", doc = "derive_dyn_traits!(Trait);")]
907    #[cfg_attr(not(feature = "std"), doc = "derive_dyn_traits!(Trait use () = ());")]
908    ///
909    /// struct Foo;
910    /// impl Trait for Foo {}
911    ///
912    /// struct Bar;
913    /// impl Trait for Bar {}
914    ///
915    /// let mut x: Xso<dyn Trait> = Xso::wrap(Foo);
916    /// // Does not contain a Bar, so downcast fails.
917    /// assert!(x.downcast_mut::<Bar>().is_none());
918    /// // *Does* contain a Foo, so downcast succeeds.
919    /// let f: &mut Foo = x.downcast_mut().unwrap();
920    /// ```
921    pub fn downcast_mut<U: 'static>(&mut self) -> Option<&mut U>
922    where
923        T: MayContain<U>,
924    {
925        self.inner.try_downcast_mut()
926    }
927
928    fn inner_type_id(&self) -> TypeId {
929        DynXso::type_id(&*self.inner)
930    }
931}
932
933impl<R: DynXsoRegistryAdd<T> + 'static, T: DynXso<Registry = R> + ?Sized + 'static> Xso<T> {
934    /// Register a new type to be constructible.
935    ///
936    /// Only types registered through this function can be parsed from XML via
937    /// the [`FromXml`] implementation on `Xso<T>`. See
938    /// [`dynxso`][`crate::dynxso`] for details.
939    ///
940    #[cfg_attr(
941        not(all(feature = "macros", feature = "std")),
942        doc = "Because the macros and std features were not enabled at doc build time, the example cannot be tested.\n\n```ignore\n"
943    )]
944    #[cfg_attr(all(feature = "macros", feature = "std"), doc = "\n```\n")]
945    /// # use core::any::Any;
946    /// # use xso::{dynxso::Xso, derive_dyn_traits, from_bytes, FromXml};
947    /// trait Trait: Any {}
948    /// derive_dyn_traits!(Trait);
949    ///
950    /// #[derive(FromXml, PartialEq, Debug)]
951    /// #[xml(namespace = "urn:example", name = "foo")]
952    /// struct Foo;
953    /// impl Trait for Foo {}
954    ///
955    /// // Parsing fails, because register_type() has not been called for
956    /// // Foo:
957    /// assert!(from_bytes::<Xso<dyn Trait>>("<foo xmlns='urn:example'/>".as_bytes()).is_err());
958    ///
959    /// Xso::<dyn Trait>::register_type::<Foo>();
960    /// // After registering Foo with Xso<dyn Trait>, parsing succeeds and
961    /// // we can downcast to Foo:
962    /// let x: Xso<dyn Trait> = from_bytes("<foo xmlns='urn:example'/>".as_bytes()).unwrap();
963    /// assert_eq!(Foo, *x.downcast().unwrap());
964    /// ```
965    pub fn register_type<U: FromXml + 'static>()
966    where
967        T: MayContain<U>,
968    {
969        T::registry().add::<U>()
970    }
971}
972
973/// Wrapper around a `FromEventsBuilder` to convert a `Box<T>` output to a
974/// `Xso<T>` output.
975///
976/// Not constructible by users, only for internal use.
977pub struct DynBuilder<B> {
978    inner: B,
979}
980
981impl<T: DynXso + ?Sized + 'static, B: FromEventsBuilder<Output = Box<T>>> FromEventsBuilder
982    for DynBuilder<B>
983{
984    type Output = Xso<T>;
985
986    fn feed(&mut self, ev: rxml::Event, ctx: &Context) -> Result<Option<Self::Output>, Error> {
987        self.inner
988            .feed(ev, ctx)
989            .map(|x| x.map(|inner| Xso { inner }))
990    }
991}
992
993/// Wrapper around a `FromEventsBuilder` to convert a `Box<T>` output to a
994/// `T` output.
995pub struct UnboxBuilder<T> {
996    inner: T,
997}
998
999impl<O, T: FromEventsBuilder<Output = Box<O>>> UnboxBuilder<T> {
1000    /// Wrap a `FromEventsBuilder` which generates `Box<O>`.
1001    pub fn wrap(inner: T) -> Self {
1002        Self { inner }
1003    }
1004}
1005
1006impl<O, T: FromEventsBuilder<Output = Box<O>>> FromEventsBuilder for UnboxBuilder<T> {
1007    type Output = O;
1008
1009    fn feed(&mut self, ev: rxml::Event, ctx: &Context) -> Result<Option<Self::Output>, Error> {
1010        self.inner.feed(ev, ctx).map(|x| x.map(|inner| *inner))
1011    }
1012}
1013
1014impl<R: DynXsoRegistryLookup<T> + 'static, T: DynXso<Registry = R> + ?Sized + 'static> FromXml
1015    for Xso<T>
1016{
1017    type Builder = DynBuilder<Box<dyn FromEventsBuilder<Output = Box<T>>>>;
1018
1019    fn from_events(
1020        name: rxml::QName,
1021        attrs: rxml::AttrMap,
1022        ctx: &Context<'_>,
1023    ) -> Result<Self::Builder, FromEventsError> {
1024        T::registry()
1025            .make_builder(name, attrs, ctx)
1026            .map(|inner| DynBuilder { inner })
1027    }
1028}
1029
1030impl<T: DynXso + AsXmlDyn + ?Sized + 'static> AsXml for Xso<T> {
1031    type ItemIter<'x> = Box<dyn Iterator<Item = Result<Item<'x>, Error>> + 'x>;
1032
1033    fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
1034        self.inner.as_xml_dyn_iter()
1035    }
1036
1037    fn as_xml_dyn_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
1038        self.inner.as_xml_dyn_iter()
1039    }
1040}
1041
1042/// Error type for retrieving a single item from `XsoVec`.
1043#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1044pub enum TakeOneError {
1045    /// More than one item was found.
1046    MultipleEntries,
1047}
1048
1049impl fmt::Display for TakeOneError {
1050    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1051        match self {
1052            Self::MultipleEntries => f.write_str("multiple entries found"),
1053        }
1054    }
1055}
1056
1057/// # Container for dynamically-typed XSOs optimized for type-keyed access
1058///
1059/// This container holds dynamically typed XSOs (see
1060/// [`Xso<dyn Trait>`][`Xso`]). It allows efficient access to its contents
1061/// based on the actual type.
1062///
1063/// Like `Xso<dyn Trait>` itself, `XsoVec<dyn Trait>` requires that
1064/// `MayContain` is implemented by `dyn Trait` for all items which are added
1065/// to the container. This is automatically the case for all `T: Trait`
1066/// if [`derive_dyn_traits`][`crate::derive_dyn_traits`] has been used on
1067/// `Trait`.
1068///
1069/// Note that `XsoVec` has a non-obvious iteration order, which is described
1070/// in [`XsoVec::iter()`][`Self::iter`].
1071pub struct XsoVec<T: ?Sized> {
1072    inner: BTreeMap<TypeId, Vec<Xso<T>>>,
1073}
1074
1075impl<T: ?Sized> fmt::Debug for XsoVec<T> {
1076    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1077        write!(
1078            f,
1079            "XsoVec[{} types, {} items]",
1080            self.inner.len(),
1081            self.len()
1082        )
1083    }
1084}
1085
1086impl<T: ?Sized> Default for XsoVec<T> {
1087    fn default() -> Self {
1088        Self {
1089            inner: BTreeMap::default(),
1090        }
1091    }
1092}
1093
1094impl<T: DynXso + ?Sized + 'static> XsoVec<T> {
1095    /// Construct a new, empty `XsoVec`.
1096    ///
1097    /// ```
1098    #[doc = include_str!("xso_vec_test_prelude.rs")]
1099    /// let mut vec = XsoVec::<dyn Trait>::new();
1100    /// ```
1101    pub const fn new() -> Self {
1102        Self {
1103            inner: BTreeMap::new(),
1104        }
1105    }
1106
1107    /// Return a reference to the first item of type `U`.
1108    ///
1109    /// If the container does not hold any item of type `U`, return `None`.
1110    ///
1111    /// ```
1112    #[doc = include_str!("xso_vec_test_prelude.rs")]
1113    /// #[derive(PartialEq, Debug)]
1114    /// struct Foo(u8);
1115    /// impl Trait for Foo {}
1116    ///
1117    /// #[derive(PartialEq, Debug)]
1118    /// struct Bar(u16);
1119    /// impl Trait for Bar {}
1120    ///
1121    /// #[derive(PartialEq, Debug)]
1122    /// struct Baz(u32);
1123    /// impl Trait for Baz {}
1124    ///
1125    /// let mut vec = XsoVec::<dyn Trait>::new();
1126    /// vec.push(Bar(1));
1127    /// vec.push(Foo(2));
1128    /// vec.push(Foo(1));
1129    /// assert_eq!(vec.get_first::<Foo>(), Some(&Foo(2)));
1130    /// assert_eq!(vec.get_first::<Bar>(), Some(&Bar(1)));
1131    /// assert_eq!(vec.get_first::<Baz>(), None);
1132    ///
1133    /// ```
1134    pub fn get_first<U: 'static>(&self) -> Option<&U>
1135    where
1136        T: MayContain<U>,
1137    {
1138        self.iter_typed::<U>().next()
1139    }
1140
1141    /// Return a mutable reference to the first item of type `U`.
1142    ///
1143    /// If the container does not hold any item of type `U`, return `None`.
1144    ///
1145    /// ```
1146    #[doc = include_str!("xso_vec_test_prelude.rs")]
1147    /// #[derive(PartialEq, Debug)]
1148    /// struct Foo(u8);
1149    /// impl Trait for Foo {}
1150    ///
1151    /// let mut vec = XsoVec::<dyn Trait>::new();
1152    /// vec.push(Foo(1));
1153    /// vec.get_first_mut::<Foo>().unwrap().0 = 2;
1154    /// assert_eq!(vec.get_first::<Foo>(), Some(&Foo(2)));
1155    /// ```
1156    pub fn get_first_mut<U: 'static>(&mut self) -> Option<&mut U>
1157    where
1158        T: MayContain<U>,
1159    {
1160        self.iter_typed_mut::<U>().next()
1161    }
1162
1163    /// Take and return exactly one item of type `U`.
1164    ///
1165    /// If no item of type `U` is present in the container, return Ok(None).
1166    /// If more than one item of type `U` is present in the container,
1167    /// return an error.
1168    /// ```
1169    #[doc = include_str!("xso_vec_test_prelude.rs")]
1170    /// #[derive(PartialEq, Debug)]
1171    /// struct Foo(u8);
1172    /// impl Trait for Foo {}
1173    ///
1174    /// #[derive(PartialEq, Debug)]
1175    /// struct Bar(u16);
1176    /// impl Trait for Bar {}
1177    ///
1178    /// #[derive(PartialEq, Debug)]
1179    /// struct Baz(u32);
1180    /// impl Trait for Baz {}
1181    ///
1182    /// let mut vec = XsoVec::<dyn Trait>::new();
1183    /// vec.push(Bar(1));
1184    /// vec.push(Foo(2));
1185    /// vec.push(Foo(1));
1186    /// assert_eq!(vec.take_one::<Foo>(), Err(TakeOneError::MultipleEntries));
1187    /// assert_eq!(*vec.take_one::<Bar>().unwrap().unwrap(), Bar(1));
1188    /// assert_eq!(vec.take_one::<Bar>(), Ok(None));
1189    /// assert_eq!(vec.take_one::<Baz>(), Ok(None));
1190    /// ```
1191    pub fn take_one<U: 'static>(&mut self) -> Result<Option<Box<U>>, TakeOneError>
1192    where
1193        T: MayContain<U>,
1194    {
1195        let source = match self.inner.get_mut(&TypeId::of::<U>()) {
1196            Some(v) => v,
1197            None => return Ok(None),
1198        };
1199        if source.len() > 1 {
1200            return Err(TakeOneError::MultipleEntries);
1201        }
1202        Ok(source.pop().map(Xso::force_downcast))
1203    }
1204
1205    /// Take and return the first item of type `U`.
1206    ///
1207    /// If no item of type `U` is present in the container, return None.
1208    /// ```
1209    #[doc = include_str!("xso_vec_test_prelude.rs")]
1210    /// #[derive(PartialEq, Debug)]
1211    /// struct Foo(u8);
1212    /// impl Trait for Foo {}
1213    ///
1214    /// #[derive(PartialEq, Debug)]
1215    /// struct Bar(u16);
1216    /// impl Trait for Bar {}
1217    ///
1218    /// #[derive(PartialEq, Debug)]
1219    /// struct Baz(u32);
1220    /// impl Trait for Baz {}
1221    ///
1222    /// let mut vec = XsoVec::<dyn Trait>::new();
1223    /// vec.push(Bar(1));
1224    /// vec.push(Foo(2));
1225    /// vec.push(Foo(1));
1226    /// assert_eq!(*vec.take_first::<Foo>().unwrap(), Foo(2));
1227    /// assert_eq!(*vec.take_first::<Foo>().unwrap(), Foo(1));
1228    /// assert_eq!(*vec.take_first::<Bar>().unwrap(), Bar(1));
1229    /// assert_eq!(vec.take_first::<Bar>(), None);
1230    /// assert_eq!(vec.take_first::<Baz>(), None);
1231    /// ```
1232    pub fn take_first<U: 'static>(&mut self) -> Option<Box<U>>
1233    where
1234        T: MayContain<U>,
1235    {
1236        let source = self.inner.get_mut(&TypeId::of::<U>())?;
1237        if source.len() == 0 {
1238            return None;
1239        }
1240        Some(source.remove(0).force_downcast())
1241    }
1242
1243    /// Take and return the last item of type `U`.
1244    ///
1245    /// If no item of type `U` is present in the container, return None.
1246    /// ```
1247    #[doc = include_str!("xso_vec_test_prelude.rs")]
1248    /// #[derive(PartialEq, Debug)]
1249    /// struct Foo(u8);
1250    /// impl Trait for Foo {}
1251    ///
1252    /// #[derive(PartialEq, Debug)]
1253    /// struct Bar(u16);
1254    /// impl Trait for Bar {}
1255    ///
1256    /// #[derive(PartialEq, Debug)]
1257    /// struct Baz(u32);
1258    /// impl Trait for Baz {}
1259    ///
1260    /// let mut vec = XsoVec::<dyn Trait>::new();
1261    /// vec.push(Bar(1));
1262    /// vec.push(Foo(2));
1263    /// vec.push(Foo(1));
1264    /// assert_eq!(*vec.take_last::<Foo>().unwrap(), Foo(1));
1265    /// assert_eq!(*vec.take_last::<Foo>().unwrap(), Foo(2));
1266    /// assert_eq!(*vec.take_last::<Bar>().unwrap(), Bar(1));
1267    /// assert_eq!(vec.take_last::<Bar>(), None);
1268    /// assert_eq!(vec.take_last::<Baz>(), None);
1269    /// ```
1270    pub fn take_last<U: 'static>(&mut self) -> Option<Box<U>>
1271    where
1272        T: MayContain<U>,
1273    {
1274        let source = self.inner.get_mut(&TypeId::of::<U>())?;
1275        source.pop().map(Xso::force_downcast)
1276    }
1277
1278    /// Iterate all items of type `U` as references.
1279    ///
1280    /// ```
1281    #[doc = include_str!("xso_vec_test_prelude.rs")]
1282    /// #[derive(PartialEq, Debug)]
1283    /// struct Foo(u8);
1284    /// impl Trait for Foo {}
1285    ///
1286    /// #[derive(PartialEq, Debug)]
1287    /// struct Bar(u16);
1288    /// impl Trait for Bar {}
1289    ///
1290    /// #[derive(PartialEq, Debug)]
1291    /// struct Baz(u32);
1292    /// impl Trait for Baz {}
1293    ///
1294    /// let mut vec = XsoVec::<dyn Trait>::new();
1295    /// vec.push(Bar(1));
1296    /// vec.push(Foo(2));
1297    /// vec.push(Foo(1));
1298    ///
1299    /// let foos: Vec<_> = vec.iter_typed::<Foo>().collect();
1300    /// assert_eq!(&foos[..], &[&Foo(2), &Foo(1)]);
1301    /// ```
1302    pub fn iter_typed<U: 'static>(&self) -> impl Iterator<Item = &U>
1303    where
1304        T: MayContain<U>,
1305    {
1306        let iter = match self.inner.get(&TypeId::of::<U>()) {
1307            Some(v) => v.deref().iter(),
1308            None => [].iter(),
1309        };
1310        // UNWRAP: We group the values by TypeId, so the downcast should never
1311        // fail, but I am too chicken to use the unchecked variants :).
1312        iter.map(|x| x.downcast_ref::<U>().unwrap())
1313    }
1314
1315    /// Iterate all items of type `U` as mutable references.
1316    ///
1317    /// ```
1318    #[doc = include_str!("xso_vec_test_prelude.rs")]
1319    /// #[derive(PartialEq, Debug)]
1320    /// struct Foo(u8);
1321    /// impl Trait for Foo {}
1322    ///
1323    /// #[derive(PartialEq, Debug)]
1324    /// struct Bar(u16);
1325    /// impl Trait for Bar {}
1326    ///
1327    /// #[derive(PartialEq, Debug)]
1328    /// struct Baz(u32);
1329    /// impl Trait for Baz {}
1330    ///
1331    /// let mut vec = XsoVec::<dyn Trait>::new();
1332    /// vec.push(Bar(1));
1333    /// vec.push(Foo(2));
1334    /// vec.push(Foo(1));
1335    ///
1336    /// let foos: Vec<_> = vec.iter_typed_mut::<Foo>().collect();
1337    /// assert_eq!(&foos[..], &[&mut Foo(2), &mut Foo(1)]);
1338    /// ```
1339    pub fn iter_typed_mut<U: 'static>(&mut self) -> impl Iterator<Item = &mut U>
1340    where
1341        T: MayContain<U>,
1342    {
1343        let iter = match self.inner.get_mut(&TypeId::of::<U>()) {
1344            Some(v) => v.deref_mut().iter_mut(),
1345            None => [].iter_mut(),
1346        };
1347        // UNWRAP: We group the values by TypeId, so the downcast should never
1348        // fail, but I am too chicken to use the unchecked variants :).
1349        iter.map(|x| x.downcast_mut::<U>().unwrap())
1350    }
1351
1352    /// Drain all items of type `U` out of the container.
1353    ///
1354    /// If the result is dropped before the end of the iterator has been
1355    /// reached, the remaining items are still dropped out of the container.
1356    ///
1357    /// ```
1358    #[doc = include_str!("xso_vec_test_prelude.rs")]
1359    /// #[derive(PartialEq, Debug)]
1360    /// struct Foo(u8);
1361    /// impl Trait for Foo {}
1362    ///
1363    /// #[derive(PartialEq, Debug)]
1364    /// struct Bar(u16);
1365    /// impl Trait for Bar {}
1366    ///
1367    /// #[derive(PartialEq, Debug)]
1368    /// struct Baz(u32);
1369    /// impl Trait for Baz {}
1370    ///
1371    /// let mut vec = XsoVec::<dyn Trait>::new();
1372    /// vec.push(Bar(1));
1373    /// vec.push(Foo(2));
1374    /// vec.push(Foo(1));
1375    ///
1376    /// let foos: Vec<_> = vec.drain_typed::<Foo>().map(|x| *x).collect();
1377    /// //                             converts Box<T> to T ↑
1378    /// assert_eq!(&foos[..], &[Foo(2), Foo(1)]);
1379    /// ```
1380    pub fn drain_typed<U: 'static>(&mut self) -> impl Iterator<Item = Box<U>>
1381    where
1382        T: MayContain<U>,
1383    {
1384        let iter = match self.inner.remove(&TypeId::of::<U>()) {
1385            Some(v) => v.into_iter(),
1386            None => Vec::new().into_iter(),
1387        };
1388        // UNWRAP: We group the values by TypeId, so the downcast should never
1389        // fail, but I am too chicken to use the unchecked variants :).
1390        iter.map(|x| match x.downcast::<U>() {
1391            Ok(v) => v,
1392            Err(_) => {
1393                unreachable!("TypeId disagrees with Xso<_>::downcast, or internal state corruption")
1394            }
1395        })
1396    }
1397
1398    fn ensure_vec_mut_for(&mut self, type_id: TypeId) -> &mut Vec<Xso<T>> {
1399        match self.inner.entry(type_id) {
1400            Entry::Vacant(v) => v.insert(Vec::new()),
1401            Entry::Occupied(o) => o.into_mut(),
1402        }
1403    }
1404
1405    /// Push a new item of type `U` to the end of the section of `U` inside
1406    /// the container.
1407    ///
1408    /// Please note the information about iteration order of the `XsoVec`
1409    /// at [`XsoVec::iter`][`Self::iter`].
1410    ///
1411    /// ```
1412    #[doc = include_str!("xso_vec_test_prelude.rs")]
1413    /// #[derive(PartialEq, Debug)]
1414    /// struct Foo(u8);
1415    /// impl Trait for Foo {}
1416    ///
1417    /// let mut vec = XsoVec::<dyn Trait>::new();
1418    /// vec.push(Foo(1));
1419    /// ```
1420    pub fn push<U: 'static>(&mut self, value: U)
1421    where
1422        T: MayContain<U>,
1423    {
1424        self.ensure_vec_mut_for(TypeId::of::<U>())
1425            .push(Xso::wrap(value));
1426    }
1427
1428    /// Push a new dynamically typed item to the end of the section of values
1429    /// with the same type inside the container.
1430    ///
1431    /// Please note the information about iteration order of the `XsoVec`
1432    /// at [`XsoVec::iter`][`Self::iter`].
1433    ///
1434    /// ```
1435    /// # use xso::dynxso::Xso;
1436    #[doc = include_str!("xso_vec_test_prelude.rs")]
1437    /// #[derive(PartialEq, Debug)]
1438    /// struct Foo(u8);
1439    /// impl Trait for Foo {}
1440    ///
1441    /// #[derive(PartialEq, Debug)]
1442    /// struct Bar(u8);
1443    /// impl Trait for Bar {}
1444    ///
1445    /// let mut vec = XsoVec::<dyn Trait>::new();
1446    /// vec.push(Foo(1));
1447    /// vec.push_dyn(Xso::wrap(Foo(2)));
1448    /// vec.push_dyn(Xso::wrap(Bar(1)));
1449    /// vec.push(Bar(2));
1450    ///
1451    /// let foos: Vec<_> = vec.iter_typed::<Foo>().collect();
1452    /// assert_eq!(&foos[..], &[&Foo(1), &Foo(2)]);
1453    ///
1454    /// let bars: Vec<_> = vec.iter_typed::<Bar>().collect();
1455    /// assert_eq!(&bars[..], &[&Bar(1), &Bar(2)]);
1456    /// ```
1457    pub fn push_dyn(&mut self, value: Xso<T>) {
1458        self.ensure_vec_mut_for(value.inner_type_id()).push(value);
1459    }
1460}
1461
1462impl<T: ?Sized> XsoVec<T> {
1463    /// Clear all contents, without deallocating memory.
1464    ///
1465    /// ```
1466    #[doc = include_str!("xso_vec_test_prelude.rs")]
1467    /// #[derive(PartialEq, Debug)]
1468    /// struct Foo(u8);
1469    /// impl Trait for Foo {}
1470    ///
1471    /// let mut vec = XsoVec::<dyn Trait>::new();
1472    /// vec.push(Foo(1));
1473    /// vec.push(Foo(2));
1474    /// vec.clear();
1475    /// assert_eq!(vec.len(), 0);
1476    /// ```
1477    pub fn clear(&mut self) {
1478        self.inner.values_mut().for_each(|x| x.clear());
1479    }
1480
1481    /// Return true if there are no items in the container.
1482    ///
1483    /// ```
1484    #[doc = include_str!("xso_vec_test_prelude.rs")]
1485    /// #[derive(PartialEq, Debug)]
1486    /// struct Foo(u8);
1487    /// impl Trait for Foo {}
1488    ///
1489    /// let mut vec = XsoVec::<dyn Trait>::new();
1490    /// assert!(vec.is_empty());
1491    /// vec.push(Foo(1));
1492    /// assert!(!vec.is_empty());
1493    /// ```
1494    pub fn is_empty(&self) -> bool {
1495        self.inner.values().all(|x| x.is_empty())
1496    }
1497
1498    /// Reduce memory use of the container to the minimum required to hold
1499    /// the current data.
1500    ///
1501    /// This may be expensive if lots of data needs to be shuffled.
1502    pub fn shrink_to_fit(&mut self) {
1503        self.inner.retain(|_, x| {
1504            if x.is_empty() {
1505                return false;
1506            }
1507            x.shrink_to_fit();
1508            true
1509        });
1510    }
1511
1512    /// Return the total amount of items in the container.
1513    ///
1514    /// ```
1515    #[doc = include_str!("xso_vec_test_prelude.rs")]
1516    /// #[derive(PartialEq, Debug)]
1517    /// struct Foo(u8);
1518    /// impl Trait for Foo {}
1519    ///
1520    /// let mut vec = XsoVec::<dyn Trait>::new();
1521    /// assert_eq!(vec.len(), 0);
1522    /// vec.push(Foo(1));
1523    /// assert_eq!(vec.len(), 1);
1524    /// ```
1525    pub fn len(&self) -> usize {
1526        self.inner.values().map(|x| x.len()).sum()
1527    }
1528
1529    /// Iterate the items inside the container.
1530    ///
1531    /// This iterator (unlike the iterator returned by
1532    /// [`iter_typed()`][`Self::iter_typed`]) yields references to **untyped**
1533    /// [`Xso<dyn Trait>`][`Xso`].
1534    ///
1535    /// # Iteration order
1536    ///
1537    /// Items which have the same concrete type are grouped and their ordering
1538    /// with respect to one another is preserved. However, the ordering of
1539    /// items with *different* concrete types is unspecified.
1540    ///
1541    /// # Example
1542    ///
1543    /// ```
1544    #[doc = include_str!("xso_vec_test_prelude.rs")]
1545    /// #[derive(PartialEq, Debug)]
1546    /// struct Foo(u8);
1547    /// impl Trait for Foo {}
1548    ///
1549    /// #[derive(PartialEq, Debug)]
1550    /// struct Bar(u16);
1551    /// impl Trait for Bar {}
1552    ///
1553    /// let mut vec = XsoVec::<dyn Trait>::new();
1554    /// vec.push(Foo(1));
1555    /// vec.push(Bar(1));
1556    /// vec.push(Foo(2));
1557    ///
1558    /// for item in vec.iter() {
1559    ///     println!("{:?}", item);
1560    /// }
1561    /// ```
1562    pub fn iter(&self) -> XsoVecIter<'_, T> {
1563        XsoVecIter {
1564            remaining: self.len(),
1565            outer: self.inner.values(),
1566            inner: None,
1567        }
1568    }
1569
1570    /// Iterate the items inside the container, mutably.
1571    ///
1572    /// This iterator (unlike the iterator returned by
1573    /// [`iter_typed_mut()`][`Self::iter_typed_mut`]) yields mutable
1574    /// references to **untyped** [`Xso<dyn Trait>`][`Xso`].
1575    ///
1576    /// Please note the information about iteration order of the `XsoVec`
1577    /// at [`XsoVec::iter`][`Self::iter`].
1578    pub fn iter_mut(&mut self) -> XsoVecIterMut<'_, T> {
1579        XsoVecIterMut {
1580            remaining: self.len(),
1581            outer: self.inner.values_mut(),
1582            inner: None,
1583        }
1584    }
1585}
1586
1587impl<T: ?Sized> IntoIterator for XsoVec<T> {
1588    type Item = Xso<T>;
1589    type IntoIter = XsoVecIntoIter<T>;
1590
1591    fn into_iter(self) -> Self::IntoIter {
1592        XsoVecIntoIter {
1593            remaining: self.len(),
1594            outer: self.inner.into_values(),
1595            inner: None,
1596        }
1597    }
1598}
1599
1600impl<'x, T: ?Sized> IntoIterator for &'x XsoVec<T> {
1601    type Item = &'x Xso<T>;
1602    type IntoIter = XsoVecIter<'x, T>;
1603
1604    fn into_iter(self) -> Self::IntoIter {
1605        self.iter()
1606    }
1607}
1608
1609impl<'x, T: ?Sized> IntoIterator for &'x mut XsoVec<T> {
1610    type Item = &'x mut Xso<T>;
1611    type IntoIter = XsoVecIterMut<'x, T>;
1612
1613    fn into_iter(self) -> Self::IntoIter {
1614        self.iter_mut()
1615    }
1616}
1617
1618impl<T: DynXso + ?Sized + 'static> Extend<Xso<T>> for XsoVec<T> {
1619    fn extend<I: IntoIterator<Item = Xso<T>>>(&mut self, iter: I) {
1620        for item in iter {
1621            self.ensure_vec_mut_for(item.inner_type_id()).push(item);
1622        }
1623    }
1624}
1625
1626/// Helper types for [`XsoVec`].
1627pub mod xso_vec {
1628    use super::*;
1629
1630    /// Iterator over the contents of an [`XsoVec`].
1631    pub struct XsoVecIter<'x, T: ?Sized> {
1632        pub(super) outer: btree_map::Values<'x, TypeId, Vec<Xso<T>>>,
1633        pub(super) inner: Option<slice::Iter<'x, Xso<T>>>,
1634        pub(super) remaining: usize,
1635    }
1636
1637    impl<'x, T: ?Sized> Iterator for XsoVecIter<'x, T> {
1638        type Item = &'x Xso<T>;
1639
1640        fn next(&mut self) -> Option<Self::Item> {
1641            loop {
1642                if let Some(inner) = self.inner.as_mut() {
1643                    if let Some(item) = inner.next() {
1644                        self.remaining = self.remaining.saturating_sub(1);
1645                        return Some(item);
1646                    }
1647                    // Inner is exhausted, so equivalent to None, fall through.
1648                }
1649                // The `?` in there is our exit condition.
1650                self.inner = Some(self.outer.next()?.deref().iter())
1651            }
1652        }
1653
1654        fn size_hint(&self) -> (usize, Option<usize>) {
1655            (self.remaining, Some(self.remaining))
1656        }
1657    }
1658
1659    /// Mutable iterator over the contents of an [`XsoVec`].
1660    pub struct XsoVecIterMut<'x, T: ?Sized> {
1661        pub(super) outer: btree_map::ValuesMut<'x, TypeId, Vec<Xso<T>>>,
1662        pub(super) inner: Option<slice::IterMut<'x, Xso<T>>>,
1663        pub(super) remaining: usize,
1664    }
1665
1666    impl<'x, T: ?Sized> Iterator for XsoVecIterMut<'x, T> {
1667        type Item = &'x mut Xso<T>;
1668
1669        fn next(&mut self) -> Option<Self::Item> {
1670            loop {
1671                if let Some(inner) = self.inner.as_mut() {
1672                    if let Some(item) = inner.next() {
1673                        self.remaining = self.remaining.saturating_sub(1);
1674                        return Some(item);
1675                    }
1676                    // Inner is exhausted, so equivalent to None, fall through.
1677                }
1678                // The `?` in there is our exit condition.
1679                self.inner = Some(self.outer.next()?.deref_mut().iter_mut())
1680            }
1681        }
1682
1683        fn size_hint(&self) -> (usize, Option<usize>) {
1684            (self.remaining, Some(self.remaining))
1685        }
1686    }
1687
1688    /// Iterator over the owned contents of an [`XsoVec`].
1689    pub struct XsoVecIntoIter<T: ?Sized> {
1690        pub(super) outer: btree_map::IntoValues<TypeId, Vec<Xso<T>>>,
1691        pub(super) inner: Option<vec::IntoIter<Xso<T>>>,
1692        pub(super) remaining: usize,
1693    }
1694
1695    impl<T: ?Sized> Iterator for XsoVecIntoIter<T> {
1696        type Item = Xso<T>;
1697
1698        fn next(&mut self) -> Option<Self::Item> {
1699            loop {
1700                if let Some(inner) = self.inner.as_mut() {
1701                    if let Some(item) = inner.next() {
1702                        self.remaining = self.remaining.saturating_sub(1);
1703                        return Some(item);
1704                    }
1705                    // Inner is exhausted, so equivalent to None, fall through.
1706                }
1707                // The `?` in there is our exit condition.
1708                self.inner = Some(self.outer.next()?.into_iter())
1709            }
1710        }
1711
1712        fn size_hint(&self) -> (usize, Option<usize>) {
1713            (self.remaining, Some(self.remaining))
1714        }
1715    }
1716}
1717
1718use xso_vec::*;
1719
1720#[cfg(test)]
1721mod tests {
1722    use super::*;
1723
1724    #[test]
1725    fn xso_inner_type_id_is_correct() {
1726        trait Trait: Any {}
1727        crate::derive_dyn_traits!(Trait use () = ());
1728        struct Foo;
1729        impl Trait for Foo {}
1730
1731        let ty_id = TypeId::of::<Foo>();
1732        let x: Xso<dyn Trait> = Xso::wrap(Foo);
1733        assert_eq!(x.inner_type_id(), ty_id);
1734    }
1735}