use anyhow::anyhow;
use serde::{Deserialize, Serialize};
pub unsafe fn fork_map<F, R>(func: F) -> anyhow::Result<R>
where
F: Fn() -> anyhow::Result<R>,
R: Serialize + for<'a> Deserialize<'a>,
{
let mut pipe: [libc::c_int; 2] = [0; 2];
libc::pipe(pipe.as_mut_ptr());
let pid = libc::fork();
if pid == 0 {
libc::close(pipe[0]);
let result = func().map_err(|e| serde_error::Error::new(&*e));
let ser = serde_json::to_string(&result).unwrap_or("".to_string());
libc::write(pipe[1], ser.as_ptr() as *const libc::c_void, ser.len());
libc::close(pipe[1]);
libc::exit(0);
}
libc::close(pipe[1]);
let mut des = vec![];
let des = loop {
const BUF_SIZE: usize = 0x1000;
let mut buf: [u8; BUF_SIZE] = [0; BUF_SIZE];
let count = libc::read(pipe[0], buf.as_mut_ptr() as *mut libc::c_void, BUF_SIZE);
if count < 0 {
break Err(anyhow!("io error: {}", std::io::Error::last_os_error()));
}
des.extend_from_slice(&buf[0..(count as usize)]);
if (count as usize) < BUF_SIZE {
break Ok(des);
}
};
let mut status = 0;
libc::waitpid(pid, &mut status, 0);
if status != 0 {
return Err(anyhow!("Process returned non-zero status code {}", status));
}
des.and_then(|des| {
serde_json::from_slice::<Result<R, serde_error::Error>>(des.as_slice())
.map_err(|e| anyhow!("{}", e))
.and_then(|se| match se {
Ok(i) => Ok(i),
Err(e) => Err(anyhow::Error::from(e)),
})
})
}