shmipc 0.1.1

Shared memory IPC for Rust
Documentation
use tokio::net::{TcpListener, TcpStream, UnixListener, UnixStream};

pub trait TransportStream: std::os::fd::AsRawFd {
    type ReadHalf: tokio::io::AsyncRead;
    type WriteHalf: tokio::io::AsyncWrite;

    fn into_split(self) -> (Self::ReadHalf, Self::WriteHalf);
}

pub trait TransportConnect {
    type Stream: TransportStream;
    type Address;

    fn connect(
        &self,
        addr: Self::Address,
    ) -> impl Future<Output = std::io::Result<Self::Stream>> + Send;
}

pub trait TransportListen {
    type Listener: TransportListener;
    type Address;

    fn listen(
        &self,
        addr: Self::Address,
    ) -> impl Future<Output = std::io::Result<Self::Listener>> + Send;
}

pub trait TransportListener {
    type Stream: TransportStream;
    type Address;

    fn accept(&self)
    -> impl Future<Output = std::io::Result<(Self::Stream, Self::Address)>> + Send;
}

impl TransportStream for TcpStream {
    type ReadHalf = tokio::net::tcp::OwnedReadHalf;
    type WriteHalf = tokio::net::tcp::OwnedWriteHalf;

    fn into_split(self) -> (Self::ReadHalf, Self::WriteHalf) {
        self.into_split()
    }
}

impl TransportStream for UnixStream {
    type ReadHalf = tokio::net::unix::OwnedReadHalf;
    type WriteHalf = tokio::net::unix::OwnedWriteHalf;

    fn into_split(self) -> (Self::ReadHalf, Self::WriteHalf) {
        self.into_split()
    }
}

#[derive(Clone, Debug, Default)]
pub struct DefaultTcpConnect;

impl TransportConnect for DefaultTcpConnect {
    type Stream = TcpStream;
    type Address = std::net::SocketAddr;

    fn connect(
        &self,
        addr: Self::Address,
    ) -> impl Future<Output = std::io::Result<Self::Stream>> + Send {
        TcpStream::connect(addr)
    }
}

#[derive(Clone, Debug, Default)]
pub struct DefaultUnixConnect;

impl TransportConnect for DefaultUnixConnect {
    type Stream = UnixStream;
    type Address = std::os::unix::net::SocketAddr;

    async fn connect(&self, addr: Self::Address) -> std::io::Result<Self::Stream> {
        let Some(path) = addr.as_pathname() else {
            return Err(std::io::Error::new(
                std::io::ErrorKind::AddrNotAvailable,
                "unnamed unix domain socket cannot be connected",
            ));
        };
        UnixStream::connect(path).await
    }
}

#[derive(Clone, Debug, Default)]
pub struct DefaultTcpListen;

impl TransportListen for DefaultTcpListen {
    type Listener = TcpListener;
    type Address = std::net::SocketAddr;

    async fn listen(&self, addr: Self::Address) -> std::io::Result<Self::Listener> {
        TcpListener::from_std(std::net::TcpListener::bind(addr)?)
    }
}

#[derive(Clone, Debug, Default)]
pub struct DefaultUnixListen;

impl TransportListen for DefaultUnixListen {
    type Listener = UnixListener;
    type Address = std::os::unix::net::SocketAddr;

    async fn listen(&self, addr: Self::Address) -> std::io::Result<Self::Listener> {
        let Some(path) = addr.as_pathname() else {
            return Err(std::io::Error::new(
                std::io::ErrorKind::AddrNotAvailable,
                "unnamed unix domain socket cannot be listened",
            ));
        };
        let _ = nix::unistd::unlink(path);
        UnixListener::bind(path)
    }
}

impl TransportListener for TcpListener {
    type Stream = TcpStream;
    type Address = std::net::SocketAddr;

    fn accept(
        &self,
    ) -> impl Future<Output = std::io::Result<(Self::Stream, Self::Address)>> + Send {
        self.accept()
    }
}

impl TransportListener for UnixListener {
    type Stream = UnixStream;
    type Address = tokio::net::unix::SocketAddr;

    fn accept(
        &self,
    ) -> impl Future<Output = std::io::Result<(Self::Stream, Self::Address)>> + Send {
        self.accept()
    }
}