1#![forbid(unsafe_code)]
7
8use mesh::MeshPayload;
9use mesh::payload::DefaultEncoding;
10use mesh::payload::FieldDecode;
11use mesh::payload::FieldEncode;
12use mesh::payload::inplace::InplaceOption;
13use mesh::resource::Resource;
14use pal_async::driver::SpawnDriver;
15use pal_async::task::Task;
16use pal_async::wait::PolledWait;
17use pal_event::Event;
18use std::fmt::Debug;
19use std::sync::Arc;
20use std::sync::OnceLock;
21
22#[derive(Clone, Debug, MeshPayload)]
32pub struct Interrupt {
33 #[mesh(encoding = "InterruptEncoding")]
34 inner: Arc<InterruptInner>,
35}
36
37impl Default for Interrupt {
38 fn default() -> Self {
39 Self::null()
40 }
41}
42
43impl Interrupt {
44 pub fn null() -> Self {
50 Self::from_target(NullEventTarget)
51 }
52
53 pub fn from_event(event: Event) -> Self {
57 let event = Arc::new(event);
58 Self {
59 inner: Arc::new(InterruptInner {
60 event: OnceLock::from(Some(event.clone())),
61 t: EventTarget(event),
62 }),
63 }
64 }
65
66 pub fn from_fn<F>(f: F) -> Self
71 where
72 F: 'static + Send + Sync + Fn(),
73 {
74 Self {
75 inner: Arc::new(InterruptInner {
76 event: OnceLock::new(),
77 t: FnTarget(f),
78 }),
79 }
80 }
81
82 pub fn from_target(target: impl InterruptTarget + 'static) -> Self {
84 Self {
85 inner: Arc::new(InterruptInner {
86 event: OnceLock::new(),
87 t: target,
88 }),
89 }
90 }
91
92 pub fn deliver(&self) {
94 self.inner.t.deliver();
95 }
96
97 pub fn event(&self) -> Option<&Event> {
102 self.inner.event().as_deref()
103 }
104
105 pub fn event_or_proxy(
113 &self,
114 driver: &impl SpawnDriver,
115 ) -> std::io::Result<(Event, Option<EventProxy>)> {
116 if let Some(event) = self.event() {
117 Ok((event.clone(), None))
118 } else {
119 let (proxy, event) = EventProxy::new(driver, self.clone())?;
120 Ok((event, Some(proxy)))
121 }
122 }
123}
124
125pub trait InterruptTarget: Send + Sync {
130 fn deliver(&self);
132
133 fn event(&self) -> Option<Arc<Event>> {
139 None
140 }
141}
142
143struct InterruptInner<T: ?Sized = dyn InterruptTarget> {
144 event: OnceLock<Option<Arc<Event>>>,
145 t: T,
146}
147
148impl Debug for InterruptInner {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 f.pad("InterruptInner")
151 }
152}
153
154impl InterruptInner {
155 fn event(&self) -> &Option<Arc<Event>> {
156 self.event.get_or_init(|| self.t.event())
157 }
158}
159
160struct EventTarget(Arc<Event>);
162
163impl InterruptTarget for EventTarget {
164 fn deliver(&self) {
165 self.0.signal();
166 }
167
168 fn event(&self) -> Option<Arc<Event>> {
169 Some(self.0.clone())
170 }
171}
172
173struct FnTarget<F>(F);
175
176impl<F: Send + Sync + Fn()> InterruptTarget for FnTarget<F> {
177 fn deliver(&self) {
178 (self.0)()
179 }
180}
181
182struct NullEventTarget;
184
185impl InterruptTarget for NullEventTarget {
186 fn deliver(&self) {}
187
188 fn event(&self) -> Option<Arc<Event>> {
189 Some(Arc::new(Event::new()))
190 }
191}
192
193struct InterruptEncoding;
194
195type EventFieldEncoding = <Event as DefaultEncoding>::Encoding;
196
197impl FieldEncode<Arc<InterruptInner>, Resource> for InterruptEncoding {
198 fn write_field(
199 item: Arc<InterruptInner>,
200 writer: mesh::payload::protobuf::FieldWriter<'_, '_, Resource>,
201 ) {
202 if let Some(event) = item.event() {
203 EventFieldEncoding::write_field_in_sequence((**event).clone(), &mut writer.sequence());
204 } else {
205 tracing::warn!("encoding local-only interrupt");
206 }
207 }
208
209 fn compute_field_size(
210 item: &mut Arc<InterruptInner>,
211 sizer: mesh::payload::protobuf::FieldSizer<'_>,
212 ) {
213 if item.event().is_some() {
214 sizer.sequence().field().resource();
215 }
216 }
217
218 fn wrap_in_sequence() -> bool {
219 true
220 }
221}
222
223impl FieldDecode<'_, Arc<InterruptInner>, Resource> for InterruptEncoding {
224 fn read_field(
225 item: &mut InplaceOption<'_, Arc<InterruptInner>>,
226 reader: mesh::payload::protobuf::FieldReader<'_, '_, Resource>,
227 ) -> mesh::payload::Result<()> {
228 mesh::payload::inplace_none!(event: Event);
229 EventFieldEncoding::read_field_in_sequence(&mut event, reader)?;
230 let event = Arc::new(event.take().unwrap());
231 item.set(Arc::new(InterruptInner {
232 event: OnceLock::from(Some(event.clone())),
233 t: EventTarget(event),
234 }));
235 Ok(())
236 }
237
238 fn default_field(
239 _item: &mut InplaceOption<'_, Arc<InterruptInner>>,
240 ) -> mesh::payload::Result<()> {
241 Err(mesh::payload::Error::new(
242 "missing event in serialized interrupt",
243 ))
244 }
245
246 fn wrap_in_sequence() -> bool {
247 true
248 }
249}
250
251pub struct EventProxy {
258 _task: Task<()>,
259}
260
261impl EventProxy {
262 pub fn new(driver: &impl SpawnDriver, interrupt: Interrupt) -> std::io::Result<(Self, Event)> {
265 let event = Event::new();
266 let wait = PolledWait::new(driver, event.clone())?;
267 let task = driver.spawn("interrupt-event-proxy", async move {
268 Self::run(wait, interrupt).await;
269 });
270 Ok((Self { _task: task }, event))
271 }
272
273 async fn run(mut wait: PolledWait<Event>, interrupt: Interrupt) {
274 loop {
275 wait.wait().await.expect("wait should not fail");
276 interrupt.deliver();
277 }
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use super::Interrupt;
284 use super::InterruptTarget;
285 use pal_async::DefaultDriver;
286 use pal_async::async_test;
287 use pal_event::Event;
288 use std::sync::Arc;
289 use std::sync::atomic::{AtomicUsize, Ordering};
290
291 #[test]
292 fn test_interrupt_event() {
293 let event = Event::new();
294 let interrupt = Interrupt::from_event(event.clone());
295 interrupt.deliver();
296 assert!(event.try_wait());
297 }
298
299 #[test]
300 fn test_interrupt_fn() {
301 let count = Arc::new(AtomicUsize::new(0));
302 let count2 = count.clone();
303 let interrupt = Interrupt::from_fn(move || {
304 count2.fetch_add(1, Ordering::SeqCst);
305 });
306 interrupt.deliver();
307 interrupt.deliver();
308 assert_eq!(count.load(Ordering::SeqCst), 2);
309 }
310
311 #[test]
312 fn test_interrupt_null_does_not_signal() {
313 let interrupt = Interrupt::null();
314 interrupt.deliver();
316 }
317
318 #[test]
319 fn test_event_backed_has_event() {
320 let event = Event::new();
321 let interrupt = Interrupt::from_event(event.clone());
322 assert!(interrupt.event().is_some());
323 }
324
325 #[test]
326 fn test_fn_backed_has_no_event() {
327 let interrupt = Interrupt::from_fn(|| {});
328 assert!(interrupt.event().is_none());
329 }
330
331 #[test]
332 fn test_null_has_event() {
333 let interrupt = Interrupt::null();
334 assert!(interrupt.event().is_some());
336 }
337
338 #[test]
339 fn test_null_event_is_stable() {
340 let interrupt = Interrupt::null();
341 let e1 = std::ptr::from_ref::<Event>(interrupt.event().unwrap());
342 let e2 = std::ptr::from_ref::<Event>(interrupt.event().unwrap());
343 assert_eq!(
344 e1, e2,
345 "event() should return the same event on repeated calls"
346 );
347 }
348
349 #[test]
350 fn test_from_target() {
351 struct TestTarget {
352 count: Arc<AtomicUsize>,
353 }
354 impl InterruptTarget for TestTarget {
355 fn deliver(&self) {
356 self.count.fetch_add(1, Ordering::SeqCst);
357 }
358 }
359 let count = Arc::new(AtomicUsize::new(0));
360 let interrupt = Interrupt::from_target(TestTarget {
361 count: count.clone(),
362 });
363 interrupt.deliver();
364 assert_eq!(count.load(Ordering::SeqCst), 1);
365 assert!(interrupt.event().is_none());
366 }
367
368 #[test]
369 fn test_from_target_with_event() {
370 struct TestTarget(Arc<Event>);
371 impl InterruptTarget for TestTarget {
372 fn deliver(&self) {
373 self.0.signal();
374 }
375 fn event(&self) -> Option<Arc<Event>> {
376 Some(self.0.clone())
377 }
378 }
379 let event = Arc::new(Event::new());
380 let interrupt = Interrupt::from_target(TestTarget(event.clone()));
381 assert!(interrupt.event().is_some());
382 interrupt.deliver();
383 assert!(event.try_wait());
384 }
385
386 #[test]
387 fn test_clone_shares_state() {
388 let count = Arc::new(AtomicUsize::new(0));
389 let count2 = count.clone();
390 let interrupt = Interrupt::from_fn(move || {
391 count2.fetch_add(1, Ordering::SeqCst);
392 });
393 let cloned = interrupt.clone();
394 interrupt.deliver();
395 cloned.deliver();
396 assert_eq!(count.load(Ordering::SeqCst), 2);
397 }
398
399 #[test]
400 fn test_default_is_null() {
401 let interrupt = Interrupt::default();
402 interrupt.deliver();
404 assert!(interrupt.event().is_some());
405 }
406
407 #[test]
408 fn test_mesh_round_trip_event_backed() {
409 let event = Event::new();
410 let interrupt = Interrupt::from_event(event);
411 let msg = mesh::payload::SerializedMessage::from_message(interrupt);
412 let decoded: Interrupt = msg.into_message().unwrap();
413 assert!(decoded.event().is_some());
415 decoded.deliver();
416 }
417
418 #[async_test]
419 async fn test_event_or_proxy_event_backed(driver: DefaultDriver) {
420 let orig_event = Event::new();
421 let interrupt = Interrupt::from_event(orig_event.clone());
422 let (event, proxy) = interrupt.event_or_proxy(&driver).unwrap();
423 assert!(proxy.is_none());
425 event.signal();
426 assert!(orig_event.try_wait());
427 }
428
429 #[async_test]
430 async fn test_event_or_proxy_fn_backed(driver: DefaultDriver) {
431 let count = Arc::new(AtomicUsize::new(0));
432 let count2 = count.clone();
433 let interrupt = Interrupt::from_fn(move || {
434 count2.fetch_add(1, Ordering::SeqCst);
435 });
436 let (event, proxy) = interrupt.event_or_proxy(&driver).unwrap();
437 assert!(proxy.is_some());
439 event.signal();
441 for _ in 0..100 {
443 if count.load(Ordering::SeqCst) > 0 {
444 break;
445 }
446 pal_async::timer::PolledTimer::new(&driver)
447 .sleep(std::time::Duration::from_millis(10))
448 .await;
449 }
450 assert_eq!(count.load(Ordering::SeqCst), 1);
451 }
452}