Skip to content

Commit dd61ccb

Browse files
committed
more
1 parent a4d88eb commit dd61ccb

File tree

6 files changed

+1239
-135
lines changed

6 files changed

+1239
-135
lines changed

src/builder.rs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use 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+
2093
fn 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
}

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ impl Plugin for JonmoPlugin {
115115
/// `use jonmo::prelude::*;` imports everything one needs to use start using [jonmo](crate).
116116
pub mod prelude {
117117
#[cfg(feature = "builder")]
118-
pub use crate::builder::JonmoBuilder;
118+
pub use crate::builder::{
119+
Holdable, JonmoBuilder, SignalHoldExt, SignalMapHoldExt, SignalVecHoldExt,
120+
};
119121
pub use crate::{
120122
JonmoPlugin,
121123
graph::SignalHandles,

0 commit comments

Comments
 (0)