use std::any::Any;
use std::marker::PhantomData;
use std::panic;
use ::traits::{IntegrandInput, IntegrandOutput};
use ::Real;
pub struct LandingPad<A, B, F: FnMut(A) -> B> {
err: Option<Box<Any + Send + 'static>>,
fun: F,
a: PhantomData<A>,
b: PhantomData<B>,
}
impl<A: IntegrandInput, B: IntegrandOutput, F: FnMut(A) -> B> LandingPad<A, B, F> {
pub fn new(fun: F) -> Self {
LandingPad {
err: None, fun: fun,
a: PhantomData, b: PhantomData,
}
}
pub fn try_call(&mut self, args: &[Real], output: &mut [Real]) -> Result<(), &(Any + Send + 'static)> {
if self.err.is_some() {
Err(self.err.as_ref().expect("just said it is some"))
} else {
let res = {
let mut borself = panic::AssertUnwindSafe(&mut *self);
let mut output_buf = panic::AssertUnwindSafe(&mut *output);
panic::catch_unwind(move || {
let lp: &mut LandingPad<A, B, F> = &mut borself;
(lp.fun)(A::from_args(args)).into_args(&mut *output_buf)
})
};
match res {
Ok(()) => Ok(()),
Err(err) => {
self.err = Some(err);
Err(self.err.as_ref().expect("just set to Some(..)"))
}
}
}
}
pub(crate) fn raw_call(&mut self, args: &[Real]) -> B {
(self.fun)(A::from_args(args))
}
pub fn maybe_resume_unwind(self) {
if self.err.is_some() {
self.resume_unwind()
}
}
pub fn finish(self) -> Option<Box<Any + Send + 'static>> {
self.err
}
fn resume_unwind(self) -> ! {
panic::resume_unwind(self.err.expect("trying to resume unwind"))
}
}