use crate::raw::PollEvented;
use async_datagram::AsyncDatagram;
use async_ready::{AsyncReadReady, AsyncWriteReady, TakeError};
use futures::{ready, Poll};
use mio_uds;
use std::fmt;
use std::io;
use std::net::Shutdown;
use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::net::SocketAddr;
use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::task::Context;
use std::future::Future;
pub struct UnixDatagram {
io: PollEvented<mio_uds::UnixDatagram>,
}
#[derive(Debug)]
pub struct SendTo<'a, 'b> {
socket: &'a mut UnixDatagram,
buf: &'b [u8],
target: &'b PathBuf,
}
impl<'a, 'b> Future for SendTo<'a, 'b> {
type Output = io::Result<usize>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let SendTo {
socket,
buf,
target,
} = &mut *self;
Pin::new(&mut **socket).poll_send_to(cx, buf, target)
}
}
#[derive(Debug)]
pub struct RecvFrom<'a, 'b> {
socket: &'a mut UnixDatagram,
buf: &'b mut [u8],
}
impl<'a, 'b> Future for RecvFrom<'a, 'b> {
type Output = io::Result<(usize, SocketAddr)>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let RecvFrom { socket, buf } = &mut *self;
Pin::new(&mut **socket).poll_recv_from(cx, buf)
}
}
impl UnixDatagram {
pub fn bind(path: impl AsRef<Path>) -> io::Result<UnixDatagram> {
let socket = mio_uds::UnixDatagram::bind(path)?;
Ok(UnixDatagram::new(socket))
}
pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
let (a, b) = mio_uds::UnixDatagram::pair()?;
let a = UnixDatagram::new(a);
let b = UnixDatagram::new(b);
Ok((a, b))
}
fn new(socket: mio_uds::UnixDatagram) -> UnixDatagram {
let io = PollEvented::new(socket);
UnixDatagram { io }
}
pub fn unbound() -> io::Result<UnixDatagram> {
let socket = mio_uds::UnixDatagram::unbound()?;
Ok(UnixDatagram::new(socket))
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io.get_ref().local_addr()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io.get_ref().peer_addr()
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io.get_ref().shutdown(how)
}
pub fn send_to<'a, 'b>(&'a mut self, buf: &'b [u8], target: &'b PathBuf) -> SendTo<'a, 'b> {
SendTo {
buf,
target,
socket: self,
}
}
pub fn recv_from<'a, 'b>(&'a mut self, buf: &'b mut [u8]) -> RecvFrom<'a, 'b> {
RecvFrom { buf, socket: self }
}
}
impl AsyncDatagram for UnixDatagram {
type Sender = SocketAddr;
type Receiver = PathBuf;
type Err = io::Error;
fn poll_send_to(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
receiver: &Self::Receiver,
) -> Poll<io::Result<usize>> {
ready!(self.io.poll_write_ready(cx)?);
match self.io.get_ref().send_to(buf, receiver) {
Ok(n) => Poll::Ready(Ok(n)),
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
Pin::new(&mut self.io).clear_write_ready(cx)?;
Poll::Pending
}
Err(e) => Poll::Ready(Err(e)),
}
}
fn poll_recv_from(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<(usize, Self::Sender)>> {
ready!(Pin::new(&mut self.io).poll_read_ready(cx)?);
let r = self.io.get_ref().recv_from(buf);
if is_wouldblock(&r) {
Pin::new(&mut self.io).clear_read_ready(cx)?;
Poll::Pending
} else {
Poll::Ready(r)
}
}
}
impl AsyncReadReady for UnixDatagram {
type Ok = mio::Ready;
type Err = io::Error;
fn poll_read_ready(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Self::Ok, Self::Err>> {
Pin::new(&mut self.io).poll_read_ready(cx)
}
}
impl AsyncWriteReady for UnixDatagram {
type Ok = mio::Ready;
type Err = io::Error;
fn poll_write_ready(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Self::Ok, Self::Err>> {
Pin::new(&mut self.io).poll_write_ready(cx)
}
}
impl TakeError for UnixDatagram {
type Ok = io::Error;
type Err = io::Error;
fn take_error(&self) -> Result<Option<Self::Ok>, Self::Err> {
self.io.get_ref().take_error()
}
}
impl fmt::Debug for UnixDatagram {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.io.get_ref().fmt(f)
}
}
impl AsRawFd for UnixDatagram {
fn as_raw_fd(&self) -> RawFd {
self.io.get_ref().as_raw_fd()
}
}
fn is_wouldblock<T>(r: &io::Result<T>) -> bool {
match *r {
Ok(_) => false,
Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
}
}