diff --git a/Cargo.toml b/Cargo.toml index 42f6536..4cf42d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ cfg-if = "1.0.0" libc = "0.2.99" once_cell = "1.8.0" serde = { version = "1.0.129", features = ["derive"] } +serde_cbor = "0.11.2" diff --git a/src/channel.rs b/src/channel.rs index e579e73..0024fd6 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,16 +1,41 @@ //! `Channel`: Move objects between parent and child processes. use super::*; -use bytes::Buf; +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. @@ -24,6 +49,10 @@ pub trait TransferMethod /// 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. @@ -38,7 +67,16 @@ 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.) @@ -47,7 +85,29 @@ 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. @@ -75,18 +135,19 @@ pub struct Receiver _mathod: PhantomData, } -#[inline] pub fn pair() -> (Sender, Receiver) +#[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) +#[inline] pub unsafe fn pair_bitwise() -> (Sender, Receiver) { Sender::<_, TransferBitwise>::new() } -impl Sender +// 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) @@ -95,16 +156,56 @@ impl Sender } } -impl Sender +impl Sender { pub fn new() -> (Self, Receiver) { todo!() } } -//TODO: Re-do. Do not use generics on the Error type... -// It does NOT need to hold the type information or value. -pub struct Error; //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)]