@ -7,6 +7,17 @@ use libc::{
setuid ,
} ;
use std ::{ fmt , error } ;
use std ::io ::{
self ,
Read ,
Write ,
} ;
use std ::marker ::Unpin ;
use std ::panic ::{
AssertUnwindSafe ,
catch_unwind ,
resume_unwind ,
} ;
use errno ::Errno ;
@ -27,6 +38,49 @@ pub enum ErrorKind
Pipe ( pipe ::ErrorKind ) ,
}
// TODO: Add non-`sys` type: `Channel<T>`, which can be used to send/recv typed data between parent and child.
// It should leverage the two below functions: `move_*_stream()`.
/// Move a value into a stream.
///
/// This function will return `Ok` if and only if all bytes from `val` were successfully written to the stream `to`.
/// If only a subset of them were written, then the data is corrupt and that is counted as an error.
///
/// # Safety
/// The object `val` is written into the stream `to` verbatim. Its destructor is not run.
/// The object should be read verbatim from the stream with no errors or corruption before its dropped, or it will leak resources.
///
/// This function is safe, but reading from the stream into a new object is not.
///
/// ## Unpin
/// `T` should be `Unpin` in case it contains self-referrential data, as those references will no longer be valid after being moved across a stream.
// TODO: Should we expose these to the user somehow, with an unsafe helper module maybe? They could be useful.
// Or perhaps: Add the functionality to move types to/from the child/parent into the library, similar to `mpsc`.
pub ( crate ) fn move_write_value < T : Unpin , S : Write > ( mut to : S , val : T ) -> io ::Result < ( ) >
{
let bytes = unsafe {
std ::slice ::from_raw_parts ( & val as * const T as * const u8 , std ::mem ::size_of ::< T > ( ) )
} ;
// Catch any panics that may happen in `write`.
let res = catch_unwind ( AssertUnwindSafe ( move | | {
to . write_all ( bytes )
} ) ) ;
// Ensure this happens even if the above panics.
drop ( bytes ) ; // Make sure `bytes` isn't dangling after we move `val` into `forget()`.
std ::mem ::forget ( val ) ;
// Resume unwind if one occoured, if not return the value
match res {
Ok ( v ) = > v ,
Err ( panic ) = > resume_unwind ( panic ) ,
}
}
//TODO: Counterpart to `move_write_value()`. This function should be `unsafe` as it is extermely unsafe.
pub ( crate ) unsafe fn move_read_value < T : Unpin , S : Read > ( mut from : S ) -> io ::Result < T >
{
todo! ( )
}
/// An error in either forking or communicating with the child process during its setup.
#[ derive(Debug) ]
#[ repr(transparent) ]