all_is_cubes/universe/
members.rs

1//! Module defining various traits and impls relating to [`Universe`] containing different
2//! types of members.
3//!
4//! This module is not public and that is part of the protection of several items
5//! inside it (the public-in-private trick).
6
7use alloc::boxed::Box;
8use core::any::Any;
9use core::{fmt, hash};
10
11use bevy_ecs::prelude as ecs;
12use bevy_ecs::query::QueryData;
13
14use crate::block::BlockDef;
15use crate::character::Character;
16use crate::sound::SoundDef;
17use crate::space::Space;
18use crate::tag::TagDef;
19use crate::transaction;
20use crate::universe::{
21    self, ErasedHandle, Handle, InsertError, Name, Universe, handle::HandlePtr, universe_txn as ut,
22};
23
24// -------------------------------------------------------------------------------------------------
25// Traits
26
27/// Not-externally-implementable supertrait for [`UniverseMember`] to make it sealed and hide
28/// implementation details.
29// TODO(ecs): make Component not a supertrait once we have split members into multiple components.
30pub(crate) trait SealedMember: Sized {
31    /// Components to spawn when inserting a member of this type into a universe.
32    type Bundle: ecs::Bundle;
33
34    type ReadQueryData: bevy_ecs::query::ReadOnlyQueryData + Clone;
35
36    /// Register `VisitableComponents` and anything else needed.
37    fn register_all_member_components(world: &mut ecs::World);
38
39    /// Constructs `Self::Read` from a value that has not yet been inserted into the
40    /// [`Universe`].
41    fn read_from_standalone(value: &Self) -> Self::Read<'_>
42    where
43        Self: UniverseMember;
44
45    /// Constructs `Self::Read` from query data.
46    fn read_from_query(data: <Self::ReadQueryData as QueryData>::Item<'_>) -> Self::Read<'_>
47    where
48        Self: UniverseMember;
49
50    /// Constructs `Self::Read` from an [`ecs::EntityRef`].
51    /// This may be used when queries are not feasible.
52    ///
53    /// Returns [`None`] when the entity does not have the components it should have.
54    /// No other validation is guaranteed to be performed.
55    #[expect(
56        unused,
57        reason = "TODO(ecs): remove this if we turn out to never need it"
58    )]
59    fn read_from_entity_ref(entity: ecs::EntityRef<'_>) -> Option<Self::Read<'_>>
60    where
61        Self: UniverseMember;
62
63    /// Converts `Self` (the form independent of a universe) into a bundle to be part of a
64    /// newly spawned entity.
65    fn into_bundle(value: Box<Self>) -> Self::Bundle;
66}
67
68/// Trait for every type which can be a named member of a universe and be referred to by
69/// [`Handle`]s.
70///
71/// This trait provides no operations itself, but is a bound on functions of [`Universe`],
72/// [`Handle`], and [`UniverseTransaction`][ut::UniverseTransaction].
73//---
74// TODO: Give this trait a better name. Some errors refer to this concept as "object", and
75// in a purely abstract architecture sense it’s a sort of “entity” but that conflicts with
76// “is a bevy_ecs entity”.
77#[expect(private_bounds)]
78pub trait UniverseMember: Sized + 'static + fmt::Debug + SealedMember + MemberBoilerplate {
79    /// Type returned by [`Handle::<T>::read()`][Handle::read()] which is the way to read the
80    /// `T` value after it has been inserted into the [`Universe`].
81    //---
82    // For serialization, this type must serialize to the universe member type’s serialization
83    // schema. (The simplest way to do this is for it to be `&T`, for example.)
84    type Read<'ticket>: Clone;
85}
86
87/// Trait for operations on [`Handle`]s and queries that must be implemented for each member type.
88/// This trait is implemented by macro and not customized for each member type.
89pub(in crate::universe) trait MemberBoilerplate: Sized {
90    /// Generic constructor for [`AnyHandle`].
91    fn into_any_handle(handle: Handle<Self>) -> AnyHandle;
92
93    /// Generic constructor for [`AnyPending`].
94    fn into_any_pending(handle: Handle<Self>, value: Option<Box<Self>>) -> AnyPending;
95
96    fn member_read_query_state(
97        queries: &MemberReadQueryStates,
98    ) -> &ecs::QueryState<Self::ReadQueryData>
99    where
100        Self: UniverseMember;
101
102    fn member_mutation_query_state(
103        queries: &mut MemberWriteQueryStates,
104    ) -> &mut ecs::QueryState<<<Self as universe::Transactional>::Transaction as universe::TransactionOnEcs>::WriteQueryData>
105    where
106        Self: UniverseMember + transaction::Transactional<Transaction: universe::TransactionOnEcs>;
107
108    /// Fetch the query for for this member tyype from [`MemberReadQueries`].
109    /// May fail if such a query was not provided.
110    fn member_read_query<'q, 'w, 's>(
111        queries: &'q MemberReadQueries<'w, 's>,
112    ) -> Option<&'q ecs::Query<'w, 's, Self::ReadQueryData>>
113    where
114        Self: UniverseMember;
115}
116
117// -------------------------------------------------------------------------------------------------
118
119/// Use this macro to implement [`UniverseMember`] and related traits for any member type whose only
120/// ECS component (that are read through [`Handle`]s) is itself.
121///
122/// TODO(ecs): Remove all uses of this so that public types are not component types.
123macro_rules! impl_universe_member_for_single_component_type {
124    ($member_type:path) => {
125        impl $crate::universe::SealedMember for $member_type {
126            type Bundle = (Self,);
127            type ReadQueryData = &'static Self;
128
129            fn register_all_member_components(world: &mut ::bevy_ecs::world::World) {
130                $crate::universe::VisitableComponents::register::<$member_type>(world);
131            }
132
133            fn read_from_standalone(
134                value: &Self,
135            ) -> <Self as $crate::universe::UniverseMember>::Read<'_> {
136                // TODO(ecs): when we have multiple components, this will need to be defined
137                // separately for each member type.
138                value
139            }
140
141            fn read_from_query(
142                data: <Self::ReadQueryData as ::bevy_ecs::query::QueryData>::Item<'_>,
143            ) -> <Self as $crate::universe::UniverseMember>::Read<'_> {
144                // TODO(ecs): when we have multiple components, this will need to be defined
145                // separately for each member type.
146                data
147            }
148
149            fn read_from_entity_ref(
150                entity: ::bevy_ecs::world::EntityRef<'_>,
151            ) -> Option<<Self as $crate::universe::UniverseMember>::Read<'_>> {
152                // TODO(ecs): when we have multiple components, this will need to be defined
153                // separately for each member type.
154                entity.get::<$member_type>()
155            }
156
157            fn into_bundle(value: ::alloc::boxed::Box<Self>) -> Self::Bundle {
158                // TODO(ecs): when we have multiple components, this will need to be defined
159                // separately for each member type.
160                (*value,)
161            }
162        }
163
164        impl $crate::universe::UniverseMember for $member_type {
165            // TODO(ecs): when we have multiple components, this will need to be defined
166            // separately for each member type.
167            type Read<'ticket> = &'ticket $member_type;
168        }
169    };
170}
171pub(crate) use impl_universe_member_for_single_component_type;
172
173/// Generates boilerplate impls for a specific Universe member type.
174macro_rules! impl_universe_for_member {
175    ($member_type:ident, $table:ident) => {
176        impl MemberBoilerplate for $member_type {
177            fn into_any_handle(handle: Handle<Self>) -> AnyHandle {
178                AnyHandle::$member_type(handle)
179            }
180
181            fn into_any_pending(handle: Handle<Self>, value: Option<Box<Self>>) -> AnyPending {
182                AnyPending::$member_type { handle, value }
183            }
184
185            fn member_read_query_state(
186                queries: &MemberReadQueryStates,
187            ) -> &ecs::QueryState<<Self as SealedMember>::ReadQueryData> {
188                &queries.$table
189            }
190
191            fn member_mutation_query_state(
192                queries: &mut MemberWriteQueryStates,
193            ) -> &mut ecs::QueryState<<<Self as universe::Transactional>::Transaction as universe::TransactionOnEcs>::WriteQueryData> {
194                &mut queries.$table
195            }
196
197            fn member_read_query<'q, 'w, 's>(
198                queries: &'q MemberReadQueries<'w, 's>,
199            ) -> Option<&'q ecs::Query<'w, 's, <Self as SealedMember>::ReadQueryData>>
200            {
201                queries.$table.as_ref()
202            }
203        }
204
205
206        impl ut::UTransactional for $member_type {
207            fn bind(
208                target: Handle<Self>,
209                transaction: Self::Transaction,
210            ) -> ut::UniverseTransaction {
211                ut::UniverseTransaction::from(AnyTransaction::$member_type(
212                    ut::TransactionInUniverse {
213                        target,
214                        transaction,
215                    },
216                ))
217            }
218        }
219    };
220}
221
222/// Generates data structures which cover all universe member types.
223macro_rules! member_enums_and_impls {
224    ( $( ($member_type:ident, $table_name:ident), )* ) => {
225        impl Universe {
226            /// Iterate over all members of this universe.
227            ///
228            /// The iteration order is currently not guaranteed.
229            pub fn iter(&self) -> impl Iterator<Item = AnyHandle> {
230                core::iter::empty()
231                $(
232                    .chain(self.iter_by_type::<$member_type>()
233                        .map(|(_name, handle)| AnyHandle::$member_type(handle)))
234                )*
235            }
236
237            pub(in crate::universe) fn register_all_member_components(world: &mut ecs::World) {
238                $(
239                    <$member_type as SealedMember>::register_all_member_components(world);
240                )*
241            }
242        }
243
244        /// Holds any one of the concrete [`Handle<T>`](Handle) types that can be in a [`Universe`].
245        ///
246        /// See also [`ErasedHandle`], which is implemented by `Handle`s rather than owning one.
247        /// This type dereferences to `dyn ErasedHandle` to provide all the operations that
248        /// trait does.
249        #[derive(Clone, Debug)]
250        #[non_exhaustive]
251        #[allow(missing_docs, reason = "variant meanings are obvious from name")]
252        pub enum AnyHandle {
253            $( $member_type(Handle<$member_type>), )*
254        }
255
256        impl AnyHandle {
257            /// For debugging — not guaranteed to be stable.
258            #[doc(hidden)] // TODO: not great API, but used by all-is-cubes-port
259            pub fn member_type_name(&self) -> &'static str {
260                 match self {
261                    $( AnyHandle::$member_type(_) => {
262                        core::any::type_name::<$member_type>()
263                    } )*
264                }
265            }
266
267            /// Used as part of checking whether a deserialized Universe contains bad handles.
268            #[cfg(feature = "save")]
269            pub(crate) fn not_still_deserializing(
270                &self,
271                read_ticket: $crate::universe::ReadTicket<'_>,
272            ) -> bool {
273                match self {
274                    $( AnyHandle::$member_type(h) => {
275                        !matches!(
276                            h.read(read_ticket),
277                            Err(handle_error) if matches!(
278                                handle_error.kind,
279                                $crate::universe::HandleErrorKind::NotReady,
280                            )
281                        )
282                    } )*
283                }
284            }
285
286            /// For deleting members.
287            pub(in crate::universe) fn set_state_to_gone(
288                &self,
289                reason: $crate::universe::GoneReason,
290            ) -> () {
291                match self {
292                    $( AnyHandle::$member_type(handle) => handle.set_state_to_gone(reason), )*
293                }
294            }
295
296            pub(in crate::universe) fn has_strong_handles(
297                &self,
298            ) -> bool {
299                match self {
300                    $( AnyHandle::$member_type(handle) => handle.has_strong_handles(), )*
301                }
302            }
303        }
304
305        impl core::ops::Deref for AnyHandle {
306            type Target = dyn ErasedHandle;
307
308            fn deref(&self) -> &Self::Target {
309                match self {
310                    $( Self::$member_type(r) => r, )*
311                }
312            }
313        }
314
315        $( impl_universe_for_member!($member_type, $table_name); )*
316
317        /// Polymorphic container for [`TransactionInUniverse`] which is
318        /// used to store transactions in a [`UniverseTransaction`].
319        #[derive(Clone, Default, PartialEq)]
320        #[non_exhaustive]
321        pub(in crate::universe) enum AnyTransaction {
322            #[default]
323            Noop,
324            $( $member_type(ut::TransactionInUniverse<$member_type>), )*
325        }
326
327        impl AnyTransaction {
328            pub(in crate::universe) fn target_erased(&self) -> Option<&dyn ErasedHandle> {
329                use AnyTransaction::*;
330                match self {
331                    Noop => None,
332                    $( $member_type(t) => Some(&t.target), )*
333                }
334            }
335
336            /// Returns the transaction out of the [`TransactionInUniverse`] wrapper.
337            pub(in crate::universe) fn transaction_as_debug(&self) -> &dyn fmt::Debug {
338                use AnyTransaction::*;
339                match self {
340                    Noop => &"AnyTransaction::Noop",
341                    $( Self::$member_type(t) => &t.transaction, )*
342                }
343            }
344        }
345
346        impl transaction::Transaction for AnyTransaction {
347            type Target = Universe;
348            type Context<'a> = ();
349            type CommitCheck = ut::AnyTransactionCheck;
350            type Output = transaction::NoOutput;
351            type Mismatch = AnyTransactionMismatch;
352
353            fn check(
354                &self,
355                universe: &Universe, (): Self::Context<'_>
356            ) -> Result<Self::CommitCheck, Self::Mismatch> {
357                Ok::<Self::CommitCheck, Self::Mismatch>(match self {
358                    Self::Noop => Box::new(()),
359                    $(
360                        Self::$member_type(t) => Box::new(t.check(universe, ())
361                            .map_err(AnyTransactionMismatch::$member_type)?),
362                    )*
363                })
364            }
365
366            fn commit(
367                self,
368                universe: &mut Universe,
369                check: Self::CommitCheck,
370                outputs: &mut dyn FnMut(Self::Output),
371            ) -> Result<(), transaction::CommitError> {
372                match self {
373                    Self::Noop => Ok(()),
374                    $( Self::$member_type(t) => ut::anytxn_commit_helper(t, universe, check, outputs), )*
375                }
376            }
377        }
378
379        impl transaction::Merge for AnyTransaction {
380            type MergeCheck = ut::AnyTransactionCheck;
381            type Conflict = AnyTransactionConflict;
382
383            fn check_merge(&self, other: &Self) -> Result<Self::MergeCheck, Self::Conflict> {
384                match (self, other) {
385                    (Self::Noop, _) => Ok(Box::new(())),
386                    (_, Self::Noop) => Ok(Box::new(())),
387                    $( (Self::$member_type(t1), Self::$member_type(t2)) => {
388                        let check =
389                            t1.check_merge(t2)
390                                .map_err(AnyTransactionConflict::$member_type)?;
391                        Ok(Box::new(check))
392                    } )*
393                    (_, _) => Err(AnyTransactionConflict::TypeMismatch),
394                }
395            }
396
397            fn commit_merge(&mut self, other: Self, check: Self::MergeCheck) {
398                match (self, other) {
399                    (_t1, Self::Noop) => {},
400                    (t1 @ Self::Noop, t2) => *t1 = t2,
401                    $( (Self::$member_type(t1), Self::$member_type(t2)) => {
402                        ut::anytxn_merge_helper(t1, t2, check)
403                    } )*
404                    (_, _) => panic!("Mismatched transaction target types"),
405                }
406            }
407        }
408
409        /// [`AnyTransaction`] precondition errors.
410        #[derive(Clone, Debug, Eq, PartialEq)]
411        #[non_exhaustive]
412        pub(in crate::universe) enum AnyTransactionMismatch {
413            $(
414                $member_type(
415                    <
416                        <$member_type as transaction::Transactional>::Transaction
417                        as transaction::Transaction
418                    >::Mismatch
419                ),
420            )*
421        }
422
423        /// [`AnyTransaction`] conflict errors.
424        #[derive(Clone, Debug, Eq, PartialEq)]
425        #[non_exhaustive]
426        pub(in crate::universe) enum AnyTransactionConflict {
427            TypeMismatch,
428            $(
429                $member_type(
430                    <
431                        <$member_type as transaction::Transactional>::Transaction
432                        as transaction::Merge
433                    >::Conflict
434                ),
435            )*
436        }
437
438            impl core::error::Error for AnyTransactionMismatch {
439                fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
440                    match self {
441                        $( Self::$member_type(e) => Some(e), )*
442                    }
443                }
444            }
445
446            impl core::error::Error for AnyTransactionConflict {
447                fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
448                    match self {
449                        Self::TypeMismatch => None,
450                        $( Self::$member_type(e) => Some(e), )*
451                    }
452                }
453            }
454
455        impl fmt::Display for AnyTransactionMismatch {
456            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457                match self {
458                    $( Self::$member_type(e) => e.fmt(f), )*
459                }
460            }
461        }
462        impl fmt::Display for AnyTransactionConflict {
463            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
464                match self {
465                    Self::TypeMismatch => write!(f, "Mismatched transaction target types"),
466                    $( Self::$member_type(e) => e.fmt(f), )*
467                }
468            }
469        }
470
471        /// Holds a pending handle and its value, to be inserted into a universe.
472        ///
473        /// There is no validation that the handle is in fact pending.
474        /// This type is used only within [`crate::universe::universe_txn::MemberTxn`].
475        pub(in crate::universe) enum AnyPending {
476            $(
477                $member_type {
478                    handle: Handle<$member_type>,
479
480                    /// Handle’s value, if it has been provided yet.
481                    /// Insertion always fails if `None`.
482                    ///
483                    /// Boxed so that the size of the enum isn't the size of the largest member type
484                    value: Option<Box<$member_type>>,
485                },
486            )*
487        }
488
489        impl AnyPending {
490            pub(crate) fn handle(&self) -> &dyn ErasedHandle {
491                match self {
492                    $( AnyPending::$member_type { handle, .. } => handle, )*
493                }
494            }
495
496            /// Returns whether this does not yet belong to a universe and can start
497            /// doing so. Used by [`MemberTxn::check()`].
498            ///
499            /// See [`Handle::check_upgrade_pending()`] for more information.
500            pub(crate) fn check_upgrade_pending(
501                &self,
502                read_ticket_for_self: $crate::universe::ReadTicket<'_>,
503                universe_id: $crate::universe::UniverseId,
504            ) -> Result<(), $crate::universe::InsertError> {
505                match self {
506                    $(
507                        Self::$member_type { handle, value: _ } => {
508                            handle.check_upgrade_pending(read_ticket_for_self, universe_id)
509                        }
510                    )*
511                }
512            }
513
514            /// Returns a reference to a `dyn Any` whose underlying type is the owned
515            /// `Option<Box<T>>`.
516            pub(crate) fn value_as_any_option_box(&self) -> &dyn Any {
517                match self {
518                    $(
519                        Self::$member_type { handle: _, value } => value,
520                    )*
521                }
522            }
523            /// Returns a reference to a `dyn Any` whose underlying type is the owned
524            /// `Option<Box<T>>`.
525            pub(crate) fn value_as_mut_any_option_box(&mut self) -> &mut dyn Any {
526                match self {
527                    $(
528                        Self::$member_type { handle: _, value } => value,
529                    )*
530                }
531            }
532
533            /// Used by [`MemberTxn::commit()`] to perform inserts.
534            pub(crate) fn insert_pending_into_universe(
535                self,
536                universe: &mut Universe
537            ) -> Result<(), InsertError> {
538                match self {
539                    $(
540                        AnyPending::$member_type { handle, value } => {
541                            if let Some(value) = value {
542                                handle.insert_pending_into_universe(universe, value)
543                            } else {
544                                Err(InsertError {
545                                    name: handle.name(),
546                                    kind: $crate::universe::InsertErrorKind::ValueMissing,
547                                })
548                            }
549
550                        }
551                    )*
552                }
553            }
554        }
555
556        impl fmt::Debug for AnyPending {
557            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
558                write!(f, "{:?} = ", self.handle())?;
559                match self {
560                    $(
561                        Self::$member_type { handle: _, value: Some(value) } => {
562                            value.fmt(f)?;
563                        },
564                    )*
565                    $( Self::$member_type { handle: _, value: None } )|* => {
566                        write!(f, "<value not set>")?;
567                    }
568                }
569                Ok(())
570            }
571        }
572
573        impl PartialEq for AnyPending {
574            fn eq(&self, rhs: &Self) -> bool {
575                match (self, rhs) {
576                    $(
577                        (
578                            AnyPending::$member_type { handle: h1, value: _ },
579                            AnyPending::$member_type { handle: h2, value: _ },
580                        ) => {
581                            // It should be impossible for two `AnyPending`s with the same handle
582                            // to exist, and the value may not implement `PartialEq`, so we don't.
583                            h1 == h2
584                        }
585                    )*
586                    (_, _) => false,
587                }
588            }
589        }
590        impl Eq for AnyPending {}
591
592        /// Queries for reading members, sometimes used by [`Handle::read()`].
593        /// Contains one `QueryState` per member type, whose `QueryData` is that member's
594        /// `UniverseMember::Read`.
595        #[derive(ecs::FromWorld)]
596        #[macro_rules_attribute::derive($crate::universe::ecs_details::derive_manual_query_bundle!)]
597        pub(crate) struct MemberReadQueryStates {
598            $(
599                pub(in crate::universe) $table_name:
600                    ::bevy_ecs::query::QueryState<
601                        <$member_type as universe::SealedMember>::ReadQueryData
602                    >,
603            )*
604        }
605
606        impl MemberReadQueryStates {
607        #[expect(dead_code, reason = "TODO(ecs): going to use this in systems")]
608            pub fn query_manual<'w, 's>(
609                &'s self,
610                world: &'w ecs::World,
611            ) -> MemberReadQueries<'w, 's> {
612                MemberReadQueries {
613                    universe_id: *world.resource(),
614                    $(
615                        $table_name:
616                            Some(self.$table_name.query_manual(world)),
617                    )*
618                }
619            }
620        }
621
622        /// Queries for mutating members, used by transaction commits.
623        /// Contains one `QueryState` per member type, whose `QueryData` is that member's
624        /// `TransactionOnEcs::WriteQueryData`.
625        #[derive(ecs::FromWorld)]
626        #[macro_rules_attribute::derive($crate::universe::ecs_details::derive_manual_query_bundle!)]
627        pub(in crate::universe) struct MemberWriteQueryStates {
628            $(
629                pub(in crate::universe) $table_name:
630                    ::bevy_ecs::query::QueryState<
631                        <
632                            <$member_type as universe::Transactional>::Transaction
633                            as universe::TransactionOnEcs
634                        >::WriteQueryData
635                    >,
636            )*
637        }
638
639        /// Queries for reading members, sometimes used by [`Handle::read()`].
640        /// Contains one optional `Query` per member type, whose `QueryData` is that member's
641        /// `UniverseMember::Read`.
642        ///
643        /// Each query is optional so as to enable constructing this with a variety of different
644        /// amounts of access from different systems.
645        ///
646        /// To obtain this, either:
647        ///
648        /// * Use [`AllMemberReadQueries`] as a system parameter, or
649        /// * Call [`MemberReadQueries::query_manuql()`].
650        pub(crate) struct MemberReadQueries<'w, 's> {
651            pub(crate) universe_id: universe::UniverseId,
652            $(
653                pub(crate) $table_name:
654                    ::core::option::Option<::bevy_ecs::prelude::Query<'w, 's,
655                        <$member_type as universe::SealedMember>::ReadQueryData
656                    >>,
657            )*
658        }
659
660        /// System parameter that constructs a [`MemberReadQueries`].
661        #[derive(bevy_ecs::system::SystemParam)]
662        pub(crate) struct AllMemberReadQueries<'w, 's> {
663            pub(crate) universe_id: ecs::Res<'w, universe::UniverseId>,
664            $(
665                pub(crate) $table_name:
666                    ::bevy_ecs::prelude::Query<'w, 's,
667                        <$member_type as universe::SealedMember>::ReadQueryData
668                    >,
669            )*
670        }
671
672        impl<'w, 's> AllMemberReadQueries<'w, 's> {
673            pub fn get(self) -> MemberReadQueries<'w, 's> {
674                MemberReadQueries {
675                    universe_id: *self.universe_id,
676                    $(
677                        $table_name: Some(self.$table_name),
678                    )*
679                }
680            }
681        }
682    }
683}
684
685// This macro does not handle everything.
686// To add another type, it is also necessary to update:
687//    Universe::delete
688//    Universe::gc
689//    Universe::step (if the members do anything on step)
690//    struct PartialUniverse
691//    impl Serialize for PartialUniverse
692//    save::schema::MemberSer
693//    transaction::universe_txn::*
694// TODO(ecs): The above comment is stale.
695member_enums_and_impls!(
696    (BlockDef, blocks),
697    (Character, characters),
698    (SoundDef, sounds),
699    (Space, spaces),
700    (TagDef, tags),
701);
702
703// -------------------------------------------------------------------------------------------------
704
705impl AnyHandle {
706    /// Downcast to a specific `Handle<T>` type.
707    pub fn downcast_ref<T: 'static>(&self) -> Option<&Handle<T>> {
708        let handle: &dyn ErasedHandle = self.as_ref();
709        let handle: &dyn Any = handle;
710        handle.downcast_ref()
711    }
712
713    /// Downcast to a specific `Handle<T>` type.
714    pub fn downcast<T: 'static>(self) -> Result<Handle<T>, AnyHandle> {
715        // TODO: implement this more efficiently, without the clone
716        // (note that `Box`ing to use `Box<dyn Any>` downcasting is *not* more efficient)
717        match self.downcast_ref() {
718            Some(handle) => Ok(handle.clone()),
719            None => Err(self),
720        }
721    }
722}
723
724impl AsRef<dyn ErasedHandle> for AnyHandle {
725    fn as_ref(&self) -> &dyn ErasedHandle {
726        &**self
727    }
728}
729impl core::borrow::Borrow<dyn ErasedHandle> for AnyHandle {
730    fn borrow(&self) -> &dyn ErasedHandle {
731        &**self
732    }
733}
734
735impl HandlePtr for AnyHandle {
736    fn as_erased_shared_pointer(&self) -> *const () {
737        let r: &dyn ErasedHandle = &**self;
738        r.as_erased_shared_pointer()
739    }
740}
741
742impl ErasedHandle for AnyHandle {
743    fn name(&self) -> Name {
744        let r: &dyn ErasedHandle = &**self;
745        r.name()
746    }
747
748    fn universe_id(&self) -> Option<super::UniverseId> {
749        let r: &dyn ErasedHandle = &**self;
750        r.universe_id()
751    }
752
753    fn as_entity(
754        &self,
755        expected_universe: super::UniverseId,
756    ) -> Result<ecs::Entity, universe::handle::HandleError> {
757        let r: &dyn ErasedHandle = &**self;
758        r.as_entity(expected_universe)
759    }
760
761    fn to_any_handle(&self) -> AnyHandle {
762        self.clone()
763    }
764}
765
766impl PartialEq for AnyHandle {
767    fn eq(&self, other: &AnyHandle) -> bool {
768        self.as_erased_shared_pointer() == other.as_erased_shared_pointer()
769    }
770}
771impl Eq for AnyHandle {}
772impl hash::Hash for AnyHandle {
773    fn hash<H: hash::Hasher>(&self, state: &mut H) {
774        // Must agree with `Hash for Handle` and `Hash for dyn ErasedHandle`
775        self.as_erased_shared_pointer().hash(state);
776    }
777}
778
779impl PartialEq<dyn ErasedHandle> for AnyHandle {
780    fn eq(&self, other: &dyn ErasedHandle) -> bool {
781        self.as_erased_shared_pointer() == other.as_erased_shared_pointer()
782    }
783}
784impl hashbrown::Equivalent<AnyHandle> for dyn ErasedHandle {
785    fn equivalent(&self, other: &AnyHandle) -> bool {
786        self.as_erased_shared_pointer() == other.as_erased_shared_pointer()
787    }
788}
789
790impl<T> PartialEq<Handle<T>> for AnyHandle
791where
792    Handle<T>: HandlePtr,
793{
794    fn eq(&self, other: &Handle<T>) -> bool {
795        self.as_erased_shared_pointer() == other.as_erased_shared_pointer()
796    }
797}
798impl<T> PartialEq<AnyHandle> for Handle<T>
799where
800    Handle<T>: HandlePtr,
801{
802    fn eq(&self, other: &AnyHandle) -> bool {
803        *other == *self
804    }
805}
806
807// TODO: we can get rid of this if we arrange to have a version of `MemberReadQueryStates` that carries `Query` instead of `QueryState`
808impl bevy_ecs::system::ExclusiveSystemParam for &mut MemberReadQueryStates {
809    type State = MemberReadQueryStates;
810    type Item<'s> = &'s mut MemberReadQueryStates;
811
812    fn init(world: &mut ecs::World, _: &mut bevy_ecs::system::SystemMeta) -> Self::State {
813        <MemberReadQueryStates as bevy_ecs::world::FromWorld>::from_world(world)
814    }
815
816    fn get_param<'s>(
817        state: &'s mut Self::State,
818        _: &bevy_ecs::system::SystemMeta,
819    ) -> Self::Item<'s> {
820        state
821    }
822}