1use std::any::Any;
2use std::cell::UnsafeCell;
3use std::mem;
4use std::sync::atomic::{AtomicBool, Ordering};
5use super::unwind;
6
7pub enum JobResult<T> {
9 None,
10 Ok(T),
11 Panic(Box<dyn Any + Send>),
12}
13
14pub struct StackJob<F, R> {
16 func: UnsafeCell<Option<F>>,
17 result: UnsafeCell<JobResult<R>>,
18 latch: AtomicBool,
19}
20
21impl<F, R> StackJob<F, R> {
22 pub fn new(f: F) -> Self
23 where F: FnOnce() -> R + Send
24 {
25 Self {
26 func: UnsafeCell::new(Some(f)),
27 result: UnsafeCell::new(JobResult::None),
28 latch: AtomicBool::new(false),
29 }
30 }
31
32 #[inline]
33 pub fn into_result(self) -> R {
34 unsafe {
35 debug_assert!((*self.func.get()).is_none());
36 match mem::replace(&mut *self.result.get(), JobResult::None) {
37 JobResult::None => unreachable!(),
38 JobResult::Ok(r) => r,
39 JobResult::Panic(x) => unwind::resume_unwinding(x),
40 }
41 }
42 }
43 pub fn probe(&self) -> bool {
44 self.latch.load(Ordering::Acquire)
45 }
46}
47
48impl<F, R> Job for StackJob<F, R>
49where
50 F: FnOnce() -> R + Send,
52 R: Send,
53{
54 #[inline]
55 unsafe fn execute(this: *const Self) {
56 let this = &*this;
57 let abort = unwind::AbortIfPanic;
58 let func = (*this.func.get()).take().unwrap();
59 (*this.result.get()) = match unwind::halt_unwinding(|| func()) {
60 Ok(x) => JobResult::Ok(x),
61 Err(x) => JobResult::Panic(x),
62 };
63 this.latch.store(true, Ordering::Release);
64 mem::forget(abort);
66 }
67}
68
69
70pub trait Job {
76 unsafe fn execute(this: *const Self);
80}
81
82#[derive(Copy, Clone, Debug, PartialEq, Eq)]
89pub struct JobRef {
90 pointer: *const (),
91 execute_fn: unsafe fn(*const ()),
92}
93
94unsafe impl Send for JobRef {}
95unsafe impl Sync for JobRef {}
96
97impl JobRef {
98 pub unsafe fn new<T>(data: *const T) -> JobRef
101 where
102 T: Job + Send,
103 {
104 let fn_ptr: unsafe fn(*const T) = <T as Job>::execute;
105
106 let fn_ptr: unsafe fn(*const ()) = mem::transmute(fn_ptr);
108 let pointer = data as *const ();
109
110 JobRef {
111 pointer: pointer,
112 execute_fn: fn_ptr,
113 }
114 }
115
116 #[inline]
117 pub unsafe fn execute(&self) {
118 (self.execute_fn)(self.pointer)
119 }
120}
121