12 releases

0.2.2 Mar 27, 2024
0.2.0 Nov 6, 2023
0.1.1 May 31, 2023
0.1.0 Mar 9, 2023
0.0.4 Dec 6, 2021

#470 in Asynchronous

Download history 150/week @ 2024-02-26 23/week @ 2024-03-04 16/week @ 2024-03-11 29/week @ 2024-03-18 189/week @ 2024-03-25 121/week @ 2024-04-01 48/week @ 2024-04-08 12/week @ 2024-04-15 31/week @ 2024-04-22 43/week @ 2024-04-29 92/week @ 2024-05-06 52/week @ 2024-05-13 99/week @ 2024-05-20 153/week @ 2024-05-27 123/week @ 2024-06-03 119/week @ 2024-06-10

498 downloads per month
Used in 4 crates (3 directly)

MIT/Apache

765KB
17K SLoC

Monoio Compat

A compat wrapper for monoio.

Usage example:

use monoio_compat::{AsyncReadExt, AsyncWriteExt, TcpStreamCompat};

#[monoio::main]
async fn main() {
    const ADDRESS: &str = "127.0.0.1:50009";
    let (mut oneshot_tx, mut oneshot_rx) = local_sync::oneshot::channel::<()>();

    let server = async move {
        let listener = monoio::net::TcpListener::bind(ADDRESS).unwrap();
        oneshot_rx.close();
        let (conn, _) = listener.accept().await.unwrap();
        let mut compat_conn = unsafe { TcpStreamCompat::new(conn) };

        let mut buf = [0u8; 10];
        compat_conn.read_exact(&mut buf).await.unwrap();
        buf[0] += 1;
        compat_conn.write_all(&buf).await.unwrap();
    };
    let client = async {
        oneshot_tx.closed().await;
        let conn = monoio::net::TcpStream::connect(ADDRESS).await.unwrap();
        let mut compat_conn = unsafe { TcpStreamCompat::new(conn) };

        let mut buf = [65u8; 10];
        compat_conn.write_all(&buf).await.unwrap();
        compat_conn.read_exact(&mut buf).await.unwrap();
        assert_eq!(buf[0], 66);
    };
    monoio::join!(client, server);
}

Please read the following note before using this crate.

Important Note

Even with this wrapper, TcpStreamCompat is still not fully compatible with the Tokio IO interface.

The user must ensure that once a slice of data is sent using poll_write and poll_read, it will continue to be used until the call returns Ready. Otherwise, the old data will be send.

We implement a simple checking mechanism to ensure that the data is the same between poll_write. But for the sake of performance, we only check the data length, which is not enough. It may cause unsoundness.

For example, running h2 server based on this wrapper will fail. Inside the h2, it will try to send a data frame with poll_write, and if it get Pending, it will assume the data not be sent yet. If there is another data frame with a higher priority, it will poll_write the new frame instead. But the old data frame will be sent with our wrapper.

The core problem is caused by incompatible between poll-like interface and asynchronous system call.

TcpStreamCompat and TcpStreamCompatUnsafe

TcpStreamCompat: Will copy data into owned buffer first, then construct save the future. If user does not follow the rule, it will panic.

TcpStreamCompatUnsafe: Will only save user-provided buffer pointer and length. It will not copy the data, so it is more efficient than TcpStreamCompat. But if user does not follow the rule, it will cause memory corruption.

Dependencies

~3–13MB
~132K SLoC