//! //! Handle for recoverable process use std::any::Any; use crate::proc_data::ProcData; use crate::proc_handle::ProcHandle; use crate::state::State; use std::fmt::{self, Debug, Formatter}; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::thread; /// Recoverable handle which encapsulates a standard Proc Handle and contain all panics inside. /// /// Execution of `after_panic` will be immediate on polling the [RecoverableHandle]'s future. pub struct RecoverableHandle { inner: ProcHandle>, /// Panic callback /// /// This callback will be called if the interior future panics. It is passed the panic // reason i.e. the `Err` of [`std::thread::Result`] panicked: Option) + Send + Sync>>, } impl RecoverableHandle { pub(crate) fn new(inner: ProcHandle>) -> Self { RecoverableHandle { inner, panicked: None, } } /// Cancels the proc. /// /// If the proc has already completed, calling this method will have no effect. /// /// When a proc is cancelled, its future cannot be polled again and will be dropped instead. pub fn cancel(&self) { self.inner.cancel() } /// Returns a state of the ProcHandle. pub fn state(&self) -> State { self.inner.state() } /// Adds a callback that will be executed should the inner future `panic!`s /// /// ```rust /// # use std::any::Any; /// use lightproc::proc_stack::ProcStack; /// use lightproc::proc_state::EmptyProcState; /// # use lightproc::prelude::*; /// # /// # // ... future that does work /// # let future = async { /// # println!("Doing some work"); /// # }; /// # /// # // ... basic schedule function with no waker logic /// # fn schedule_function(proc: LightProc) {;} /// # /// # // ... process stack with a lifecycle callback /// # let proc_stack = /// # ProcStack::default() /// # .with_after_panic(|s: &mut EmptyProcState| { /// # println!("After panic started!"); /// # }); /// # /// // ... creating a recoverable process /// let (proc, recoverable) = LightProc::recoverable( /// future, /// schedule_function, /// ); /// /// recoverable /// .on_return(|_e: Box| { /// println!("Inner future panicked"); /// }); /// ``` pub fn on_panic(mut self, callback: F) -> Self where F: FnOnce(Box) + Send + Sync + 'static, { self.panicked = Some(Box::new(callback)); self } } impl Future for RecoverableHandle { type Output = Option; fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { match Pin::new(&mut self.inner).poll(cx) { Poll::Pending => Poll::Pending, Poll::Ready(None) => Poll::Ready(None), Poll::Ready(Some(Ok(val))) => Poll::Ready(Some(val)), Poll::Ready(Some(Err(e))) => { if let Some(callback) = self.panicked.take() { callback(e); } Poll::Ready(None) }, } } } impl Debug for RecoverableHandle { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { let ptr = self.inner.raw_proc.as_ptr(); let pdata = ptr as *const ProcData; fmt.debug_struct("ProcHandle") .field("pdata", unsafe { &(*pdata) }) .finish_non_exhaustive() } }