Skip to main content

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};
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>, _event: ()) {
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 = 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/// For exclusive write access, use [`ResMut<T>`]. For optional read
53/// access (no panic if unregistered), use [`Option<Res<T>>`].
54///
55/// Construction is `pub(crate)` — only the dispatch layer creates these.
56pub struct Res<'w, T: Resource> {
57    value: &'w T,
58}
59
60impl<'w, T: Resource> Res<'w, T> {
61    pub(crate) fn new(value: &'w T) -> Self {
62        Self { value }
63    }
64}
65
66impl<T: std::fmt::Debug + Resource> std::fmt::Debug for Res<'_, T> {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        self.value.fmt(f)
69    }
70}
71
72impl<T: Resource> Deref for Res<'_, T> {
73    type Target = T;
74
75    #[inline(always)]
76    fn deref(&self) -> &T {
77        self.value
78    }
79}
80
81/// Mutable reference to a resource in [`World`](crate::World).
82///
83/// Analogous to Bevy's `ResMut<T>`.
84///
85/// Appears in handler function signatures to declare a write dependency.
86/// Derefs to the inner value transparently.
87///
88/// For shared read access, use [`Res<T>`]. For optional write access
89/// (no panic if unregistered), use [`Option<ResMut<T>>`].
90///
91/// Construction is `pub(crate)` — only the dispatch layer creates these.
92pub struct ResMut<'w, T: Resource> {
93    value: &'w mut T,
94}
95
96impl<'w, T: Resource> ResMut<'w, T> {
97    pub(crate) fn new(value: &'w mut T) -> Self {
98        Self { value }
99    }
100}
101
102impl<T: std::fmt::Debug + Resource> std::fmt::Debug for ResMut<'_, T> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        self.value.fmt(f)
105    }
106}
107
108impl<T: Resource> Deref for ResMut<'_, T> {
109    type Target = T;
110
111    #[inline(always)]
112    fn deref(&self) -> &T {
113        self.value
114    }
115}
116
117impl<T: Resource> DerefMut for ResMut<'_, T> {
118    #[inline(always)]
119    fn deref_mut(&mut self) -> &mut T {
120        self.value
121    }
122}
123
124// =============================================================================
125// Seq / SeqMut — sequence number access
126// =============================================================================
127
128/// Read-only access to the world's current sequence number.
129///
130/// Appears in handler function signatures alongside other params.
131/// Derefs to [`Sequence`].
132///
133/// # Example
134///
135/// ```ignore
136/// use nexus_rt::{Seq, Handler, IntoHandler};
137///
138/// fn log_event(seq: Seq, event: u64) {
139///     println!("event {} at sequence {}", event, seq.get());
140/// }
141/// ```
142#[derive(Clone, Copy)]
143pub struct Seq(pub(crate) Sequence);
144
145impl Seq {
146    /// Returns the current sequence value.
147    #[inline(always)]
148    pub const fn get(&self) -> i64 {
149        self.0.get()
150    }
151}
152
153impl Deref for Seq {
154    type Target = Sequence;
155
156    #[inline(always)]
157    fn deref(&self) -> &Sequence {
158        &self.0
159    }
160}
161
162/// Mutable access to the world's current sequence number.
163///
164/// Allows handlers to advance the sequence — useful for stamping
165/// outbound messages with monotonic sequence numbers.
166///
167/// # Example
168///
169/// ```ignore
170/// use nexus_rt::{SeqMut, Handler, IntoHandler};
171///
172/// fn send_message(mut seq: SeqMut<'_>, event: u64) {
173///     let msg_seq = seq.advance();
174///     // stamp msg_seq on outbound message
175/// }
176/// ```
177pub struct SeqMut<'w>(pub(crate) &'w Cell<Sequence>);
178
179impl SeqMut<'_> {
180    /// Returns the current sequence value.
181    #[inline(always)]
182    pub fn get(&self) -> Sequence {
183        self.0.get()
184    }
185
186    /// Advance the sequence by 1 and return the new value.
187    #[inline(always)]
188    pub fn advance(&mut self) -> Sequence {
189        let next = Sequence(self.0.get().0.wrapping_add(1));
190        self.0.set(next);
191        next
192    }
193}
194
195// =============================================================================
196// Tests
197// =============================================================================
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202    use crate::world::Resource;
203
204    struct Val(u64);
205    impl Resource for Val {}
206
207    #[test]
208    fn res_deref() {
209        let val = Val(42);
210        let res = Res::new(&val);
211        assert_eq!(res.0, 42);
212    }
213
214    #[test]
215    fn res_mut_deref() {
216        let mut val = Val(0);
217        let mut res = ResMut::new(&mut val);
218        res.0 = 99;
219        assert_eq!(val.0, 99);
220    }
221
222    #[test]
223    fn res_mut_deref_mut_no_stamp() {
224        // ResMut::deref_mut is now a plain pass-through — no stamping.
225        let mut val = Val(0);
226        let mut res = ResMut::new(&mut val);
227        *res = Val(123);
228        assert_eq!(val.0, 123);
229    }
230
231    #[test]
232    fn seq_get() {
233        let seq = Seq(Sequence(42));
234        assert_eq!(seq.get(), 42);
235    }
236
237    #[test]
238    fn seq_mut_advance() {
239        let cell = Cell::new(Sequence(0));
240        let mut seq = SeqMut(&cell);
241        let next = seq.advance();
242        assert_eq!(next, Sequence(1));
243        assert_eq!(cell.get(), Sequence(1));
244    }
245}