fltk/app/
channel.rs

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