use sealed::DeSerializeBytes;
use std::{
io::{self, Read, Write},
marker::PhantomData,
os::{
fd::{AsFd, BorrowedFd},
unix::net::UnixStream,
},
};
mod sealed {
pub trait DeSerializeBytes {
fn zero_init() -> Self;
fn as_mut_ref(&mut self) -> &mut [u8];
}
impl<const N: usize> DeSerializeBytes for [u8; N] {
fn zero_init() -> [u8; N] {
[0; N]
}
fn as_mut_ref(&mut self) -> &mut [u8] {
self.as_mut_slice()
}
}
}
pub trait DeSerialize {
type Bytes: sealed::DeSerializeBytes;
fn serialize(&self) -> Self::Bytes;
fn deserialize(bytes: Self::Bytes) -> Self;
}
pub struct BinPipe<R: DeSerialize, W: DeSerialize = R> {
sock: UnixStream,
_read_marker: PhantomData<R>,
_write_marker: PhantomData<W>,
}
impl<R: DeSerialize, W: DeSerialize> BinPipe<R, W> {
pub fn pair() -> io::Result<(BinPipe<R, W>, BinPipe<W, R>)> {
let (first, second) = UnixStream::pair()?;
Ok((
BinPipe {
sock: first,
_read_marker: PhantomData::<R>,
_write_marker: PhantomData::<W>,
},
BinPipe {
sock: second,
_read_marker: PhantomData::<W>,
_write_marker: PhantomData::<R>,
},
))
}
pub fn read(&mut self) -> io::Result<R> {
let mut bytes = R::Bytes::zero_init();
self.sock.read_exact(bytes.as_mut_ref())?;
Ok(R::deserialize(bytes))
}
pub fn write(&mut self, bytes: &W) -> io::Result<()> {
self.sock.write_all(bytes.serialize().as_mut_ref())?;
Ok(())
}
#[cfg(debug_assertions)]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.sock.set_nonblocking(nonblocking)
}
}
impl<R: DeSerialize, W: DeSerialize> AsFd for BinPipe<R, W> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.sock.as_fd()
}
}
impl DeSerialize for i32 {
type Bytes = [u8; std::mem::size_of::<Self>()];
fn serialize(&self) -> Self::Bytes {
self.to_ne_bytes()
}
fn deserialize(bytes: Self::Bytes) -> Self {
Self::from_ne_bytes(bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn single_type() {
let (mut tx, mut rx) = BinPipe::pair().unwrap();
tx.write(&42i32).unwrap();
assert_eq!(rx.read().unwrap(), 42);
rx.write(&23i32).unwrap();
assert_eq!(tx.read().unwrap(), 23);
}
impl DeSerialize for u8 {
type Bytes = [u8; std::mem::size_of::<Self>()];
fn serialize(&self) -> [u8; 1] {
self.to_ne_bytes()
}
fn deserialize(bytes: [u8; 1]) -> Self {
Self::from_ne_bytes(bytes)
}
}
#[test]
pub fn different_types() {
let (mut tx, mut rx) = BinPipe::pair().unwrap();
tx.write(&42i32).unwrap();
assert_eq!(rx.read().unwrap(), 42);
rx.write(&23u8).unwrap();
assert_eq!(tx.read().unwrap(), 23);
}
}