use std::sync::mpsc::Sender;
use once_cell::sync::Lazy;
use crate::error::Error;
use crate::runtime::execution::RUNTIME;
use crate::runtime::work::Work;
thread_local! {
pub(super) static RUNTIME_THREAD_LOCAL: Lazy<RuntimeThreadLocal> = Lazy::new(|| {
RUNTIME.lock().unwrap().thread_local()
});
}
pub struct RuntimeThreadLocal(Sender<Work>);
impl RuntimeThreadLocal {
pub(super) fn from_sender(sender: Sender<Work>) -> Self {
RuntimeThreadLocal(sender)
}
pub(super) fn enqueue(&self, function: Work) -> Result<(), Error> {
self.0.send(function).map_err(|_| Error::Runtime)
}
}
#[inline]
pub fn enqueue_decoupled(f: impl FnOnce() + Send + 'static) {
let f = Box::new(f);
RUNTIME_THREAD_LOCAL
.with(|runtime| runtime.enqueue(Work::new(f)))
.expect("runtime broken")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_enqueue_works() {
let (tx, rx) = std::sync::mpsc::channel();
assert!(RUNTIME_THREAD_LOCAL
.with(|runtime| {
runtime.enqueue(Work::new(move || {
assert!(tx.send(true).is_ok());
}))
})
.is_ok());
assert!(matches!(
rx.recv_timeout(std::time::Duration::from_millis(100)),
Ok(true),
));
}
#[test]
fn test_enqueue_decoupled_works() {
let (tx, rx) = std::sync::mpsc::channel();
enqueue_decoupled(move || {
assert!(tx.send(true).is_ok());
});
assert!(matches!(
rx.recv_timeout(std::time::Duration::from_millis(100)),
Ok(true),
));
}
}