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