wireshift-uring 0.1.1

Native Linux io_uring backend for wireshift
Documentation
use std::collections::HashMap;
use std::os::fd::RawFd;

use wireshift_core::{Error, Result};

/// Returns the first duplicate fd in the slice, or None if all are unique.
pub fn duplicate_fd(fds: &[RawFd]) -> Option<RawFd> {
    let mut seen = std::collections::HashSet::with_capacity(fds.len());
    fds.iter().find(|&&fd| !seen.insert(fd)).copied()
}

/// A table mapping raw file descriptors to `io_uring` fixed-file slots.
#[derive(Debug, Default)]
pub struct FileRegistryTable {
    pub(crate) slots_by_fd: HashMap<RawFd, u32>,
}

impl FileRegistryTable {
    /// Registers a set of file descriptors with the kernel.
    pub fn register(&mut self, submitter: &io_uring::Submitter<'_>, fds: &[RawFd]) -> Result<()> {
        if let Some(duplicate) = duplicate_fd(fds) {
            return Err(Error::validation(
                format!("duplicate fd {duplicate} cannot be mapped to multiple fixed-file slots"),
                "register each fd at most once or duplicate the descriptor before registering",
            ));
        }

        submitter.register_files(fds).map_err(|error| {
            Error::io(
                "IORING_REGISTER_FILES failed",
                error,
                "ensure every fd is valid and the kernel supports fixed-file registration",
            )
        })?;

        self.slots_by_fd = fds
            .iter()
            .enumerate()
            .map(|(slot, &fd)| (fd, slot as u32))
            .collect();
        Ok(())
    }

    /// Unregisters all file descriptors from the kernel.
    pub fn unregister(&mut self, submitter: &io_uring::Submitter<'_>) -> Result<()> {
        submitter.unregister_files().map_err(|error| {
            Error::io(
                "IORING_UNREGISTER_FILES failed",
                error,
                "wait for in-flight fixed-file requests to finish before unregistering files",
            )
        })?;
        self.slots_by_fd.clear();
        Ok(())
    }

    /// Looks up the fixed-file slot for a given raw file descriptor.
    pub fn lookup(&self, fd: RawFd) -> Option<u32> {
        self.slots_by_fd.get(&fd).copied()
    }

    /// Clears the local mapping (does not unregister from kernel).
    pub fn clear(&mut self) {
        self.slots_by_fd.clear();
    }
}