bevy_defer/access/
impls.rs

1//! Access traits for `bevy_defer`.
2
3use crate::access::async_query::OwnedReadonlyQueryState;
4use crate::access::{
5    AsyncAsset, AsyncComponent, AsyncEntityQuery, AsyncNonSend, AsyncQuery, AsyncQuerySingle,
6    AsyncRelatedQuery, AsyncResource, AsyncWorld, RelatedQueryState,
7};
8use crate::tween::{AsSeconds, Playback};
9use crate::OwnedQueryState;
10use crate::{
11    cancellation::TaskCancellation,
12    executor::{with_world_mut, with_world_ref},
13    sync::oneshot::{ChannelOut, InterpolateOut},
14    AccessError, AccessResult,
15};
16use bevy::asset::{Asset, Assets};
17use bevy::ecs::component::Mutable;
18use bevy::ecs::query::{ReadOnlyQueryData, ReleaseStateQueryData};
19use bevy::ecs::relationship::RelationshipTarget;
20use bevy::ecs::{
21    component::Component,
22    query::{QueryData, QueryFilter},
23    resource::Resource,
24};
25use bevy::math::StableInterpolate;
26use std::any::type_name;
27use std::cell::OnceCell;
28use std::marker::PhantomData;
29
30trait ShouldContinue {
31    fn should_continue(_e: AccessError) -> bool {
32        false
33    }
34}
35
36macro_rules! inject {
37    ($var: ident $fst: expr) => {
38        let $var = $fst;
39    };
40
41    ($var: ident $fst: stmt; $($stmts: tt)*) => {
42        inject!([$fst]$var $($stmts)*)
43    };
44
45    ([$($prev: stmt);*] $var: ident $fst: expr) => {
46        $($prev)*
47        let $var = $fst;
48    };
49
50    ([$($prev: stmt);*] $var: ident $fst: stmt; $($stmts: tt)*) => {
51        inject!([$($prev;)* $fst] $var $($stmts)*)
52    };
53}
54
55macro_rules! tri {
56    ($($tt:tt)*) => {
57        (|| {$($tt)*})()
58    };
59}
60
61macro_rules! impl_async_access {
62    ($($tt: tt)*) => {
63        impl_async_access1!($($tt)*);
64        impl_async_access2!($($tt)*);
65    }
66}
67
68macro_rules! impl_async_access1 {
69    (impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {}) => {};
70    (
71        impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {
72            fn get($this: ident: &Self, $world: ident: &World) -> AccessResult<$Ref: ty> {
73                $($stmts: tt)*
74            }
75
76            $($remaining: tt)*
77        }
78    ) => {
79        #[allow(unused)]
80        impl<$($impl_generics)*> $ty <$($ty_generics)*> {
81            /// Run a function on a readonly reference to this item and obtain the result.
82            ///
83            /// Can be used inside a readonly world access scope and
84            /// converts the scope into a readonly world access scope.
85            #[track_caller]
86            pub fn get<A>(&self, f: impl FnOnce($Ref) -> A) -> AccessResult<A> {
87                let $this = self;
88                with_world_ref(|$world|{
89                    inject!(out $($stmts)*);
90                    let result = f(out?);
91                    Ok(result)
92                })
93            }
94
95            /// Run a function on this item and obtain the result once loaded.
96            ///
97            /// Can be used inside a readonly world access scope.
98            #[track_caller]
99            pub fn get_on_load<A: 'static>(
100                &self,
101                mut f: impl FnMut($Ref) -> A + 'static,
102            ) -> ChannelOut<AccessResult<A>> {
103                let $this = self.clone();
104                AsyncWorld.watch(move |$world| {
105                    let out = tri!{
106                        inject!(out $($stmts)*);
107                        let result = f(out?);
108                        Ok(result)
109                    };
110
111                    match out {
112                        Ok(value) => Some(Ok(value)),
113                        Err(err) if <Self as ShouldContinue>::should_continue(err) => None,
114                        Err(err) => Some(Err(err))
115                    }
116                })
117            }
118
119            /// Check if item exists.
120            ///
121            /// Can be used inside a readonly world access scope.
122            #[track_caller]
123            pub fn exists(&self) -> bool {
124                let $this = self;
125                with_world_ref::<AccessResult<bool>>(|$world|{
126                    inject!(out $($stmts)*);
127                    Ok(out.is_ok())
128                }).is_ok()
129            }
130        }
131
132        impl_async_access1!(
133            impl[$($impl_generics)*] $ty [$($ty_generics)*] {
134                $($remaining)*
135            }
136        );
137    };
138    (
139        impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {
140            fn take($this: ident: &Self, $world: ident: &mut World) -> AccessResult<$Ref: ty> {
141                $($stmts: tt)*
142            }
143
144            $($remaining: tt)*
145        }
146    ) => {
147        #[allow(unused)]
148        impl<$($impl_generics)*> $ty <$($ty_generics)*> {
149            /// Remove the item from the world.
150            #[track_caller]
151            pub fn remove(&self) {
152                let $this = self;
153                with_world_mut(|$world|{
154                    inject!(out $($stmts)*);
155                    AccessResult::Ok(())
156                });
157            }
158
159            /// Remove and obtain the item from the world.
160            #[track_caller]
161            pub fn take(&self) -> AccessResult<$Ref> {
162                let $this = self;
163                with_world_mut(|$world|{
164                    inject!(out $($stmts)*);
165                    out
166                })
167            }
168
169            /// Remove and obtain the item from the world once loaded.
170            #[track_caller]
171            pub fn take_on_load(&self) -> ChannelOut<AccessResult<$Ref>> {
172                let $this = self.clone();
173                AsyncWorld.watch(move |$world| {
174                    let out = tri! {
175                        inject!(out $($stmts)*);
176                        out
177                    };
178                    match out {
179                        Ok(value) => Some(Ok(value)),
180                        Err(err) if <Self as ShouldContinue>::should_continue(err) => None,
181                        Err(err) => Some(Err(err))
182                    }
183                })
184            }
185        }
186    };
187    (
188        impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {
189            fn get_mut($this: ident: &Self, $world: ident: &mut World) -> AccessResult<$Ref: ty> {
190                $($stmts: tt)*
191            }
192
193            $($remaining: tt)*
194        }
195    ) => {
196        #[allow(unused)]
197        impl<$($impl_generics)*> $ty <$($ty_generics)*> {
198            /// Run a function on a readonly reference to this item and obtain the result.
199            #[track_caller]
200            pub fn get_mut<A>(&self, f: impl FnOnce($Ref) -> A) -> AccessResult<A> {
201                let $this = self;
202                with_world_mut(|$world|{
203                    inject!(out $($stmts)*);
204                    let result = f(out?);
205                    Ok(result)
206                })
207            }
208
209            /// Run a function on this item until it returns `Some`.
210            #[track_caller]
211            pub fn watch<A: 'static>(
212                &self,
213                mut f: impl FnMut($Ref) -> Option<A> + 'static,
214            ) -> ChannelOut<AccessResult<A>> {
215                let $this = self.clone();
216                AsyncWorld.watch(move |$world| {
217                    let out = (|| {
218                        inject!(out $($stmts)*);
219                        let result = f(out?);
220                        Ok(result)
221                    })();
222
223                    match out {
224                        Ok(Some(value)) => Some(Ok(value)),
225                        Ok(None) => None,
226                        Err(err) if <Self as ShouldContinue>::should_continue(err) => None,
227                        Err(err) => Some(Err(err))
228                    }
229                })
230            }
231
232            /// Run a function on this item and obtain the result once loaded.
233            #[track_caller]
234            pub fn get_mut_on_load<A: 'static>(
235                &self,
236                mut f: impl FnMut($Ref) -> A + 'static,
237            ) -> ChannelOut<AccessResult<A>> {
238                let $this = self.clone();
239                AsyncWorld.watch(move |$world| {
240                    let out = tri! {
241                        inject!(out $($stmts)*);
242                        let result = f(out?);
243                        Ok(result)
244                    };
245
246                    match out {
247                        Ok(value) => Some(Ok(value)),
248                        Err(err) if <Self as ShouldContinue>::should_continue(err) => None,
249                        Err(err) => Some(Err(err))
250                    }
251                })
252            }
253        }
254
255        impl_async_access1!(
256            impl[$($impl_generics)*] $ty [$($ty_generics)*] {
257                $($remaining)*
258            }
259        );
260    };
261}
262
263macro_rules! impl_async_access2 {
264    (impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {}) => {};
265
266    (
267        impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {
268            fn get($this: ident: &Self, $world: ident: &World) -> AccessResult<&$Ref: ty> {
269                $($stmts: tt)*
270            }
271
272            $($remaining: tt)*
273        }
274    ) => {
275        #[allow(unused)]
276        impl<$($impl_generics)*> $ty <$($ty_generics)*> {
277            /// Obtain a copy of the underlying item.
278            ///
279            /// Can be used inside a readonly world access scope.
280            #[track_caller]
281            pub fn copied(&self) -> AccessResult<$Ref> where $Ref: Copy {
282                let $this = self;
283                with_world_ref(|$world|{
284                    inject!(out $($stmts)*);
285                    Ok(*(out?))
286                })
287            }
288
289            /// Obtain a clone of the underlying item.
290            ///
291            /// Can be used inside a readonly world access scope.
292            #[track_caller]
293            pub fn cloned(&self) -> AccessResult<$Ref> where $Ref: Clone {
294                let $this = self;
295                with_world_ref(|$world|{
296                    inject!(out $($stmts)*);
297                    Ok((out?).clone())
298                })
299            }
300
301            /// Run a function on this item and obtain the result once loaded.
302            ///
303            /// Can be used inside a readonly world access scope.
304            #[track_caller]
305            pub fn clone_on_load(&self) -> ChannelOut<AccessResult<$Ref>> where $Ref: Clone {
306                let $this = self.clone();
307                AsyncWorld.watch(move |$world| {
308                    let out = tri!{
309                        inject!(out $($stmts)*);
310                        Ok((out?).clone())
311                    };
312
313                    match out {
314                        Ok(value) => Some(Ok(value)),
315                        Err(err) if <Self as ShouldContinue>::should_continue(err) => None,
316                        Err(err) => Some(Err(err))
317                    }
318                })
319            }
320        }
321
322
323        impl_async_access2!(
324            impl[$($impl_generics)*] $ty [$($ty_generics)*] {
325                $($remaining)*
326            }
327        );
328    };
329
330    (
331        impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {
332            fn get_mut($this: ident: &Self, $world: ident: &mut World) -> AccessResult<&mut $Ref: ty> {
333                $($stmts: tt)*
334            }
335
336            $($remaining: tt)*
337        }
338    ) => {
339        #[allow(unused)]
340        impl<$($impl_generics)*> $ty <$($ty_generics)*> {
341            /// Interpolate to a new value from the previous value.
342            #[track_caller]
343            pub fn interpolate_to<V: StableInterpolate + 'static>(
344                &self,
345                to: V,
346                mut get: impl FnMut(&$Ref) -> V + Send + 'static,
347                mut set: impl FnMut(&mut $Ref, V) + Send + 'static,
348                mut curve: impl FnMut(f32) -> f32 + Send + 'static,
349                duration: impl AsSeconds,
350                cancel: impl Into<TaskCancellation>,
351            ) -> InterpolateOut {
352                let $this = self.clone();
353                let mut t = 0.0;
354                let duration = duration.as_secs();
355                let source = OnceCell::<V>::new();
356                let cancel = cancel.into();
357                AsyncWorld
358                    .timed_routine(
359                        move |$world, dt| {
360                            tri! {
361                                inject!(out $($stmts)*);
362                                let item = out?;
363                                t += dt.as_secs_f32();
364                                let source = source.get_or_init(|| get(item)).clone();
365                                if t > duration {
366                                    set(item, to.clone());
367                                    Ok(Ok(()))
368                                } else {
369                                    let fac = curve(t / duration);
370                                    set(item, V::interpolate_stable(&source, &to, fac));
371                                    Err(AccessError::ShouldNotHappen)
372                                }
373                            }.ok()
374                        },
375                        cancel,
376                    )
377                    .into_interpolate_out()
378            }
379
380            /// Run an animation, maybe repeatedly, that can be cancelled.
381            ///
382            /// It is recommended to `spawn` the result instead of awaiting it directly
383            /// if not [`Playback::Once`].
384            ///
385            /// ```
386            /// # /*
387            /// spawn(interpolate(.., Playback::Loop, &cancel));
388            /// cancel.cancel();
389            /// # */
390            /// ```
391            #[track_caller]
392            pub fn interpolate<V>(
393                &self,
394                mut span: impl FnMut(f32) -> V + 'static,
395                mut write: impl FnMut(&mut $Ref, V) + 'static,
396                mut curve: impl FnMut(f32) -> f32 + 'static,
397                duration: impl AsSeconds,
398                playback: Playback,
399                cancel: impl Into<TaskCancellation>,
400            ) -> InterpolateOut {
401                let $this = self.clone();
402                let duration = duration.as_secs();
403                let mut t = 0.0;
404                let cancel = cancel.into();
405                AsyncWorld
406                    .timed_routine(
407                        move |$world, dt| {
408                            tri! {
409                                inject!(out $($stmts)*);
410                                let item = out?;
411                                t += dt.as_secs_f32() / duration;
412                                let fac = if t > 1.0 {
413                                    match playback {
414                                        Playback::Once => {
415                                            write(item, span(curve(1.0)));
416                                            return Ok(Ok(()));
417                                        }
418                                        Playback::Loop => {
419                                            t = t.fract();
420                                            t
421                                        }
422                                        Playback::Bounce => {
423                                            t %= 2.0;
424                                            1.0 - (1.0 - t % 2.0).abs()
425                                        }
426                                    }
427                                } else {
428                                    t
429                                };
430                                write(item, span(curve(fac)));
431                                Err(AccessError::ShouldNotHappen)
432                            }.ok()
433                        },
434                        cancel,
435                    )
436                    .into_interpolate_out()
437            }
438        }
439
440        impl_async_access2!(
441            impl[$($impl_generics)*] $ty [$($ty_generics)*] {
442                $($remaining)*
443            }
444        );
445    };
446
447    (
448        impl[$($impl_generics:tt)*] $ty: ident [$($ty_generics:tt)*] {
449            fn $name: ident ($($a:tt)*) -> $b: ty {$($c:tt)*}
450            $($remaining: tt)*
451        }
452    ) => {
453        impl_async_access2!(
454            impl[$($impl_generics)*] $ty [$($ty_generics)*] {
455                $($remaining)*
456            }
457        );
458    }
459}
460
461impl_async_access! {
462    impl[C: Component<Mutability = Mutable>] AsyncComponent [C] {
463        fn get_mut(this: &Self, world: &mut World) -> AccessResult<&mut C> {
464            let entity = this.id();
465            let mut entity_mut = world
466                .get_entity_mut(entity)
467                .map_err(|_| AccessError::EntityNotFound(entity))?;
468            entity_mut
469                .get_mut::<C>()
470                .map(|x| x.into_inner())
471                .ok_or(AccessError::ComponentNotFound {
472                    name: type_name::<C>(),
473                })
474        }
475    }
476}
477
478/// Not a loading resource, ignore.
479impl<C: Component> ShouldContinue for AsyncComponent<C> {}
480
481impl_async_access! {
482    impl[C: Component] AsyncComponent [C] {
483        fn get(this: &Self, world: &World) -> AccessResult<&C> {
484            let entity = this.id();
485            world
486                .get_entity(entity)
487                .map_err(|_| AccessError::EntityNotFound(entity))?
488                .get::<C>()
489                .ok_or(AccessError::ComponentNotFound {
490                    name: type_name::<C>(),
491                })
492        }
493
494        fn take(this: &Self, world: &mut World) -> AccessResult<C> {
495            let entity = this.id();
496            world
497                .get_entity_mut(entity)
498                .map_err(|_| AccessError::EntityNotFound(entity))?
499                .take::<C>()
500                .ok_or(AccessError::ComponentNotFound {
501                    name: type_name::<C>(),
502                })
503        }
504    }
505}
506
507impl<R: Resource> ShouldContinue for AsyncResource<R> {
508    fn should_continue(e: AccessError) -> bool {
509        e == AccessError::ResourceNotFound {
510            name: type_name::<R>(),
511        }
512    }
513}
514
515impl_async_access! {
516    impl[R: Resource] AsyncResource [R] {
517        fn get(this: &Self, world: &World) -> AccessResult<&R> {
518            world.get_resource::<R>().ok_or(AccessError::ResourceNotFound {
519                name: type_name::<R>(),
520            })
521        }
522
523        fn get_mut(this: &Self, world: &mut World) -> AccessResult<&mut R> {
524            world.get_resource_mut::<R>()
525                .map(|x| x.into_inner())
526                .ok_or(AccessError::ResourceNotFound {
527                    name: type_name::<R>(),
528                })
529        }
530    }
531}
532
533impl<R: 'static> ShouldContinue for AsyncNonSend<R> {
534    fn should_continue(e: AccessError) -> bool {
535        e == AccessError::ResourceNotFound {
536            name: type_name::<R>(),
537        }
538    }
539}
540
541impl_async_access! {
542    impl[R: 'static] AsyncNonSend [R] {
543        fn get(this: &Self, world: &World) -> AccessResult<&R> {
544            world.get_non_send_resource::<R>().ok_or(AccessError::ResourceNotFound {
545                name: type_name::<R>(),
546            })
547        }
548
549        fn get_mut(this: &Self, world: &mut World) -> AccessResult<&mut R> {
550            world.get_non_send_resource_mut::<R>()
551                .map(|x| x.into_inner())
552                .ok_or(AccessError::ResourceNotFound {
553                    name: type_name::<R>(),
554                })
555        }
556    }
557}
558
559impl<T: Asset> ShouldContinue for AsyncAsset<T> {
560    fn should_continue(e: AccessError) -> bool {
561        e == AccessError::AssetNotFound {
562            name: type_name::<T>(),
563        }
564    }
565}
566
567impl_async_access! {
568    impl[T: Asset] AsyncAsset [T] {
569        fn get(this: &Self, world: &World) -> AccessResult<&T> {
570            let id = this.id();
571            world
572                .get_resource::<Assets<T>>()
573                .ok_or(AccessError::ResourceNotFound {
574                    name: type_name::<Assets<T>>(),
575                })?
576                .get(id)
577                .ok_or(AccessError::AssetNotFound {
578                    name: type_name::<T>(),
579                })
580        }
581
582        fn get_mut(this: &Self, world: &mut World) -> AccessResult<&mut T> {
583            let id = this.id();
584            world
585                .get_resource_mut::<Assets<T>>()
586                .map(|x| x.into_inner())
587                .ok_or(AccessError::ResourceNotFound {
588                    name: type_name::<Assets<T>>(),
589                })?
590                .get_mut(id)
591                .ok_or(AccessError::AssetNotFound {
592                    name: type_name::<T>(),
593                })
594        }
595
596        fn take(this: &Self, world: &mut World) -> AccessResult<T> {
597            let id = this.id();
598            world
599                .get_resource_mut::<Assets<T>>()
600                .map(|x| x.into_inner())
601                .ok_or(AccessError::ResourceNotFound {
602                    name: type_name::<Assets<T>>(),
603                })?
604                .remove(id)
605                .ok_or(AccessError::AssetNotFound {
606                    name: type_name::<T>(),
607                })
608        }
609    }
610}
611
612impl<D: QueryData, F: QueryFilter> ShouldContinue for AsyncQuery<D, F> {}
613
614impl_async_access! {
615    impl[D: QueryData + 'static, F: QueryFilter + 'static] AsyncQuery [D, F] {
616        fn get_mut(this: &Self, world: &mut World) -> AccessResult<OwnedQueryState<D, F>> {
617            Ok(OwnedQueryState::<D, F>::new(world))
618        }
619    }
620}
621
622impl_async_access! {
623    impl[D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static] AsyncQuery [D, F] {
624        fn get(this: &Self, world: &World) -> AccessResult<OwnedReadonlyQueryState<D, F>> {
625            AccessResult::Ok(OwnedReadonlyQueryState::<D, F>::new(world))
626        }
627    }
628}
629
630impl<D: QueryData, F: QueryFilter> ShouldContinue for AsyncEntityQuery<D, F> {}
631
632impl_async_access! {
633    impl[D: ReadOnlyQueryData + ReleaseStateQueryData + 'static, F: QueryFilter + 'static] AsyncEntityQuery [D, F] {
634        fn get(this: &Self, world: &World) -> AccessResult<D::Item<'_, '_>> {
635            let entity = this.id();
636            world
637                .get_entity(entity)
638                .map_err(|_| AccessError::EntityNotFound(entity))?
639                .get_components::<D>()
640                .map_err(|_| AccessError::QueryConditionNotMet {
641                    entity,
642                    query: type_name::<D>(),
643                })
644        }
645    }
646}
647
648impl_async_access! {
649    impl[D: QueryData + ReleaseStateQueryData + 'static, F: QueryFilter + 'static] AsyncEntityQuery [D, F] {
650        fn get_mut(this: &Self, world: &mut World) -> AccessResult<D::Item<'_, '_>> {
651            let entity = this.id();
652            let mut e = world
653                .get_entity_mut(entity)
654                .map_err(|_| AccessError::EntityNotFound(entity))?;
655            e.get_components_mut::<D>()
656                .map_err(|_| AccessError::QueryConditionNotMet {
657                    entity,
658                    query: type_name::<D>(),
659                })
660        }
661    }
662}
663
664impl<D: QueryData, F: QueryFilter> ShouldContinue for AsyncQuerySingle<D, F> {}
665
666impl_async_access! {
667    impl[D: QueryData + 'static, F: QueryFilter + 'static] AsyncQuerySingle [D, F] {
668        fn get_mut(this: &Self, world: &mut World) -> AccessResult<D::Item<'_, '_>> {
669            let mut query = OwnedQueryState::<D, F>::new(world);
670            query.single_mut()
671        }
672    }
673}
674
675impl_async_access! {
676    impl[D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static] AsyncQuerySingle [D, F] {
677        fn get(this: &Self, world: &World) -> AccessResult<D::Item<'_, '_>> {
678            let mut query = OwnedReadonlyQueryState::<D, F>::new(world);
679            query.single()
680        }
681    }
682}
683
684impl<R: RelationshipTarget, D: QueryData, F: QueryFilter> ShouldContinue
685    for AsyncRelatedQuery<R, D, F>
686{
687}
688
689impl_async_access! {
690    impl[R: RelationshipTarget + 'static, D: QueryData + 'static, F: QueryFilter + 'static] AsyncRelatedQuery [R, D, F] {
691        fn get_mut(this: &Self, world: &mut World) -> AccessResult<RelatedQueryState<R, D, F>> {
692            let parent = this.id();
693            let mut query = OwnedQueryState::<D, F>::new(world);
694            Ok(RelatedQueryState::<R, D, F> {
695                world: query.world.as_unsafe_world_cell(),
696                query: query.state.as_mut().unwrap(),
697                parent,
698                p: PhantomData,
699            })
700        }
701    }
702}
703
704impl<D: QueryData + 'static, F: QueryFilter + 'static> AsyncQuery<D, F> {
705    /// Run a function on a this query.
706    #[track_caller]
707    pub fn with<A>(&self, f: impl FnOnce(OwnedQueryState<D, F>) -> A) -> A {
708        with_world_mut(|world| {
709            let state = OwnedQueryState::new(world);
710            f(state)
711        })
712    }
713}
714
715impl<R: Resource> AsyncResource<R> {
716    /// Run a function on this resource, panics if not exist.
717    #[track_caller]
718    pub fn with<A>(&self, f: impl FnOnce(&mut R) -> A) -> A {
719        with_world_mut(|world| f(world.resource_mut::<R>().into_inner()))
720    }
721}
722
723impl<R: 'static> AsyncNonSend<R> {
724    /// Run a function on this non-send resource, panics if not exist.
725    #[track_caller]
726    pub fn with<A>(&self, f: impl FnOnce(&mut R) -> A) -> A {
727        with_world_mut(|world| f(world.non_send_resource_mut::<R>().into_inner()))
728    }
729}