Skip to main content

bevy_ecs/change_detection/
maybe_location.rs

1#[cfg(feature = "bevy_reflect")]
2use bevy_reflect::Reflect;
3use core::{
4    marker::PhantomData,
5    ops::{Deref, DerefMut},
6    panic::Location,
7};
8
9/// A value that contains a `T` if the `track_location` feature is enabled,
10/// and is a ZST if it is not.
11///
12/// The overall API is similar to [`Option`], but whether the value is `Some` or `None` is set at compile
13/// time and is the same for all values.
14///
15/// If the `track_location` feature is disabled, then all functions on this type that return
16/// an `MaybeLocation` will have an empty body and should be removed by the optimizer.
17///
18/// This allows code to be written that will be checked by the compiler even when the feature is disabled,
19/// but that will be entirely removed during compilation.
20#[cfg_attr(feature = "bevy_reflect", derive(const _: () =
    {
        impl<T: ?Sized> bevy_reflect::GetTypeRegistration for MaybeLocation<T>
            where MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert(<bevy_reflect::ReflectFromPtr as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration.insert(<bevy_reflect::ReflectFromReflect as
                            bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <T as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl<T: ?Sized> bevy_reflect::Typed for MaybeLocation<T> where
            MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            #[inline(never)]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::GenericTypeInfoCell =
                    bevy_reflect::utility::GenericTypeInfoCell::new();
                CELL.get_or_insert::<Self,
                    _>(#[inline(never)] ||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<T>("value")]).with_generics(bevy_reflect::Generics::from_iter([bevy_reflect::GenericInfo::Type(bevy_reflect::TypeParamInfo::new::<T>(bevy_reflect::__macro_exports::alloc_utils::Cow::Borrowed("T")).with_default::<&'static Location<'static>>())])))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl<T: ?Sized> bevy_reflect::TypePath for MaybeLocation<T> where
            MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath {
            fn type_path() -> &'static str {
                static CELL: bevy_reflect::utility::GenericTypePathCell =
                    bevy_reflect::utility::GenericTypePathCell::new();
                CELL.get_or_insert::<Self,
                    _>(#[inline(never)] ||
                        {
                            ::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("bevy_ecs::change_detection::maybe_location::MaybeLocation<"),
                                    <T as bevy_reflect::TypePath>::type_path()), ">")
                        })
            }
            fn short_type_path() -> &'static str {
                static CELL: bevy_reflect::utility::GenericTypePathCell =
                    bevy_reflect::utility::GenericTypePathCell::new();
                CELL.get_or_insert::<Self,
                    _>(#[inline(never)] ||
                        {
                            ::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("MaybeLocation<"),
                                    <T as bevy_reflect::TypePath>::short_type_path()), ">")
                        })
            }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("MaybeLocation")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_ecs::change_detection::maybe_location".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_ecs::change_detection::maybe_location")
            }
        }
        impl<T: ?Sized> bevy_reflect::Reflect for MaybeLocation<T> where
            MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        impl<T: ?Sized> bevy_reflect::func::args::GetOwnership for
            MaybeLocation<T> where MaybeLocation<T>: ::core::any::Any +
            ::core::marker::Send + ::core::marker::Sync,
            T: bevy_reflect::TypePath, T: bevy_reflect::FromReflect +
            bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            fn ownership() -> bevy_reflect::func::args::Ownership {
                bevy_reflect::func::args::Ownership::Owned
            }
        }
        impl<T: ?Sized> bevy_reflect::func::args::FromArg for MaybeLocation<T>
            where MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            type This<'from_arg> = MaybeLocation<T>;
            fn from_arg(arg: bevy_reflect::func::args::Arg)
                ->
                    ::core::result::Result<Self::This<'_>,
                    bevy_reflect::func::args::ArgError> {
                arg.take_owned()
            }
        }
        impl<T: ?Sized> bevy_reflect::func::IntoReturn for MaybeLocation<T>
            where MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            fn into_return<'into_return>(self)
                -> bevy_reflect::func::Return<'into_return> where
                Self: 'into_return {
                bevy_reflect::func::Return::Owned(bevy_reflect::__macro_exports::alloc_utils::Box::new(self))
            }
        }
        impl<T: ?Sized> bevy_reflect::structs::Struct for MaybeLocation<T>
            where MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "value" => ::core::option::Option::Some(&self.value),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "value" => ::core::option::Option::Some(&mut self.value),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.value),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.value),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("value"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "value" => ::core::option::Option::Some(0usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 1usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                ->
                    ::core::result::Result<bevy_reflect::structs::DynamicStruct,
                    bevy_reflect::ReflectCloneError> {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("value",
                    bevy_reflect::PartialReflect::to_dynamic(&self.value)?);
                ::core::result::Result::Ok(dynamic)
            }
        }
        impl<T: ?Sized> bevy_reflect::PartialReflect for MaybeLocation<T>
            where MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            #[inline]
            #[allow(unreachable_code, reason =
            "Ignored fields without a `clone` attribute will early-return with an error")]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(Self {
                            marker: ::core::clone::Clone::clone(&self.marker),
                            value: <T as
                                        bevy_reflect::PartialReflect>::reflect_clone_and_take(&self.value)?,
                        }))
            }
        }
        impl<T: ?Sized> bevy_reflect::FromReflect for MaybeLocation<T> where
            MaybeLocation<T>: ::core::any::Any + ::core::marker::Send +
            ::core::marker::Sync, T: bevy_reflect::TypePath,
            T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
            bevy_reflect::MaybeTyped +
            bevy_reflect::__macro_exports::RegisterForReflection {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let __this =
                        Self {
                            value: <T as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "value")?)?,
                            marker: ::core::default::Default::default(),
                        };
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect))]
21#[derive(#[automatically_derived]impl<T: ::core::marker::Copy + ?Sized>
    ::core::marker::Copy for MaybeLocation<T> {
}Copy, #[automatically_derived]impl<T: ::core::clone::Clone + ?Sized>
    ::core::clone::Clone for MaybeLocation<T> {
    #[inline]
    fn clone(&self) -> Self {
        MaybeLocation {
            marker: ::core::clone::Clone::clone(&self.marker),
            value: ::core::clone::Clone::clone(&self.value),
        }
    }
}Clone, #[automatically_derived]impl<T: ::core::fmt::Debug + ?Sized>
    ::core::fmt::Debug for MaybeLocation<T> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "MaybeLocation",
            "marker", &self.marker, "value", &&self.value)
    }
}Debug, #[automatically_derived]impl<T: ::core::cmp::Eq + ?Sized> ::core::cmp::Eq for
    MaybeLocation<T> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<PhantomData<T>>;
        let _: ::core::cmp::AssertParamIsEq<T>;
    }
}Eq, #[automatically_derived]impl<T: ::core::hash::Hash + ?Sized>
    ::core::hash::Hash for MaybeLocation<T> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.marker, state);
        ::core::hash::Hash::hash(&self.value, state)
    }
}Hash, #[automatically_derived]impl<T: ::core::cmp::Ord + ?Sized> ::core::cmp::Ord
    for MaybeLocation<T> {
    #[inline]
    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.marker, &other.marker) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.value, &other.value),
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]impl<T: ::core::cmp::PartialEq + ?Sized>
    ::core::marker::StructuralPartialEq for MaybeLocation<T> {
}
#[automatically_derived]impl<T: ::core::cmp::PartialEq + ?Sized>
    ::core::cmp::PartialEq for MaybeLocation<T> {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.marker == other.marker && self.value == other.value
    }
}PartialEq, #[automatically_derived]impl<T: ::core::cmp::PartialOrd + ?Sized>
    ::core::cmp::PartialOrd for MaybeLocation<T> {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.marker,
                &other.marker) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.value,
                    &other.value),
            cmp => cmp,
        }
    }
}PartialOrd)]
22pub struct MaybeLocation<T: ?Sized = &'static Location<'static>> {
23    #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
24    marker: PhantomData<T>,
25    #[cfg(feature = "track_location")]
26    value: T,
27}
28
29impl<T: core::fmt::Display> core::fmt::Display for MaybeLocation<T> {
30    fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        #[cfg(feature = "track_location")]
32        {
33            self.value.fmt(_f)?;
34        }
35        Ok(())
36    }
37}
38
39impl<T> MaybeLocation<T> {
40    /// Constructs a new `MaybeLocation` that wraps the given value.
41    ///
42    /// This may only accept `Copy` types,
43    /// since it needs to drop the value if the `track_location` feature is disabled,
44    /// and non-`Copy` types cannot be dropped in `const` context.
45    /// Use [`new_with`][Self::new_with] if you need to construct a non-`Copy` value.
46    ///
47    /// # See also
48    /// - [`new_with`][Self::new_with] to initialize using a closure.
49    /// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.
50    #[inline]
51    pub const fn new(_value: T) -> Self
52    where
53        T: Copy,
54    {
55        Self {
56            #[cfg(feature = "track_location")]
57            value: _value,
58            marker: PhantomData,
59        }
60    }
61
62    /// Constructs a new `MaybeLocation` that wraps the result of the given closure.
63    ///
64    /// # See also
65    /// - [`new`][Self::new] to initialize using a value.
66    /// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.
67    #[inline]
68    pub fn new_with(_f: impl FnOnce() -> T) -> Self {
69        Self {
70            #[cfg(feature = "track_location")]
71            value: _f(),
72            marker: PhantomData,
73        }
74    }
75
76    /// Maps an `MaybeLocation<T> `to `MaybeLocation<U>` by applying a function to a contained value.
77    #[inline]
78    pub fn map<U>(self, _f: impl FnOnce(T) -> U) -> MaybeLocation<U> {
79        MaybeLocation {
80            #[cfg(feature = "track_location")]
81            value: _f(self.value),
82            marker: PhantomData,
83        }
84    }
85
86    /// Converts a pair of `MaybeLocation` values to an `MaybeLocation` of a tuple.
87    #[inline]
88    pub fn zip<U>(self, _other: MaybeLocation<U>) -> MaybeLocation<(T, U)> {
89        MaybeLocation {
90            #[cfg(feature = "track_location")]
91            value: (self.value, _other.value),
92            marker: PhantomData,
93        }
94    }
95
96    /// Returns the contained value or a default.
97    /// If the `track_location` feature is enabled, this always returns the contained value.
98    /// If it is disabled, this always returns `T::Default()`.
99    #[inline]
100    pub fn unwrap_or_default(self) -> T
101    where
102        T: Default,
103    {
104        self.into_option().unwrap_or_default()
105    }
106
107    /// Converts an `MaybeLocation` to an [`Option`] to allow run-time branching.
108    /// If the `track_location` feature is enabled, this always returns `Some`.
109    /// If it is disabled, this always returns `None`.
110    #[inline]
111    pub fn into_option(self) -> Option<T> {
112        #[cfg(feature = "track_location")]
113        {
114            Some(self.value)
115        }
116        #[cfg(not(feature = "track_location"))]
117        {
118            None
119        }
120    }
121}
122
123impl<T> MaybeLocation<Option<T>> {
124    /// Constructs a new `MaybeLocation` that wraps the result of the given closure.
125    /// If the closure returns `Some`, it unwraps the inner value.
126    ///
127    /// # See also
128    /// - [`new`][Self::new] to initialize using a value.
129    /// - [`new_with`][Self::new_with] to initialize using a closure.
130    #[inline]
131    pub fn new_with_flattened(_f: impl FnOnce() -> Option<MaybeLocation<T>>) -> Self {
132        Self {
133            #[cfg(feature = "track_location")]
134            value: _f().map(|value| value.value),
135            marker: PhantomData,
136        }
137    }
138
139    /// Transposes a `MaybeLocation` of an [`Option`] into an [`Option`] of a `MaybeLocation`.
140    ///
141    /// This can be useful if you want to use the `?` operator to exit early
142    /// if the `track_location` feature is enabled but the value is not found.
143    ///
144    /// If the `track_location` feature is enabled,
145    /// this returns `Some` if the inner value is `Some`
146    /// and `None` if the inner value is `None`.
147    ///
148    /// If it is disabled, this always returns `Some`.
149    ///
150    /// # Example
151    ///
152    /// ```
153    /// # use bevy_ecs::{change_detection::MaybeLocation, world::World};
154    /// # use core::panic::Location;
155    /// #
156    /// # fn test() -> Option<()> {
157    /// let mut world = World::new();
158    /// let entity = world.spawn(()).id();
159    /// let location: MaybeLocation<Option<&'static Location<'static>>> =
160    ///     world.entities().entity_get_spawned_or_despawned_by(entity);
161    /// let location: MaybeLocation<&'static Location<'static>> = location.transpose()?;
162    /// # Some(())
163    /// # }
164    /// # test();
165    /// ```
166    ///
167    /// # See also
168    ///
169    /// - [`into_option`][Self::into_option] to convert to an `Option<Option<T>>`.
170    ///   When used with [`Option::flatten`], this will have a similar effect,
171    ///   but will return `None` when the `track_location` feature is disabled.
172    #[inline]
173    pub fn transpose(self) -> Option<MaybeLocation<T>> {
174        #[cfg(feature = "track_location")]
175        {
176            self.value.map(|value| MaybeLocation {
177                value,
178                marker: PhantomData,
179            })
180        }
181        #[cfg(not(feature = "track_location"))]
182        {
183            Some(MaybeLocation {
184                marker: PhantomData,
185            })
186        }
187    }
188}
189
190impl<T> MaybeLocation<&T> {
191    /// Maps an `MaybeLocation<&T>` to an `MaybeLocation<T>` by copying the contents.
192    #[inline]
193    pub const fn copied(&self) -> MaybeLocation<T>
194    where
195        T: Copy,
196    {
197        MaybeLocation {
198            #[cfg(feature = "track_location")]
199            value: *self.value,
200            marker: PhantomData,
201        }
202    }
203}
204
205impl<T> MaybeLocation<&mut T> {
206    /// Maps an `MaybeLocation<&mut T>` to an `MaybeLocation<T>` by copying the contents.
207    #[inline]
208    pub const fn copied(&self) -> MaybeLocation<T>
209    where
210        T: Copy,
211    {
212        MaybeLocation {
213            #[cfg(feature = "track_location")]
214            value: *self.value,
215            marker: PhantomData,
216        }
217    }
218
219    /// Assigns the contents of an `MaybeLocation<T>` to an `MaybeLocation<&mut T>`.
220    #[inline]
221    pub fn assign(&mut self, _value: MaybeLocation<T>) {
222        #[cfg(feature = "track_location")]
223        {
224            *self.value = _value.value;
225        }
226    }
227}
228
229impl<T: ?Sized> MaybeLocation<T> {
230    /// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T>`.
231    #[inline]
232    pub const fn as_ref(&self) -> MaybeLocation<&T> {
233        MaybeLocation {
234            #[cfg(feature = "track_location")]
235            value: &self.value,
236            marker: PhantomData,
237        }
238    }
239
240    /// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T>`.
241    #[inline]
242    pub const fn as_mut(&mut self) -> MaybeLocation<&mut T> {
243        MaybeLocation {
244            #[cfg(feature = "track_location")]
245            value: &mut self.value,
246            marker: PhantomData,
247        }
248    }
249
250    /// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T::Target>`.
251    #[inline]
252    pub fn as_deref(&self) -> MaybeLocation<&T::Target>
253    where
254        T: Deref,
255    {
256        MaybeLocation {
257            #[cfg(feature = "track_location")]
258            value: &*self.value,
259            marker: PhantomData,
260        }
261    }
262
263    /// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T::Target>`.
264    #[inline]
265    pub fn as_deref_mut(&mut self) -> MaybeLocation<&mut T::Target>
266    where
267        T: DerefMut,
268    {
269        MaybeLocation {
270            #[cfg(feature = "track_location")]
271            value: &mut *self.value,
272            marker: PhantomData,
273        }
274    }
275}
276
277impl MaybeLocation {
278    /// Returns the source location of the caller of this function. If that function's caller is
279    /// annotated then its call location will be returned, and so on up the stack to the first call
280    /// within a non-tracked function body.
281    #[inline]
282    #[track_caller]
283    pub const fn caller() -> Self {
284        // Note that this cannot use `new_with`, since `FnOnce` invocations cannot be annotated with `#[track_caller]`.
285        MaybeLocation {
286            #[cfg(feature = "track_location")]
287            value: Location::caller(),
288            marker: PhantomData,
289        }
290    }
291}