From b9128eba4bd7d3b283cf0ac9745e38b64dfa5a3d Mon Sep 17 00:00:00 2001 From: Avril Date: Sat, 28 Aug 2021 16:54:46 +0100 Subject: [PATCH] Start: `Channel`: Typed pipes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for comfork's current commit: Curse − 凶 --- Cargo.toml | 2 + src/channel.rs | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 3 files changed, 170 insertions(+) create mode 100644 src/channel.rs diff --git a/Cargo.toml b/Cargo.toml index 405373d..42f6536 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bytes = "1.0.1" cfg-if = "1.0.0" libc = "0.2.99" once_cell = "1.8.0" +serde = { version = "1.0.129", features = ["derive"] } diff --git a/src/channel.rs b/src/channel.rs new file mode 100644 index 0000000..e579e73 --- /dev/null +++ b/src/channel.rs @@ -0,0 +1,166 @@ +//! `Channel`: Move objects between parent and child processes. +use super::*; +use bytes::Buf; +use std::marker::PhantomData; +use std::{fmt, error}; +use std::io::{ + self, + Read, + Write, +}; + +use sys::pipe; + +//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; + + /// 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 +{ + +} + +/// Send objects through the stream as bitwise copied (unsafe.) +#[derive(Debug)] +pub struct TransferBitwise; + +impl TransferMethod for TransferBitwise +{ + +} + +/// 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() +} + +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!() + } +} +//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: ... +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 + ))) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 9136015..034db3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,13 @@ #![allow(dead_code)] #[macro_use] extern crate cfg_if; +#[macro_use] extern crate serde; use std::convert::{TryFrom, TryInto}; #[macro_use] mod ext; use ext::*; mod sys; +pub mod channel; #[cfg(test)] mod tests {