fltk/app/
channel.rs

1use fltk_sys::fl;
2use std::any::Any;
3use std::marker;
4use std::sync::LazyLock;
5
6type Chan = (
7    crossbeam_channel::Sender<Box<dyn Any + Send + Sync>>,
8    crossbeam_channel::Receiver<Box<dyn Any + Send + Sync>>,
9);
10
11static CHANNEL: LazyLock<Chan> = LazyLock::new(crossbeam_channel::unbounded);
12static SENDER: LazyLock<crossbeam_channel::Sender<Box<dyn Any + Send + Sync>>> =
13    LazyLock::new(|| CHANNEL.clone().0);
14static RECEIVER: LazyLock<crossbeam_channel::Receiver<Box<dyn Any + Send + Sync>>> =
15    LazyLock::new(|| CHANNEL.clone().1);
16
17#[doc(hidden)]
18/// Sends a custom message
19/// # Safety
20/// The type must be Send and Sync safe
21pub unsafe fn awake_msg<T>(msg: T) {
22    unsafe {
23        fl::Fl_awake_msg(Box::into_raw(Box::from(msg)) as *mut std::os::raw::c_void);
24    }
25}
26
27#[doc(hidden)]
28/**
29    Receives a custom message
30    ```rust,no_run
31    use fltk::{prelude::*, *};
32    if let Some(msg) = unsafe { app::thread_msg::<i32>() } { /* do something */ }
33    ```
34    # Safety
35    The type must correspond to the received message
36*/
37pub unsafe fn thread_msg<T>() -> Option<T> {
38    unsafe {
39        let msg = fl::Fl_thread_msg();
40        if msg.is_null() {
41            None
42        } else {
43            let msg = Box::from_raw(msg as *const _ as *mut T);
44            Some(*msg)
45        }
46    }
47}
48
49/// Creates a sender struct
50#[derive(Debug)]
51pub struct Sender<T> {
52    data: marker::PhantomData<T>,
53}
54
55unsafe impl<T: Send + Sync> Send for Sender<T> {}
56unsafe impl<T: Send + Sync> Sync for Sender<T> {}
57impl<T: Send + Sync> Copy for Sender<T> {}
58
59// Manually create the impl so there's no Clone bound on T
60impl<T: Send + Sync> Clone for Sender<T> {
61    fn clone(&self) -> Self {
62        *self
63    }
64}
65
66impl<T: 'static + Send + Sync> Sender<T> {
67    /// Sends a message
68    pub fn send(&self, val: T) {
69        SENDER.try_send(Box::new(val)).ok();
70        crate::app::awake();
71    }
72    /// Get the global sender
73    pub fn get() -> Self {
74        Sender {
75            data: marker::PhantomData,
76        }
77    }
78}
79
80/// Creates a receiver struct
81#[derive(Debug)]
82pub struct Receiver<T> {
83    data: marker::PhantomData<T>,
84}
85
86unsafe impl<T: Send + Sync> Send for Receiver<T> {}
87unsafe impl<T: Send + Sync> Sync for Receiver<T> {}
88impl<T: Send + Sync> Copy for Receiver<T> {}
89
90// Manually create the impl so there's no Clone bound on T
91impl<T: Send + Sync> Clone for Receiver<T> {
92    fn clone(&self) -> Self {
93        *self
94    }
95}
96
97impl<T: 'static + Send + Sync> Receiver<T> {
98    /// Receives a message
99    pub fn recv(&self) -> Option<T> {
100        if let Ok(msg) = RECEIVER.try_recv() {
101            if let Ok(t) = (msg as Box<dyn Any + 'static>).downcast::<T>() {
102                Some(*t)
103            } else {
104                None
105            }
106        } else {
107            None
108        }
109    }
110    /// Get the global receiver
111    pub fn get() -> Self {
112        Receiver {
113            data: marker::PhantomData,
114        }
115    }
116}
117
118/// Creates a channel returning a Sender and Receiver structs (mpsc: multiple producer single consumer).
119pub fn channel<T: Send + Sync>() -> (Sender<T>, Receiver<T>) {
120    let s = Sender {
121        data: marker::PhantomData,
122    };
123    let r = Receiver {
124        data: marker::PhantomData,
125    };
126    (s, r)
127}