use libc::{c_int, c_char, c_void};
use std::any::Any;
use std::panic;
use std::slice;
pub struct CallbackState<F> {
cb: Option<F>,
panic: Option<Box<Any + Send + 'static>>,
}
impl<F> CallbackState<F> {
pub fn new(callback: F) -> Self {
CallbackState {
cb: Some(callback),
panic: None,
}
}
}
impl<F> Drop for CallbackState<F> {
fn drop(&mut self) {
if let Some(panic) = self.panic.take() {
panic::resume_unwind(panic);
}
}
}
pub extern "C" fn invoke_passwd_cb<F>(buf: *mut c_char,
size: c_int,
_rwflag: c_int,
cb_state: *mut c_void)
-> c_int
where F: FnOnce(&mut [c_char]) -> usize {
let result = panic::catch_unwind(|| {
let pass_slice = unsafe { slice::from_raw_parts_mut(buf, size as usize) };
let callback = unsafe { &mut *(cb_state as *mut CallbackState<F>) };
callback.cb.take().unwrap()(pass_slice)
});
if let Ok(len) = result {
return len as c_int;
} else {
return 0;
}
}