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