//! `Channel`: Move objects between parent and child processes. use super::*; use bytes::{ Buf, BufMut, Bytes, }; use std::marker::PhantomData; use std::{fmt, error}; use std::io::{ self, Read, Write, Cursor, }; use serde::{ Serialize, de::DeserializeOwned, }; use sys::pipe; /// A value that can be sent through a serial `Channel` /// /// Bitwise channels can take `ChannelBitwiseValue` objects. pub trait ChannelSerialValue: Serialize + DeserializeOwned{} impl ChannelSerialValue for T where T: Serialize + DeserializeOwned{} /// A value that can be sent through a bitwise `Channel` /// /// Serial channels require `ChannelSerialValue`. pub trait ChannelBitwiseValue: Send + Unpin{} impl ChannelBitwiseValue for T where T: Send + Unpin{} //TODO: We can create a non-stream version of this using a memory mapped ring-buffer on an fd shared between parent and child. (i.e: map two pages, the first and second one pointing to the start of the file). But that might be unneeded or too much work for this project's scope. /// Controls how objects are sent through the streams. pub trait TransferMethod { /// The returned buffer that is build from `send`. /// /// `recv` takes any `impl Buf` object. type Buffer: Buf; /// An optional internal state object to hold any additional data needed. /// This can be set to `()`. type State; /// Error for the send/recv conversion. /// Must be able to convert into `channel::Error`. type Error: Into; /// Serialise the object `T` to a byte buffer for sending. fn send(state: &mut Self::State, obj: &T) -> Result; /// Read the object `T` from a byte buffer that was read from the pipe. /// /// The buffer's size is handled by the channel. fn recv(state: &mut Self::State, buffer: B) -> Result; } /// Serialize objects deeply to send them. #[derive(Debug)] pub struct TransferSerial; impl TransferMethod for TransferSerial { type Buffer = Cursor>; type State = (); type Error = Error; fn send(_: &mut Self::State, obj: &T) -> Result { todo!() } fn recv(_: &mut Self::State, buffer: B) -> Result { todo!() } } /// Send objects through the stream as bitwise copied (unsafe.) #[derive(Debug)] pub struct TransferBitwise; impl TransferMethod for TransferBitwise { type Buffer = Bytes; type State = (); type Error = std::convert::Infallible; fn send(_: &mut Self::State, obj: &T) -> Result { let bytes = unsafe { std::slice::from_raw_parts(obj as *const T as *const _, std::mem::size_of::()) }; Ok(bytes.into()) } fn recv(_: &mut Self::State, mut buffer: B) -> Result { use std::mem::{ self, MaybeUninit, }; let mut value: MaybeUninit = MaybeUninit::uninit(); unsafe { let slice = std::slice::from_raw_parts_mut(&mut value as *mut MaybeUninit as *mut _, mem::size_of::()); buffer.copy_to_slice(slice); Ok(value.assume_init()) } } } /// Send objects of type `T` through parent-child streams. #[derive(Debug)] pub struct Sender { tx: pipe::WriteHalf, state: M::State, _data: PhantomData>, _method: PhantomData, } /// Receive objects of type `T` from a parent-child stream. #[derive(Debug)] pub struct Receiver { rx: pipe::ReadHalf, state: M::State, _data: PhantomData>, _mathod: PhantomData, } #[inline] pub fn pair() -> (Sender, Receiver) { Sender::<_, TransferSerial>::new() } // TODO: TransferBitwise is very unsafe, document that here. #[inline] pub unsafe fn pair_bitwise() -> (Sender, Receiver) { Sender::<_, TransferBitwise>::new() } // TODO: What bounds should we have on this, if any? Send? Unpin? Maybe even restricted to Copy. impl Sender { // TODO: TransferBitwise is very unsafe, document that here. pub unsafe fn new() -> (Self, Receiver) { todo!() } } impl Sender { pub fn new() -> (Self, Receiver) { todo!() } } /// The kind of channel error #[derive(Debug)] #[non_exhaustive] pub enum ErrorKind { Unknown, Serialisation(serde_cbor::Error), Deserialisation(serde_cbor::Error), IO(io::Error), } /// An error in a channel operation. #[derive(Debug)] pub struct Error(Box<(ErrorKind, Option)>); impl From<(ErrorKind, bool)> for Error { #[inline] fn from((k, s): (ErrorKind, bool)) -> Self { let from = (k, Some(s)); Self(Box::new(from)) } } impl From for Error { fn from(from: ErrorKind) -> Self { Self(Box::new((from, None))) } } impl From for Error { #[inline] fn from(from: std::convert::Infallible) -> Self { match from{} } } remove! { /// The kind of channel error #[derive(Debug)] #[non_exhaustive] pub enum ErrorKind { IO(io::Error), Unknown, } /// An error on a channel operation #[derive(Debug)] pub struct Error(Box<(ErrorKind, bool, Option)>); impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!() } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "channel<{}>: failed to ", std::any::type_name::())?; match (self.0.1, self.0.2.as_ref()) { (true, None) => write!(f, "send"), (false, None) => write!(f, "recv"), (true, Some(val)) => write!(f, "send (value [{:?}])", val), (false, Some(val)) => write!(f, "recv (value [{:?}])", val), }?; write!(f, ": {}", self.0.0) } } impl Error { pub fn recv(kind: ErrorKind, value: Option) -> Self { Self(Box::new(( kind, false, value ))) } pub fn send(kind: ErrorKind, value: Option) -> Self { Self(Box::new(( kind, true, value ))) } } }