use super::{BreadThread, Controller, Error, ThreadState};
use orphan_crippler::Receiver;
use std::{
any::Any,
sync::{mpsc, Arc, Weak},
thread,
};
use thread_safe::ThreadKey;
#[repr(transparent)]
pub struct ThreadHandle<'evh, Ctrl: Controller> {
state: Weak<ThreadState<'evh, Ctrl>>,
}
impl<'evh, Ctrl: Controller> Clone for ThreadHandle<'evh, Ctrl> {
#[inline]
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
}
}
}
impl<'evh, Ctrl: Controller> ThreadHandle<'evh, Ctrl> {
#[inline]
fn state(&self) -> Result<Arc<ThreadState<'evh, Ctrl>>, Error<Ctrl::Error>> {
match self.state.upgrade() {
Some(state) => Ok(state),
None => Err(Error::Closed),
}
}
#[inline]
pub(crate) fn from_weak(state: Weak<ThreadState<'evh, Ctrl>>) -> Self {
Self { state }
}
#[inline]
pub fn send_directive<T: Any + Send>(
&self,
directive: Ctrl::Directive,
) -> Result<Receiver<T>, Error<Ctrl::Error>> {
let state = self.state()?;
state.send_directive(directive, ThreadKey::get())
}
#[inline]
pub fn set_event_handler<
F: FnMut(&Ctrl, Ctrl::Event) -> Result<(), Ctrl::Error> + Send + 'evh,
>(
&self,
event_handler: F,
) -> Result<(), Error<Ctrl::Error>> {
let state = self.state()?;
state.set_event_handler(event_handler);
Ok(())
}
#[inline]
pub fn process_event(&self, event: Ctrl::Event) -> Result<(), Error<Ctrl::Error>> {
let state = self.state()?;
state.process_event(event, ThreadKey::get())
}
#[inline]
pub fn with<T, F: FnOnce(&Ctrl) -> T>(&self, f: F) -> Result<T, Error<Ctrl::Error>> {
let state = self.state()?;
state.with(f, ThreadKey::get())
}
#[inline]
pub fn pin(self) -> PinnedThreadHandle<'evh, Ctrl> {
PinnedThreadHandle {
inner: self,
key: ThreadKey::get(),
}
}
}
impl<Ctrl: Controller + Send + 'static> ThreadHandle<'static, Ctrl> {
#[inline]
pub fn in_foreign_thread(controller: Ctrl) -> ThreadHandle<'static, Ctrl> {
let (sender, receiver) = mpsc::channel::<ThreadHandle<'static, Ctrl>>();
thread::Builder::new()
.name("bread-thread".to_string())
.spawn(move || {
let bt = BreadThread::new(controller);
let th = bt.handle();
sender
.send(th)
.expect("Receiver shouldn't have closed down already");
bt.main_loop()
.unwrap_or_else(|_| panic!("Main loop failed"));
})
.expect("Unable to create foreign thread");
receiver
.recv()
.expect("Sender shouldn't close down without sending")
}
}
pub struct PinnedThreadHandle<'evh, Ctrl: Controller> {
inner: ThreadHandle<'evh, Ctrl>,
key: ThreadKey,
}
impl<'evh, Ctrl: Controller> Clone for PinnedThreadHandle<'evh, Ctrl> {
#[inline]
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
key: self.key,
}
}
}
impl<'evh, Ctrl: Controller> PinnedThreadHandle<'evh, Ctrl> {
#[inline]
pub fn send_directive<T: Any + Send>(
&self,
directive: Ctrl::Directive,
) -> Result<Receiver<T>, Error<Ctrl::Error>> {
let state = self.inner.state()?;
state.send_directive(directive, self.key)
}
#[inline]
pub fn set_event_handler<
F: FnMut(&Ctrl, Ctrl::Event) -> Result<(), Ctrl::Error> + Send + 'evh,
>(
&self,
event_handler: F,
) -> Result<(), Error<Ctrl::Error>> {
self.inner.set_event_handler(event_handler)
}
#[inline]
pub fn process_event(&self, event: Ctrl::Event) -> Result<(), Error<Ctrl::Error>> {
let state = self.inner.state()?;
state.process_event(event, self.key)
}
#[inline]
pub fn with<T, F: FnOnce(&Ctrl) -> T>(&self, f: F) -> Result<T, Error<Ctrl::Error>> {
let state = self.inner.state()?;
state.with(f, self.key)
}
#[inline]
pub fn into_inner(self) -> ThreadHandle<'evh, Ctrl> {
self.inner
}
}