wireshift-fallback 0.1.1

Blocking worker-pool fallback backend for wireshift
Documentation
use std::io::{Seek, SeekFrom, Write};

use wireshift_core::buffer::{Buffer, Submitted};
use wireshift_core::op::CompletionPayload;
use wireshift_core::{Error, Result};

use crate::ops::retry_eintr;

/// Execute a positional write at `offset`, returning the buffer and the
/// number of bytes written.
pub fn execute_write(
    mut file: std::fs::File,
    offset: u64,
    buffer: Buffer<Submitted>,
) -> Result<CompletionPayload> {
    if let Err(error) = file.seek(SeekFrom::Start(offset)) {
        let is_espipe = error.raw_os_error() == Some(rustix::io::Errno::SPIPE.raw_os_error());
        if !is_espipe || offset > 0 {
            return Err(Error::io(
                "write seek failed",
                error,
                "seek to a valid offset before writing",
            ));
        }
    }
    let data = &buffer.backend_ref()[..buffer.filled_len()];
    let bytes = retry_eintr!(file.write(data)).map_err(|error| {
        Error::io(
            "write failed",
            error,
            "ensure the file descriptor is writable",
        )
    })?;
    Ok(CompletionPayload::Bytes(bytes))
}

/// Execute a positional vectored write at `offset` over `buffers`,
/// returning the completed buffers and the total number of bytes written.
pub fn execute_write_vectored(
    mut file: std::fs::File,
    offset: u64,
    buffers: Vec<Buffer<Submitted>>,
) -> Result<CompletionPayload> {
    if let Err(error) = file.seek(SeekFrom::Start(offset)) {
        let is_espipe = error.raw_os_error() == Some(rustix::io::Errno::SPIPE.raw_os_error());
        if !is_espipe || offset > 0 {
            return Err(Error::io(
                "writev seek failed",
                error,
                "seek to a valid offset before writing vectored data",
            ));
        }
    }
    let mut written = 0_usize;
    for buffer in buffers {
        let chunk = &buffer.backend_ref()[..buffer.filled_len()];
        let bytes = retry_eintr!(file.write(chunk)).map_err(|error| {
            Error::io(
                "writev segment write failed",
                error,
                "ensure the file descriptor remains writable for all writev segments",
            )
        })?;
        written += bytes;
        if bytes < chunk.len() {
            break;
        }
    }
    Ok(CompletionPayload::Bytes(written))
}