nexus_rt/resource.rs
1//! Shared and mutable resource references for handler parameters.
2//!
3//! [`Res<T>`] and [`ResMut<T>`] appear in handler function signatures to
4//! declare read and write dependencies on [`World`](crate::World) resources.
5//! They are produced by [`Param::fetch`](crate::Param::fetch) during dispatch
6//! and deref to the inner `T` transparently.
7//!
8//! For optional dependencies, use [`Option<Res<T>>`] or
9//! [`Option<ResMut<T>>`] — these resolve to `None` if the type was not
10//! registered, rather than panicking at build time.
11//!
12//! # Examples
13//!
14//! ```
15//! use nexus_rt::{WorldBuilder, Res, ResMut, IntoHandler, Handler, Resource, no_event};
16//!
17//! #[derive(Resource)]
18//! struct Config(u64);
19//! #[derive(Resource)]
20//! struct Flag(bool);
21//!
22//! fn process(config: Res<Config>, mut state: ResMut<Flag>) {
23//! if config.0 > 10 {
24//! state.0 = true;
25//! }
26//! }
27//!
28//! let mut builder = WorldBuilder::new();
29//! builder.register(Config(42));
30//! builder.register(Flag(false));
31//! let mut world = builder.build();
32//!
33//! let mut handler = no_event(process).into_handler(world.registry());
34//! handler.run(&mut world, ());
35//!
36//! assert!(world.resource::<Flag>().0);
37//! ```
38
39use std::cell::Cell;
40use std::ops::{Deref, DerefMut};
41
42use crate::Resource;
43use crate::world::Sequence;
44
45/// Shared reference to a resource in [`World`](crate::World).
46///
47/// Analogous to Bevy's `Res<T>`.
48///
49/// Appears in handler function signatures to declare a read dependency.
50/// Derefs to the inner value transparently.
51///
52/// # Cloning
53///
54/// `Res<T>` is `Copy + Clone` regardless of `T` — the wrapped reference
55/// is `&T`, which is always `Copy`. To clone the *inner* value, use
56/// `(*res).clone()` or `res.to_owned()`. Calling `res.clone()` returns
57/// `Res<T>`, not `T` — same shadowing pattern as Bevy's `Res<T>`.
58///
59/// For exclusive write access, use [`ResMut<T>`]. For optional read
60/// access (no panic if unregistered), use [`Option<Res<T>>`].
61///
62/// Construction is `pub(crate)` — only the dispatch layer creates these.
63pub struct Res<'w, T: Resource> {
64 value: &'w T,
65}
66
67impl<'w, T: Resource> Res<'w, T> {
68 pub(crate) fn new(value: &'w T) -> Self {
69 Self { value }
70 }
71}
72
73// Manual Copy/Clone impls (not derived) so the bounds depend only on what
74// the field actually requires. The single field is `&T`, which is always
75// Copy regardless of `T`. A derive would erroneously add `T: Clone`.
76impl<T: Resource> Clone for Res<'_, T> {
77 #[inline(always)]
78 fn clone(&self) -> Self {
79 *self
80 }
81}
82
83impl<T: Resource> Copy for Res<'_, T> {}
84
85impl<T: std::fmt::Debug + Resource> std::fmt::Debug for Res<'_, T> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 self.value.fmt(f)
88 }
89}
90
91impl<T: Resource> Deref for Res<'_, T> {
92 type Target = T;
93
94 #[inline(always)]
95 fn deref(&self) -> &T {
96 self.value
97 }
98}
99
100/// Mutable reference to a resource in [`World`](crate::World).
101///
102/// Analogous to Bevy's `ResMut<T>`.
103///
104/// Appears in handler function signatures to declare a write dependency.
105/// Derefs to the inner value transparently.
106///
107/// # Passing by value
108///
109/// `ResMut<T>` cannot be `Copy` (exclusive borrow). To pass the wrapper
110/// to inner functions without moving, call [`reborrow()`](Self::reborrow)
111/// — analogous to the `&mut *x` pattern for `&mut T`.
112///
113/// For shared read access, use [`Res<T>`]. For optional write access
114/// (no panic if unregistered), use [`Option<ResMut<T>>`].
115///
116/// Construction is `pub(crate)` — only the dispatch layer creates these.
117pub struct ResMut<'w, T: Resource> {
118 value: &'w mut T,
119}
120
121impl<'w, T: Resource> ResMut<'w, T> {
122 pub(crate) fn new(value: &'w mut T) -> Self {
123 Self { value }
124 }
125
126 /// Reborrow as a `ResMut<'_, T>` with a shorter lifetime.
127 ///
128 /// The original is frozen for the duration of the reborrow, then usable
129 /// again. Lets you pass `ResMut<T>` to inner functions without moving —
130 /// analogous to the `&mut *x` reborrow pattern for `&mut T`.
131 ///
132 /// `ResMut<T>` cannot be `Copy` (exclusive borrow), so this is the
133 /// counterpart to [`Res<T>`]'s `Copy` impl when the inner function
134 /// signature takes the wrapper itself rather than `&mut T`.
135 #[inline(always)]
136 pub fn reborrow(&mut self) -> ResMut<'_, T> {
137 ResMut {
138 value: &mut *self.value,
139 }
140 }
141}
142
143impl<T: std::fmt::Debug + Resource> std::fmt::Debug for ResMut<'_, T> {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 self.value.fmt(f)
146 }
147}
148
149impl<T: Resource> Deref for ResMut<'_, T> {
150 type Target = T;
151
152 #[inline(always)]
153 fn deref(&self) -> &T {
154 self.value
155 }
156}
157
158impl<T: Resource> DerefMut for ResMut<'_, T> {
159 #[inline(always)]
160 fn deref_mut(&mut self) -> &mut T {
161 self.value
162 }
163}
164
165// =============================================================================
166// Seq / SeqMut — sequence number access
167// =============================================================================
168
169/// Read-only access to the world's current sequence number.
170///
171/// Appears in handler function signatures alongside other params.
172/// Derefs to [`Sequence`].
173///
174/// # Example
175///
176/// ```ignore
177/// use nexus_rt::{Seq, Handler, IntoHandler};
178///
179/// fn log_event(seq: Seq, event: u64) {
180/// println!("event {} at sequence {}", event, seq.get());
181/// }
182/// ```
183#[derive(Clone, Copy)]
184pub struct Seq(pub(crate) Sequence);
185
186impl Seq {
187 /// Returns the current sequence value.
188 #[inline(always)]
189 pub const fn get(&self) -> Sequence {
190 self.0
191 }
192}
193
194impl Deref for Seq {
195 type Target = Sequence;
196
197 #[inline(always)]
198 fn deref(&self) -> &Sequence {
199 &self.0
200 }
201}
202
203/// Mutable access to the world's current sequence number.
204///
205/// Allows handlers to advance the sequence — useful for stamping
206/// outbound messages with monotonic sequence numbers.
207///
208/// # Example
209///
210/// ```ignore
211/// use nexus_rt::{SeqMut, Handler, IntoHandler};
212///
213/// fn send_message(mut seq: SeqMut<'_>, event: u64) {
214/// let msg_seq = seq.advance();
215/// // stamp msg_seq on outbound message
216/// }
217/// ```
218pub struct SeqMut<'w>(pub(crate) &'w Cell<Sequence>);
219
220impl SeqMut<'_> {
221 /// Returns the current sequence value.
222 #[inline(always)]
223 pub fn get(&self) -> Sequence {
224 self.0.get()
225 }
226
227 /// Advance the sequence by 1 and return the new value.
228 #[inline(always)]
229 pub fn advance(&mut self) -> Sequence {
230 let next = Sequence(self.0.get().0.wrapping_add(1));
231 self.0.set(next);
232 next
233 }
234}
235
236// =============================================================================
237// Tests
238// =============================================================================
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243 use crate::world::Resource;
244
245 struct Val(u64);
246 impl Resource for Val {}
247
248 #[test]
249 fn res_deref() {
250 let val = Val(42);
251 let res = Res::new(&val);
252 assert_eq!(res.0, 42);
253 }
254
255 #[test]
256 fn res_mut_deref() {
257 let mut val = Val(0);
258 let mut res = ResMut::new(&mut val);
259 res.0 = 99;
260 assert_eq!(val.0, 99);
261 }
262
263 #[test]
264 fn res_mut_deref_mut_no_stamp() {
265 // ResMut::deref_mut is now a plain pass-through — no stamping.
266 let mut val = Val(0);
267 let mut res = ResMut::new(&mut val);
268 *res = Val(123);
269 assert_eq!(val.0, 123);
270 }
271
272 #[test]
273 fn res_is_copy() {
274 // Compile-time proof that Res<T> is Copy (and Clone) without
275 // requiring T: Copy or T: Clone — Val implements neither.
276 fn assert_copy<U: Copy>(_: U) {}
277 let val = Val(42);
278 let res = Res::new(&val);
279 assert_copy(res);
280 let a = res;
281 let b = res; // Copy — not a move
282 assert_eq!(a.0, 42);
283 assert_eq!(b.0, 42);
284 }
285
286 #[test]
287 fn res_pass_to_inner_function() {
288 // The motivating use case: passing Res<T> to inner functions
289 // without moving.
290 fn inner(r: Res<'_, Val>) -> u64 {
291 r.0
292 }
293 let val = Val(7);
294 let res = Res::new(&val);
295 assert_eq!(inner(res), 7);
296 assert_eq!(inner(res), 7); // would not compile without Copy
297 }
298
299 #[test]
300 fn res_mut_reborrow() {
301 // ResMut::reborrow() lets us pass ResMut<T> (the wrapper) to
302 // inner functions without moving.
303 fn inner(mut r: ResMut<'_, Val>) {
304 r.0 += 1;
305 }
306 let mut val = Val(0);
307 let mut res = ResMut::new(&mut val);
308 inner(res.reborrow());
309 inner(res.reborrow());
310 inner(res.reborrow());
311 // res is usable again here; original lifetime restored.
312 assert_eq!(res.0, 3);
313 }
314
315 #[test]
316 fn res_mut_reborrow_then_use_original() {
317 // After the reborrow goes out of scope, the original is usable
318 // for both shared and mutable access.
319 let mut val = Val(10);
320 let mut res = ResMut::new(&mut val);
321 {
322 let mut rb = res.reborrow();
323 rb.0 = 20;
324 }
325 // Original ResMut usable again.
326 res.0 = 30;
327 assert_eq!(val.0, 30);
328 }
329
330 #[test]
331 fn seq_get() {
332 let seq = Seq(Sequence(42));
333 assert_eq!(seq.get(), Sequence(42));
334 }
335
336 #[test]
337 fn seq_mut_advance() {
338 let cell = Cell::new(Sequence(0));
339 let mut seq = SeqMut(&cell);
340 let next = seq.advance();
341 assert_eq!(next, Sequence(1));
342 assert_eq!(cell.get(), Sequence(1));
343 }
344}