Skip to main content

moonshine_object/
rebind.rs

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