22use super :: {
33 graph:: { SignalHandle , SignalHandles } ,
44 signal:: { Signal , SignalBuilder , SignalExt } ,
5+ signal_map:: { SignalMap , SignalMapExt } ,
56 signal_vec:: { SignalVec , SignalVecExt , VecDiff } ,
67 utils:: { LazyEntity , SSs , ancestor_map} ,
78} ;
@@ -17,6 +18,78 @@ use bevy_platform::{
1718 sync:: { Arc , Mutex } ,
1819} ;
1920
21+ /// A type-erased signal that can be registered with a [`World`] at spawn time.
22+ ///
23+ /// This trait enables [`JonmoBuilder::hold_signals`] to accept signals that haven't
24+ /// been registered yet, deferring their registration until the entity is spawned.
25+ ///
26+ /// Use the [`.hold()`](SignalHoldExt::hold) extension method to convert a [`Signal`],
27+ /// [`SignalVec`], or [`SignalMap`] into a `Box<dyn Holdable>`.
28+ pub trait Holdable : Send + Sync + ' static {
29+ /// Register this signal with the world and return its handle.
30+ fn register_holdable ( self : Box < Self > , world : & mut World ) -> SignalHandle ;
31+ }
32+
33+ // Signal wrapper
34+ struct HoldableSignal < S > ( S ) ;
35+
36+ impl < S : Signal + SSs > Holdable for HoldableSignal < S > {
37+ fn register_holdable ( self : Box < Self > , world : & mut World ) -> SignalHandle {
38+ self . 0 . register ( world)
39+ }
40+ }
41+
42+ /// Extension trait for converting a [`Signal`] into a [`Holdable`].
43+ pub trait SignalHoldExt : Signal + Sized + SSs {
44+ /// Convert this signal into a type-erased [`Holdable`] for use with
45+ /// [`JonmoBuilder::hold_signals`].
46+ fn hold ( self ) -> Box < dyn Holdable > {
47+ Box :: new ( HoldableSignal ( self ) )
48+ }
49+ }
50+
51+ impl < S : Signal + Sized + SSs > SignalHoldExt for S { }
52+
53+ // SignalVec wrapper
54+ struct HoldableSignalVec < S > ( S ) ;
55+
56+ impl < S : SignalVec + SSs > Holdable for HoldableSignalVec < S > {
57+ fn register_holdable ( self : Box < Self > , world : & mut World ) -> SignalHandle {
58+ self . 0 . register ( world)
59+ }
60+ }
61+
62+ /// Extension trait for converting a [`SignalVec`] into a [`Holdable`].
63+ pub trait SignalVecHoldExt : SignalVec + Sized + SSs {
64+ /// Convert this signal vec into a type-erased [`Holdable`] for use with
65+ /// [`JonmoBuilder::hold_signals`].
66+ fn hold ( self ) -> Box < dyn Holdable > {
67+ Box :: new ( HoldableSignalVec ( self ) )
68+ }
69+ }
70+
71+ impl < S : SignalVec + Sized + SSs > SignalVecHoldExt for S { }
72+
73+ // SignalMap wrapper
74+ struct HoldableSignalMap < S > ( S ) ;
75+
76+ impl < S : SignalMap + SSs > Holdable for HoldableSignalMap < S > {
77+ fn register_holdable ( self : Box < Self > , world : & mut World ) -> SignalHandle {
78+ self . 0 . register ( world)
79+ }
80+ }
81+
82+ /// Extension trait for converting a [`SignalMap`] into a [`Holdable`].
83+ pub trait SignalMapHoldExt : SignalMap + Sized + SSs {
84+ /// Convert this signal map into a type-erased [`Holdable`] for use with
85+ /// [`JonmoBuilder::hold_signals`].
86+ fn hold ( self ) -> Box < dyn Holdable > {
87+ Box :: new ( HoldableSignalMap ( self ) )
88+ }
89+ }
90+
91+ impl < S : SignalMap + Sized + SSs > SignalMapHoldExt for S { }
92+
2093fn on_despawn_hook ( mut world : DeferredWorld , ctx : HookContext ) {
2194 let entity = ctx. entity ;
2295 let fs = world
@@ -100,9 +173,25 @@ impl JonmoBuilder {
100173 } )
101174 }
102175
103- /// Attach registered [`SignalHandle`]s to this entity for automatic cleanup on despawn.
104- pub fn hold_signals ( self , handles : impl IntoIterator < Item = SignalHandle > + SSs ) -> Self {
105- self . on_spawn ( move |world, entity| add_handles ( world, entity, handles) )
176+ /// Attach [`Holdable`] signals to this entity for automatic cleanup on despawn.
177+ ///
178+ /// Use [`.hold()`](SignalHoldExt::hold) to convert a [`Signal`], [`SignalVec`], or
179+ /// [`SignalMap`] into a [`Holdable`].
180+ ///
181+ /// # Example
182+ ///
183+ /// ```ignore
184+ /// let my_signal = SignalBuilder::from_resource::<MyResource>().map_in(|r| r.value).hold();
185+ /// let my_signal_vec = my_mutable_vec.signal_vec().hold();
186+ ///
187+ /// JonmoBuilder::new()
188+ /// .hold_signals([my_signal, my_signal_vec])
189+ /// ```
190+ pub fn hold_signals ( self , holdables : impl IntoIterator < Item = Box < dyn Holdable > > + SSs ) -> Self {
191+ self . on_spawn ( move |world, entity| {
192+ let handles: Vec < _ > = holdables. into_iter ( ) . map ( |h| h. register_holdable ( world) ) . collect ( ) ;
193+ add_handles ( world, entity, handles) ;
194+ } )
106195 }
107196
108197 /// Run a function with this builder's [`EntityWorldMut`].
@@ -158,6 +247,7 @@ impl JonmoBuilder {
158247 }
159248
160249 /// Set the [`LazyEntity`] to this builder's [`Entity`].
250+ #[ track_caller]
161251 pub fn lazy_entity ( self , entity : LazyEntity ) -> Self {
162252 self . on_spawn ( move |_, e| entity. set ( e) )
163253 }
0 commit comments