zincio 0.2.22

A high-performance, cross-platform asynchronous runtime for Rust
Documentation
#[cfg(feature = "blocking-default")]
use crate::blocking::DefaultBlockingThreadPool;
use crate::{blocking::BlockingThreadPool, driver::AnyDriver};

/// I/O driver selection for the async runtime.
///
/// This enum allows choosing which I/O driver to use when building the runtime.
#[derive(Clone)]
pub enum DriverKind {
    /// Uses the Mio driver for I/O operations (Unix only).
    #[cfg(unix)]
    Mio,
    /// Uses the IOCP driver for completion-based I/O operations (Windows only).
    #[cfg(windows)]
    Iocp,
    /// Uses the mock driver for testing purposes.
    Mock,
    /// Uses the io_uring driver (Linux only).
    #[cfg(target_os = "linux")]
    IoUring,
    /// Uses the io_uring driver with custom entry count (Linux only).
    #[cfg(target_os = "linux")]
    IoUringEntries(u32),
    /// Uses a custom io_uring driver (Linux only).
    #[cfg(target_os = "linux")]
    IoUringCustom(io_uring::Builder),
    /// Uses a custom io_uring driver with custom entry count (Linux only).
    #[cfg(target_os = "linux")]
    IoUringCustomEntries(u32, io_uring::Builder),
}

impl DriverKind {
    /// Creates a new runtime I/O driver from this kind.
    #[inline]
    pub(crate) fn into_driver(self) -> Result<AnyDriver, std::io::Error> {
        match self {
            #[cfg(unix)]
            DriverKind::Mio => AnyDriver::new_mio(),
            #[cfg(windows)]
            DriverKind::Iocp => AnyDriver::new_iocp(),
            DriverKind::Mock => Ok(AnyDriver::new_mock()),
            #[cfg(target_os = "linux")]
            DriverKind::IoUring => AnyDriver::new_uring(),
            #[cfg(target_os = "linux")]
            DriverKind::IoUringCustom(builder) => AnyDriver::new_uring_custom(builder),
            #[cfg(target_os = "linux")]
            DriverKind::IoUringEntries(entries) => AnyDriver::new_uring_with_entries(entries),
            #[cfg(target_os = "linux")]
            DriverKind::IoUringCustomEntries(entries, builder) => {
                AnyDriver::new_uring_custom_with_entries(entries, builder)
            }
        }
    }
}

/// Builder for configuring and creating an async runtime.
///
/// Provides a convenient way to configure the runtime's I/O driver
/// before building it.
///
/// # Examples
///
/// ```
/// use zincio::RuntimeBuilder;
///
/// let runtime = RuntimeBuilder::new()
///     .build();
/// ```
pub struct RuntimeBuilder {
    driver_kind: Option<DriverKind>,
    enable_timer: bool,
    enable_fs_offload: bool,
    blocking_pool: Option<Box<dyn BlockingThreadPool>>,
    batch_size: usize,
}

impl RuntimeBuilder {
    /// Creates a new runtime builder with default configuration.
    ///
    /// By default, the builder will select the best available driver for the platform.
    pub fn new() -> Self {
        Self {
            driver_kind: None,
            enable_timer: false,
            enable_fs_offload: false,
            blocking_pool: None,
            batch_size: 256,
        }
    }

    /// Sets the I/O driver for the runtime.
    pub fn driver(mut self, driver_kind: DriverKind) -> Self {
        self.driver_kind = Some(driver_kind);
        self
    }

    /// Enables or disables the timer for the runtime.
    ///
    /// By default, the timer is disabled.
    pub fn enable_timer(mut self, enable: bool) -> Self {
        self.enable_timer = enable;
        self
    }

    /// Enables or disables the offload of file I/O to blocking threads for the runtime.
    ///
    /// By default, the fs offload is disabled.
    pub fn enable_fs_offload(mut self, enable: bool) -> Self {
        self.enable_fs_offload = enable;
        self
    }

    /// Sets the blocking thread pool for the runtime.
    pub fn blocking_pool(mut self, blocking_pool: Box<dyn BlockingThreadPool>) -> Self {
        self.blocking_pool = Some(blocking_pool);
        self
    }

    /// Sets the number of tasks polled per scheduler loop iteration (the poll
    /// batch size). Larger batches amortize syscall/flush overhead across more
    /// tasks; smaller batches reduce worst-case latency for a single long
    /// batch. Defaults to 256.
    ///
    /// For a thread-per-core web server handling many short-lived requests,
    /// raising this (e.g. 512-1024) can improve throughput under bursty
    /// accept/completion floods; lowering it tightens tail latency when a
    /// single task does significant synchronous work per poll.
    pub fn batch_size(mut self, batch_size: usize) -> Self {
        self.batch_size = batch_size;
        self
    }

    /// Configure the underlying `io_uring` builder.
    ///
    /// Only used when the io_uring driver is selected (Linux). Allows
    /// tuning flags such as `setup_sqpoll`, `setup_coop_taskrun`,
    /// `setup_submit_all`, etc. with automatic fallback for older kernels.
    ///
    /// # Example
    /// ```
    /// # #[cfg(target_os = "linux")]
    /// # {
    /// use zincio::RuntimeBuilder;
    /// let rt = RuntimeBuilder::new()
    ///     .uring(|b| { b.setup_sqpoll(2000); })
    ///     .build()
    ///     .unwrap();
    /// # }
    /// ```
    #[cfg(target_os = "linux")]
    pub fn uring<F>(mut self, f: F) -> Self
    where
        F: FnOnce(&mut io_uring::Builder),
    {
        let mut builder = match self.driver_kind.take() {
            Some(DriverKind::IoUringCustom(b)) => b,
            _ => io_uring::IoUring::builder(),
        };
        f(&mut builder);
        self.driver_kind = Some(DriverKind::IoUringCustom(builder));
        self
    }

    /// Sets the default blocking thread pool for the runtime with specified maximum number of threads.
    #[cfg(feature = "blocking-default")]
    pub fn default_blocking_pool(mut self, max_threads: usize) -> Self {
        self.blocking_pool = Some(Box::new(DefaultBlockingThreadPool::with_max_threads(
            max_threads,
        )));
        self
    }

    /// Builds the async runtime with the configured settings.
    ///
    /// If no driver was explicitly set, selects the best available driver for the platform.
    pub fn build(self) -> Result<crate::executor::Runtime, std::io::Error> {
        let driver = if let Some(driver_kind) = self.driver_kind {
            driver_kind.into_driver()?
        } else {
            AnyDriver::new_best()?
        };
        Ok(crate::executor::Runtime::with_options(
            driver,
            self.enable_timer,
            self.blocking_pool,
            self.enable_fs_offload,
            self.batch_size,
        ))
    }
}

impl Default for RuntimeBuilder {
    fn default() -> Self {
        Self::new()
    }
}