async-std 1.5.0

Async version of the Rust standard library
Documentation
#![cfg(unix)]

use async_std::io;
use async_std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
use async_std::prelude::*;
use async_std::task;

use tempdir::TempDir;

use std::time::Duration;

const JULIUS_CAESAR: &[u8] = b"
    Friends, Romans, countrymen - lend me your ears!
    I come not to praise Caesar, but to bury him.
";

#[test]
fn send_recv() -> io::Result<()> {
    task::block_on(async {
        let (socket1, socket2) = UnixDatagram::pair().unwrap();
        socket1.send(JULIUS_CAESAR).await?;

        let mut buf = vec![0; 1024];
        let n = socket2.recv(&mut buf).await?;
        assert_eq!(&buf[..n], JULIUS_CAESAR);

        Ok(())
    })
}

#[test]
fn into_raw_fd() -> io::Result<()> {
    use async_std::os::unix::io::{FromRawFd, IntoRawFd};
    task::block_on(async {
        let (socket1, socket2) = UnixDatagram::pair().unwrap();
        socket1.send(JULIUS_CAESAR).await?;

        let mut buf = vec![0; 1024];

        let socket2 = unsafe { UnixDatagram::from_raw_fd(socket2.into_raw_fd()) };
        let n = socket2.recv(&mut buf).await?;
        assert_eq!(&buf[..n], JULIUS_CAESAR);

        Ok(())
    })
}

const PING: &[u8] = b"ping";
const PONG: &[u8] = b"pong";
const TEST_TIMEOUT: Duration = Duration::from_secs(3);

#[test]
fn socket_ping_pong() {
    let tmp_dir = TempDir::new("socket_ping_pong").expect("Temp dir not created");
    let sock_path = tmp_dir.as_ref().join("sock");
    let iter_cnt = 16;

    let listener =
        task::block_on(async { UnixListener::bind(&sock_path).await.expect("Socket bind") });

    let server_handle = std::thread::spawn(move || {
        task::block_on(async { ping_pong_server(listener, iter_cnt).await }).unwrap()
    });

    let client_handle = std::thread::spawn(move || {
        task::block_on(async { ping_pong_client(&sock_path, iter_cnt).await }).unwrap()
    });

    client_handle.join().unwrap();
    server_handle.join().unwrap();
}

async fn ping_pong_server(listener: UnixListener, iterations: u32) -> std::io::Result<()> {
    let mut incoming = listener.incoming();
    let mut buf = [0; 1024];
    for _ix in 0..iterations {
        if let Some(s) = incoming.next().await {
            let mut s = s?;
            let n = s.read(&mut buf[..]).await?;
            assert_eq!(&buf[..n], PING);
            s.write_all(&PONG).await?;
        }
    }
    Ok(())
}

async fn ping_pong_client(socket: &std::path::PathBuf, iterations: u32) -> std::io::Result<()> {
    let mut buf = [0; 1024];
    for _ix in 0..iterations {
        let mut socket = UnixStream::connect(&socket).await?;
        socket.write_all(&PING).await?;
        let n = async_std::io::timeout(TEST_TIMEOUT, socket.read(&mut buf[..])).await?;
        assert_eq!(&buf[..n], PONG);
    }
    Ok(())
}