Skip to main content

des_sim/modeling/hook/instance/
shared.rs

1//! The `shared` module provides the `SharedHook` wrapper, enabling thread-safe
2//! sharing of `Hook` implementations across different parts of the simulation.
3//!
4//! By leveraging `Arc`, `SharedHook` allows multiple components to register
5//! and receive lifecycle events from the same hook instance, facilitating
6//! centralized logging, metrics collection, or debugging in concurrent scenarios.
7
8use crate::modeling::event::Event;
9use crate::modeling::hook::Hook;
10use crate::modeling::model::Model;
11use crate::primitive::time::{Duration, MicroStep, SimTime};
12use crate::source_handler::{SourceReadyEntry, SourceView};
13use std::marker::PhantomData;
14use std::sync::Arc;
15
16/// A wrapper that allows a hook to be shared across multiple components via `Arc`.
17pub struct SharedHook<E, M: Model<E>, H: Hook<E, M>> {
18    inner: Arc<H>,
19    _event: PhantomData<E>,
20    _model: PhantomData<M>,
21}
22
23impl<E, M: Model<E>, H: Hook<E, M>> Clone for SharedHook<E, M, H> {
24    fn clone(&self) -> Self {
25        SharedHook {
26            inner: Arc::clone(&self.inner),
27            _event: PhantomData,
28            _model: PhantomData,
29        }
30    }
31}
32
33impl<E, M: Model<E>, H> Hook<E, M> for SharedHook<E, M, H>
34where
35    H: Hook<E, M>,
36{
37    // --- Simulation lifecycle ---
38
39    fn before_simulation(&self, model: &M) {
40        self.inner.as_ref().before_simulation(model)
41    }
42
43    fn after_simulation(&self, model: &M, end_tick: SimTime) {
44        self.inner.as_ref().after_simulation(model, end_tick)
45    }
46
47    // --- Tick lifecycle ---
48
49    fn before_tick(&self, model: &M, current_tick: SimTime, skipped_duration: Duration) {
50        self.inner
51            .as_ref()
52            .before_tick(model, current_tick, skipped_duration)
53    }
54
55    fn after_tick(&self, model: &M, current_tick: SimTime, last_micro_step: MicroStep) {
56        self.inner
57            .as_ref()
58            .after_tick(model, current_tick, last_micro_step)
59    }
60
61    fn before_micro_step(&self, model: &M, current_tick: SimTime, current_micro_step: MicroStep) {
62        self.inner
63            .as_ref()
64            .before_micro_step(model, current_tick, current_micro_step)
65    }
66
67    fn after_micro_step(&self, model: &M, current_tick: SimTime, current_micro_step: MicroStep) {
68        self.inner
69            .as_ref()
70            .after_micro_step(model, current_tick, current_micro_step)
71    }
72
73    fn on_discard_remain_micro_step(
74        &self,
75        model: &M,
76        current_tick: SimTime,
77        first_discarded_micro_step: MicroStep,
78        discarded_sources: &[SourceReadyEntry],
79        discarded_events: &[Event<E>],
80    ) {
81        self.inner.as_ref().on_discard_remain_micro_step(
82            model,
83            current_tick,
84            first_discarded_micro_step,
85            discarded_sources,
86            discarded_events,
87        )
88    }
89
90    // --- Source lifecycle ---
91
92    fn before_register_source(&self, model: &M, name: &str) {
93        self.inner.as_ref().before_register_source(model, name)
94    }
95
96    fn after_register_source(&self, model: &M, name: &str) {
97        self.inner.as_ref().after_register_source(model, name)
98    }
99
100    fn before_source_phase(&self, model: &M, current_tick: SimTime, current_micro_step: MicroStep) {
101        self.inner
102            .as_ref()
103            .before_source_phase(model, current_tick, current_micro_step)
104    }
105
106    fn before_source(
107        &self,
108        model: &M,
109        current_tick: SimTime,
110        current_micro_step: MicroStep,
111        source_view: &SourceView,
112    ) {
113        self.inner
114            .as_ref()
115            .before_source(model, current_tick, current_micro_step, source_view)
116    }
117
118    fn after_source(
119        &self,
120        model: &M,
121        current_tick: SimTime,
122        current_micro_step: MicroStep,
123        source_view: &SourceView,
124        computed_next_fire: Option<SimTime>,
125    ) {
126        self.inner.as_ref().after_source(
127            model,
128            current_tick,
129            current_micro_step,
130            source_view,
131            computed_next_fire,
132        )
133    }
134
135    fn cancel_source(
136        &self,
137        model: &M,
138        current_tick: SimTime,
139        current_micro_step: MicroStep,
140        scheduled_at: SimTime,
141        source_view: &SourceView,
142    ) {
143        self.inner.as_ref().cancel_source(
144            model,
145            current_tick,
146            current_micro_step,
147            scheduled_at,
148            source_view,
149        )
150    }
151
152    fn discard_source(
153        &self,
154        model: &M,
155        current_tick: SimTime,
156        current_micro_step: MicroStep,
157        source_view: &SourceView,
158    ) {
159        self.inner
160            .as_ref()
161            .discard_source(model, current_tick, current_micro_step, source_view)
162    }
163
164    fn after_source_phase(&self, model: &M, current_tick: SimTime, current_micro_step: MicroStep) {
165        self.inner
166            .as_ref()
167            .after_source_phase(model, current_tick, current_micro_step)
168    }
169
170    // --- Event lifecycle ---
171
172    fn before_event_phase(&self, model: &M, current_tick: SimTime, current_micro_step: MicroStep) {
173        self.inner
174            .as_ref()
175            .before_event_phase(model, current_tick, current_micro_step)
176    }
177
178    fn before_event(
179        &self,
180        model: &M,
181        current_tick: SimTime,
182        current_micro_step: MicroStep,
183        event: &Event<E>,
184    ) {
185        self.inner
186            .as_ref()
187            .before_event(model, current_tick, current_micro_step, event)
188    }
189
190    fn after_event(
191        &self,
192        model: &M,
193        current_tick: SimTime,
194        current_micro_step: MicroStep,
195        event: &Event<E>,
196    ) {
197        self.inner
198            .as_ref()
199            .after_event(model, current_tick, current_micro_step, event)
200    }
201
202    fn cancel_event(
203        &self,
204        model: &M,
205        current_tick: SimTime,
206        current_micro_step: MicroStep,
207        scheduled_at: SimTime,
208        event: &Event<E>,
209    ) {
210        self.inner.as_ref().cancel_event(
211            model,
212            current_tick,
213            current_micro_step,
214            scheduled_at,
215            event,
216        )
217    }
218
219    fn discard_event(
220        &self,
221        model: &M,
222        current_tick: SimTime,
223        current_micro_step: MicroStep,
224        event: &Event<E>,
225    ) {
226        self.inner
227            .as_ref()
228            .discard_event(model, current_tick, current_micro_step, event)
229    }
230
231    fn after_event_phase(&self, model: &M, current_tick: SimTime, current_micro_step: MicroStep) {
232        self.inner
233            .as_ref()
234            .after_event_phase(model, current_tick, current_micro_step)
235    }
236}
237
238impl<E, M: Model<E>, H: Hook<E, M>> SharedHook<E, M, H> {
239    /// Creates a new `SharedHook` wrapping the provided hook.
240    pub fn new(hook: H) -> Self {
241        Self {
242            inner: Arc::new(hook),
243            _event: PhantomData,
244            _model: PhantomData,
245        }
246    }
247
248    /// Returns a reference to the underlying hook.
249    pub fn get_ref(&self) -> &H {
250        &self.inner
251    }
252}