moonshine_object/
rebind.rs

1use bevy_ecs::prelude::*;
2use moonshine_kind::{prelude::*, Any, CastInto};
3
4use crate::{Object, ObjectHierarchy, ObjectInstance, ObjectRef};
5
6pub trait ObjectRebind<T: Kind = Any>: ObjectInstance<T> + Sized {
7    type Rebind<U: Kind>: ObjectHierarchy<U>;
8
9    /// Rebinds this object to an [`Instance`] of another [`Kind`].
10    ///
11    /// # Usage
12    ///
13    /// This is useful when you have an [`Object<T>`] and an [`Instance<U>`]
14    /// but you want an [`Object<U>`].
15    ///
16    /// # Example
17    /// ```
18    /// # use bevy::prelude::*;
19    /// # use moonshine_object::prelude::*;
20    /// # use moonshine_kind::prelude::*;
21    ///
22    /// #[derive(Component)]
23    /// struct Apple {
24    ///     worms: Vec<Instance<Worm>>,
25    /// }
26    ///
27    /// #[derive(Component)]
28    /// struct Worm;
29    ///
30    /// let mut app = App::new();
31    /// // ...
32    /// app.add_systems(Update, find_worms);
33    ///
34    /// fn find_worms(apples: Objects<Apple>, query: Query<&Apple>) {
35    ///     for object in apples.iter() {
36    ///         let apple = query.get(object.entity()).unwrap();
37    ///         for worm in apple.worms.iter() {
38    ///             handle_worm(object.rebind_as(*worm));
39    ///         }
40    ///     }
41    /// }
42    ///
43    /// fn handle_worm(worm: Object<Worm>) {
44    ///     println!("{:?} found! Gross!", worm);
45    /// }
46    /// ```
47    fn rebind_as<U: Kind>(&self, instance: Instance<U>) -> Self::Rebind<U>;
48
49    /// Rebinds this object to another [`Instance`] of the same [`Kind`].
50    ///
51    /// # Usage
52    ///
53    /// This is useful when you have an [`Object<T>`] and another [`Instance<T>`]
54    /// but you want another [`Object<T>`].
55    ///
56    /// # Example
57    /// ```
58    /// # use bevy::prelude::*;
59    /// # use moonshine_object::prelude::*;
60    /// # use moonshine_kind::prelude::*;
61    ///
62    /// #[derive(Component)]
63    /// struct Person {
64    ///     friends: Vec<Instance<Person>>,
65    /// }
66    ///
67    /// let mut app = App::new();
68    /// // ...
69    /// app.add_systems(Update, update_friends);
70    ///
71    /// fn update_friends(people: Objects<Person>, query: Query<&Person>) {
72    ///     for object in people.iter() {
73    ///         let person = query.get(object.entity()).unwrap();
74    ///         for friend in person.friends.iter() {
75    ///             greet_friend(object.rebind(*friend));
76    ///         }
77    ///     }
78    /// }
79    ///
80    /// fn greet_friend(friend: Object<Person>) {
81    ///     println!("Hello {:?}!", friend);
82    /// }
83    /// ```
84    fn rebind(&self, instance: Instance<T>) -> Self::Rebind<T> {
85        self.rebind_as(instance)
86    }
87
88    /// Rebinds this object to another [`Entity`].
89    ///
90    /// # Usage
91    ///
92    /// This is useful when you have an [`Object<T>`] but you want an [`Object`] for a different [`Entity`].
93    fn rebind_any(&self, entity: Entity) -> Self::Rebind<Any> {
94        self.rebind_as(Instance::from(entity))
95    }
96
97    /// Casts this object into another of a related [`Kind`].
98    ///
99    /// # Usage
100    ///
101    /// This is useful when you have an [`Object<T>`] but you want an [`Object<U>`]
102    /// where [`Kind`] `T` is safely convertible to `U`.
103    ///
104    /// See [`kind!`] for more information on kind conversion.
105    ///
106    /// # Example
107    /// ```
108    /// # use bevy::prelude::*;
109    /// # use moonshine_object::prelude::*;
110    /// # use moonshine_kind::prelude::*;
111    ///
112    /// #[derive(Component)]
113    /// struct Apple;
114    ///
115    /// #[derive(Component)]
116    /// struct Orange;
117    ///
118    /// struct Fruit;
119    ///
120    /// impl Kind for Fruit {
121    ///     // Apples and Oranges are fruits.
122    ///     type Filter = Or<(With<Apple>, With<Orange>)>;
123    /// }
124    ///
125    /// // Define related kinds:
126    /// kind!(Apple is Fruit);
127    /// kind!(Orange is Fruit);
128    ///
129    /// let mut app = App::new();
130    /// // ...
131    /// app.add_systems(Update, (eat_apples, eat_oranges));
132    ///
133    /// fn eat_apples(apples: Objects<Apple>) {
134    ///     for apple in apples.iter() {
135    ///         eat_fruit(apple.cast_into());
136    ///         println!("Crunchy!")
137    ///     }
138    /// }
139    ///
140    /// fn eat_oranges(oranges: Objects<Orange>) {
141    ///     for orange in oranges.iter() {
142    ///         eat_fruit(orange.cast_into());
143    ///         println!("Juicy!")
144    ///     }
145    /// }
146    ///
147    /// fn eat_fruit(fruit: Object<Fruit>) {
148    ///     println!("{:?} is eaten!", fruit);
149    /// }
150    /// ```
151    fn cast_into<U: Kind>(self) -> Self::Rebind<U>
152    where
153        T: CastInto<U>,
154    {
155        self.rebind_as(self.instance().cast_into())
156    }
157
158    /// Casts this object into an [`Object<Any>`].
159    ///
160    /// # Usage
161    ///
162    /// This is useful when you have an [`Object<T>`] but you want an [`Object<Any>`].
163    ///
164    /// All objects of any [`Kind`] can be cast into [`Object<Any>`].
165    fn cast_into_any(self) -> Self::Rebind<Any> {
166        self.rebind_as(self.instance().cast_into_any())
167    }
168
169    /// Casts this object into another of a different [`Kind`].
170    ///
171    /// # Usage
172    ///
173    /// This is useful when you have an [`Object<T>`] but you want an [`Object<U>`] and
174    /// you can guarantee that [`Kind`] `T` is safely convertible to `U`.
175    ///
176    /// # Safety
177    ///
178    /// It is assumed that [`Kind`] `T` is safely convertible to `U`.
179    unsafe fn cast_into_unchecked<U: Kind>(self) -> Self::Rebind<U> {
180        self.rebind_as(self.instance().cast_into_unchecked())
181    }
182}
183
184impl<'w, 's, 'a, T: Kind> ObjectRebind<T> for Object<'w, 's, 'a, T> {
185    type Rebind<U: Kind> = Object<'w, 's, 'a, U>;
186
187    fn rebind_as<U: Kind>(&self, instance: Instance<U>) -> Self::Rebind<U> {
188        Object {
189            instance,
190            hierarchy: self.hierarchy,
191            name: self.name,
192        }
193    }
194}
195
196impl<'w, 's, 'a, T: Kind> ObjectRebind<T> for ObjectRef<'w, 's, 'a, T> {
197    type Rebind<U: Kind> = ObjectRef<'w, 's, 'a, U>;
198
199    fn rebind_as<U: Kind>(&self, instance: Instance<U>) -> Self::Rebind<U> {
200        ObjectRef(self.0, self.1.rebind_as(instance))
201    }
202}