Trait a10::extract::Extract

source ·
pub trait Extract {
    // Provided method
    fn extract(self) -> Extractor<Self>
       where Self: Sized { ... }
}
Expand description

Extract input arguments from operations.

Because of the way that io_uring works the kernel needs mutable access to the inputs of a system call for entire duration the operation is in progress. For example when reading into a buffer the buffer needs to stay alive until the kernel has written into it, or until the kernel knows the operation is canceled and won’t write into the buffer any more. If we can’t ensure this the kernel might write into memory we don’t own causing write-after-free bugs.

To ensure the input stays alive A10 needs ownership of the input arguments and delays the deallocation of the inputs when a Future operation is dropped before completion. However to give the Futures a nice API we don’t return the input arguments and try to match the APIs that don’t take ownership of arguments, e.g fs::OpenOptions::open just returns a AsyncFd not the path argument.

In some cases though we would like to get back the input arguments from the operation, e.g. for performance reasons. This trait allow you to do just that: extract the input arguments from Future operations.

All I/O operations, that is the Future implementations, that support extract the input argument will implement this Extract trait. A list of the supported operations can be found below. For the actual implementations see the Future implementations on the Extractor type.

§Examples

Extracting the arguments from fs::OpenOptions::open and AsyncFd::write operations.

use std::io;
use std::path::PathBuf;

use a10::fs::OpenOptions;
use a10::{SubmissionQueue, Extract};

async fn write_all_to_file(sq: SubmissionQueue, path: PathBuf, buf: Vec<u8>) -> io::Result<(PathBuf, Vec<u8>)> {
    // This `Future` returns just the opened file.
    let open_file_future = OpenOptions::new().open(sq, path);
    // Calling `extract` and awaiting that will return both the file and
    // the path buffer.
    let (file, path) = open_file_future.extract().await?;

    // This just returns the number of bytes written.
    let write_future = file.write(buf);
    // When extracting it also returns the buffer.
    let (buf, n) = write_future.extract().await?;

    if n != buf.len() {
        // NOTE: `WriteZero` is not entirely accurate, but just for the sake
        // of the example.
        return Err(io::Error::new(io::ErrorKind::WriteZero, "didn't write entire buffer"));
    }

    Ok((path, buf))
}

Provided Methods§

source

fn extract(self) -> Extractor<Self>
where Self: Sized,

Returns a Future that returns the input arguments in addition to the regular return value(s).

Implementors§

source§

impl Extract for CreateDir

source§

impl Extract for Delete

source§

impl Extract for Open

source§

impl Extract for Rename

source§

impl<'fd, A: SocketAddress> Extract for Connect<'fd, A>

source§

impl<'fd, B: Buf> Extract for Write<'fd, B>

source§

impl<'fd, B: Buf> Extract for WriteAll<'fd, B>

source§

impl<'fd, B: Buf> Extract for Send<'fd, B>

source§

impl<'fd, B: Buf> Extract for SendAll<'fd, B>

source§

impl<'fd, B: Buf, A: SocketAddress> Extract for SendTo<'fd, B, A>

source§

impl<'fd, B: BufSlice<N>, A: SocketAddress, const N: usize> Extract for SendMsg<'fd, B, A, N>

source§

impl<'fd, B: BufSlice<N>, const N: usize> Extract for WriteAllVectored<'fd, B, N>

source§

impl<'fd, B: BufSlice<N>, const N: usize> Extract for WriteVectored<'fd, B, N>

source§

impl<'fd, B: BufSlice<N>, const N: usize> Extract for SendAllVectored<'fd, B, N>

source§

impl<'fd, T> Extract for SetSocketOption<'fd, T>