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