parent
3aa61be7cd
commit
b9128eba4b
@ -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
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue