@@ -556,6 +556,85 @@ impl<S: States> Command for StateScopedSpawnFn<S> {
556556 }
557557}
558558
559+ #[ doc( hidden) ]
560+ #[ must_use = "Defer must not be dropped immediately." ]
561+ pub struct Defer < F : FnOnce ( ) -> AccessResult > ( pub Option < F > ) ;
562+
563+ impl < F : FnOnce ( ) -> AccessResult > Drop for Defer < F > {
564+ fn drop ( & mut self ) {
565+ if in_async_context ( ) {
566+ let _ = ( self . 0 . take ( ) . unwrap ( ) ) ( ) ;
567+ }
568+ }
569+ }
570+
571+ /// Defer a set of statements that automatically triggers when the future is either completed
572+ /// or dropped (i.e. via select!)
573+ ///
574+ /// # Returns
575+ ///
576+ /// Returns a variable that triggers these statements on drop.
577+ ///
578+ /// # Note
579+ ///
580+ /// If the world is dropped, these statements will NOT be ran since `bevy_defer` functions
581+ /// will likely panic if the world is no longer available.
582+ ///
583+ /// # Example
584+ ///
585+ /// ```
586+ /// # use bevy_defer::{AccessResult, defer};
587+ /// # async fn dance(entity: i32) -> AccessResult { Ok(()) }
588+ /// # fn stop_dancing(entity: i32) -> AccessResult { Ok(()) }
589+ /// # async fn test() -> AccessResult {
590+ /// # let entity = 1;
591+ /// // Must be bound to a variable and not `_` so it lives until the end of the future.
592+ /// let _deferred = defer! {
593+ /// // stop dancing when the future is dropped
594+ /// stop_dancing(entity)?;
595+ /// };
596+ /// dance(entity).await?;
597+ /// # Ok(()) }
598+ /// ```
599+ #[ macro_export]
600+ macro_rules! defer {
601+ ( $( $tt: tt) * ) => {
602+ $crate:: Defer ( Some ( || {
603+ let _ = { $( $tt) * } ;
604+ Ok ( ( ) )
605+ } ) )
606+ } ;
607+ }
608+
609+ /// Try run a potentially async block of arguments with result type [`AccessError`],
610+ /// always discard the result and does not log the error.
611+ ///
612+ /// # Example
613+ ///
614+ /// ```
615+ /// # use bevy_defer::{AccessResult, attempt};
616+ /// # async fn dance(entity: i32) -> AccessResult { Ok(()) }
617+ /// # async fn stop_dancing(entity: i32) -> AccessResult { Ok(()) }
618+ /// # async fn test() -> AccessResult {
619+ /// # let entity = 1;
620+ /// dance(entity).await?;
621+ /// // Must be bound to a variable and not `_` so it lives until the end of the future.
622+ /// attempt! {
623+ /// stop_dancing(entity).await?;
624+ /// };
625+ /// # Ok(()) }
626+ /// ```
627+ #[ macro_export]
628+ macro_rules! attempt {
629+ ( $( $tt: tt) * ) => {
630+ let _: $crate:: AccessResult <( ) > = async {
631+ let _ = { $( $tt) * } ;
632+ Ok ( ( ) )
633+ } . await ;
634+ } ;
635+ }
636+
637+
559638#[ doc( hidden) ]
560639#[ allow( unused) ]
561640#[ macro_export]
0 commit comments