cuicui_reflect_query/
custom_ref.rs

1//! Define [`Ref`], a custom version of bevy's [`Ref`](BRef) that can be
2//! constructed from `EntityRef` and mapped over.
3use std::ops::Deref;
4
5use bevy::prelude::{DetectChanges, Ref as BRef};
6
7/// A custom version of bevy's [`Ref`](BRef) that can be
8/// constructed from `EntityRef` and mapped over.
9///
10/// Due to a limitation in bevy, it's impossible to use the bevy `Ref` for this crate.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Ref<'w, T: ?Sized> {
13    pub(crate) value: &'w T,
14    pub(crate) is_added: bool,
15    pub(crate) is_changed: bool,
16}
17impl<'w, T: ?Sized> Ref<'w, T> {
18    /// Was this added since last time the system this is called from ran?
19    #[must_use]
20    pub const fn is_added(&self) -> bool {
21        self.is_added
22    }
23    /// Was this changed since last time the system this is called from ran?
24    #[must_use]
25    pub const fn is_changed(&self) -> bool {
26        self.is_changed
27    }
28    /// Return the inner reference with its full lifetime.
29    ///
30    /// Rust's [`Deref`] trait can't produce references with a lifetime longer
31    /// than that of the `Ref` itself (with `&'a Ref<'w>`, the lifetime will
32    /// always be `'a`).
33    ///
34    /// This can become an issue in certain scenarios, this is why this method
35    /// exists.
36    ///
37    /// Note that since `Ref` is `Copy`, this **doesn't** consume the value, you
38    /// can keep using it.
39    #[must_use]
40    pub const fn into_inner(self) -> &'w T {
41        self.value
42    }
43    /// Apply a function `f` returning a result to the inner value,
44    /// and get a `Ref` with the return value of that function.
45    /// Returning `Err` if `f` returns `Err`.
46    ///
47    /// # Errors
48    /// Returns `Err` if `f` returns `Err`.
49    pub fn map_failable<E, U: ?Sized>(
50        self,
51        f: impl FnOnce(&T) -> Result<&U, E>,
52    ) -> Result<Ref<'w, U>, E> {
53        Ok(Ref {
54            value: f(self.value)?,
55            is_added: self.is_added,
56            is_changed: self.is_changed,
57        })
58    }
59    /// Apply a function `f` to the inner value,
60    /// and get a `Ref` with the return value of that function.
61    #[must_use]
62    pub fn map<U: ?Sized>(self, f: impl FnOnce(&T) -> &U) -> Ref<'w, U> {
63        Ref {
64            value: f(self.value),
65            is_added: self.is_added,
66            is_changed: self.is_changed,
67        }
68    }
69    /// Convert a bevy [`Ref`](BRef) into a `reflect_query` `Ref`, applying
70    /// a function while converting it.
71    ///
72    /// You can pass `|i| i` as function if you don't wish to convert the value.
73    #[must_use]
74    pub fn map_from<U: ?Sized>(bevy: BRef<'w, U>, f: impl FnOnce(&U) -> &T) -> Self {
75        Ref {
76            is_added: bevy.is_added(),
77            is_changed: bevy.is_changed(),
78            value: f(bevy.into_inner()),
79        }
80    }
81}
82impl<'w, T: ?Sized> From<BRef<'w, T>> for Ref<'w, T> {
83    fn from(value: BRef<'w, T>) -> Self {
84        Ref::map_from(value, |i| i)
85    }
86}
87impl<'w, T: ?Sized> AsRef<T> for Ref<'w, T> {
88    fn as_ref(&self) -> &T {
89        self.value
90    }
91}
92impl<'w, T: ?Sized> Deref for Ref<'w, T> {
93    type Target = T;
94
95    fn deref(&self) -> &Self::Target {
96        self.value
97    }
98}
99impl<'w, 'a, T> IntoIterator for &'a Ref<'w, T>
100where
101    &'a T: IntoIterator,
102{
103    type Item = <&'a T as IntoIterator>::Item;
104    type IntoIter = <&'a T as IntoIterator>::IntoIter;
105
106    fn into_iter(self) -> Self::IntoIter {
107        self.value.into_iter()
108    }
109}