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