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 = ®istry[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}