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}