Start: `Channel<T>`: Typed pipes.

Fortune for comfork's current commit: Curse − 凶
master
Avril 3 years ago
parent 3aa61be7cd
commit b9128eba4b
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -7,6 +7,8 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bytes = "1.0.1"
cfg-if = "1.0.0" cfg-if = "1.0.0"
libc = "0.2.99" libc = "0.2.99"
once_cell = "1.8.0" once_cell = "1.8.0"
serde = { version = "1.0.129", features = ["derive"] }

@ -0,0 +1,166 @@
//! `Channel<T>`: 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<T>(state: &mut Self::State, obj: &T) -> Result<Self::Buffer, Error>;
/// 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<T, B: Buf>(state: &mut Self::State, buffer: B) -> Result<T, Error>;
}
/// 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<T, M: ?Sized + TransferMethod = TransferSerial>
{
tx: pipe::WriteHalf,
state: M::State,
_data: PhantomData<Vec<T>>,
_method: PhantomData<M>,
}
/// Receive objects of type `T` from a parent-child stream.
#[derive(Debug)]
pub struct Receiver<T, M: ?Sized + TransferMethod = TransferSerial>
{
rx: pipe::ReadHalf,
state: M::State,
_data: PhantomData<Vec<T>>,
_mathod: PhantomData<M>,
}
#[inline] pub fn pair<T>() -> (Sender<T, TransferSerial>, Receiver<T, TransferSerial>)
{
Sender::<_, TransferSerial>::new()
}
// TODO: TransferBitwise is very unsafe, document that here.
#[inline] pub unsafe fn pair_bitwise<T>() -> (Sender<T, TransferBitwise>, Receiver<T, TransferBitwise>)
{
Sender::<_, TransferBitwise>::new()
}
impl<T> Sender<T, TransferBitwise>
{
// TODO: TransferBitwise is very unsafe, document that here.
pub unsafe fn new() -> (Self, Receiver<T, TransferBitwise>)
{
todo!()
}
}
impl<T> Sender<T, TransferSerial>
{
pub fn new() -> (Self, Receiver<T, TransferSerial>)
{
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<T>(Box<(ErrorKind, bool, Option<T>)>);
impl fmt::Display for ErrorKind
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
todo!()
}
}
impl<T: fmt::Debug> fmt::Display for Error<T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "channel<{}>: failed to ", std::any::type_name::<T>())?;
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<T> Error<T>
{
pub fn recv(kind: ErrorKind, value: Option<T>) -> Self
{
Self(Box::new((
kind,
false,
value
)))
}
pub fn send(kind: ErrorKind, value: Option<T>) -> Self
{
Self(Box::new((
kind,
true,
value
)))
}
}
}

@ -1,11 +1,13 @@
#![allow(dead_code)] #![allow(dead_code)]
#[macro_use] extern crate cfg_if; #[macro_use] extern crate cfg_if;
#[macro_use] extern crate serde;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
#[macro_use] mod ext; use ext::*; #[macro_use] mod ext; use ext::*;
mod sys; mod sys;
pub mod channel;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

Loading…
Cancel
Save