use super::proc_state::*;
use std::fmt::{self, Debug, Formatter};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
pub struct ProcStack {
pub pid: AtomicUsize,
pub(crate) state: ProcState,
pub(crate) before_start: Option<Arc<dyn Fn(ProcState) + Send + Sync>>,
pub(crate) after_complete: Option<Arc<dyn Fn(ProcState) + Send + Sync>>,
pub(crate) after_panic: Option<Arc<dyn Fn(ProcState) + Send + Sync>>,
}
impl ProcStack {
pub fn with_pid(mut self, pid: usize) -> Self {
self.pid = AtomicUsize::new(pid);
self
}
pub fn with_state<S>(mut self, state: S) -> Self
where
S: State + 'static,
{
self.state = Arc::new(Mutex::new(state));
self
}
pub fn with_before_start<C, S>(mut self, callback: C) -> Self
where
S: State,
C: Fn(&mut S) + Send + Sync + 'static,
{
self.before_start = Some(self.wrap_callback(callback));
self
}
pub fn with_after_complete<C, S>(mut self, callback: C) -> Self
where
S: State,
C: Fn(&mut S) + Send + Sync + 'static,
{
self.after_complete = Some(self.wrap_callback(callback));
self
}
pub fn with_after_panic<C, S>(mut self, callback: C) -> Self
where
S: State,
C: Fn(&mut S) + Send + Sync + 'static,
{
self.after_panic = Some(self.wrap_callback(callback));
self
}
pub fn get_pid(&self) -> usize {
self.pid.load(Ordering::Acquire)
}
pub fn get_state<S>(&self) -> S
where
S: State + Copy + 'static,
{
let state = self.state.clone();
let s = unsafe { &*(&state as *const ProcState as *const Arc<Mutex<S>>) };
*s.lock().unwrap()
}
fn wrap_callback<C, S>(&self, callback: C) -> Arc<dyn Fn(ProcState) + Send + Sync>
where
S: State + 'static,
C: Fn(&mut S) + Send + Sync + 'static,
{
let wrapped = move |s: ProcState| {
let x = unsafe { &*(&s as *const ProcState as *const Arc<Mutex<S>>) };
let mut mg = x.lock().unwrap();
callback(&mut *mg);
};
Arc::new(wrapped)
}
}
impl Default for ProcStack {
fn default() -> Self {
ProcStack {
pid: AtomicUsize::new(0xDEAD_BEEF),
state: Arc::new(Mutex::new(EmptyState)),
before_start: None,
after_complete: None,
after_panic: None,
}
}
}
impl Debug for ProcStack {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.debug_struct("ProcStack")
.field("pid", &self.pid.load(Ordering::SeqCst))
.field("state", &self.state)
.field("before_start", &self.before_start.is_some())
.field("after_complete", &self.after_complete.is_some())
.field("after_panic", &self.after_panic.is_some())
.finish()
}
}
impl Clone for ProcStack {
fn clone(&self) -> Self {
ProcStack {
pid: AtomicUsize::new(self.pid.load(Ordering::Acquire)),
state: self.state.clone(),
before_start: self.before_start.clone(),
after_complete: self.after_complete.clone(),
after_panic: self.after_panic.clone(),
}
}
}