use super::tasks::{set_thread_poster, ThreadPoster};
use std::cell::RefCell;
use std::sync::Arc;
pub trait SynchronizationContext: Send + Sync {
fn post(&self, work: Box<dyn FnOnce() + Send>);
fn send(&self, work: Box<dyn FnOnce() + Send>);
fn post_local(&self, work: Box<dyn FnOnce()>);
fn send_local(&self, work: Box<dyn FnOnce()>);
fn operation_started(&self) {}
fn operation_completed(&self) {}
}
crate::ferro_thread_local! {
static CURRENT: RefCell<Option<Arc<dyn SynchronizationContext>>> = const { RefCell::new(None) };
}
pub fn current_synchronization_context() -> Option<Arc<dyn SynchronizationContext>> {
CURRENT.try_with(|current| current.borrow().clone()).ok().flatten()
}
pub fn set_synchronization_context(context: Option<Arc<dyn SynchronizationContext>>) {
let poster: Option<ThreadPoster> = context.as_ref().map(|context| {
let context = context.clone();
let poster: ThreadPoster = Arc::new(move |work: Box<dyn FnOnce() + Send>| context.post(work));
poster
});
let previous = CURRENT.try_with(|current| current.replace(context)).ok().flatten();
drop(previous);
set_thread_poster(poster);
}
impl dyn SynchronizationContext {
pub fn current() -> Option<Arc<dyn SynchronizationContext>> {
current_synchronization_context()
}
pub fn set_synchronization_context(context: Option<Arc<dyn SynchronizationContext>>) {
set_synchronization_context(context);
}
pub fn is_current(context: &Arc<dyn SynchronizationContext>) -> bool {
current_synchronization_context().is_some_and(|current| std::ptr::addr_eq(Arc::as_ptr(¤t), Arc::as_ptr(context)))
}
}