pub mod allocator;
pub mod bytes;
pub mod direct_file;
pub mod direct_fs;
pub mod monitor;
use std::{fmt::Debug, future::Future};
use allocator::AlignedAllocator;
use monitor::Monitored;
use crate::{
error::Result, DirectFileDevice, DirectFileDeviceOptions, DirectFsDevice, DirectFsDeviceOptions, IoBytes,
IoBytesMut, Runtime,
};
pub const ALIGN: usize = 4096;
pub const IO_BUFFER_ALLOCATOR: AlignedAllocator<ALIGN> = AlignedAllocator::new();
pub type RegionId = u32;
pub trait DevOptions: Send + Sync + 'static + Debug + Clone {
fn verify(&self) -> Result<()>;
}
pub trait Dev: Send + Sync + 'static + Sized + Clone + Debug {
type Options: DevOptions;
fn capacity(&self) -> usize;
fn region_size(&self) -> usize;
#[must_use]
fn open(options: Self::Options, runtime: Runtime) -> impl Future<Output = Result<Self>> + Send;
#[must_use]
fn write(&self, buf: IoBytes, region: RegionId, offset: u64) -> impl Future<Output = Result<()>> + Send;
#[must_use]
fn read(&self, region: RegionId, offset: u64, len: usize) -> impl Future<Output = Result<IoBytesMut>> + Send;
#[must_use]
fn flush(&self, region: Option<RegionId>) -> impl Future<Output = Result<()>> + Send;
}
pub trait DevExt: Dev {
fn align(&self) -> usize {
ALIGN
}
fn regions(&self) -> usize {
self.capacity() / self.region_size()
}
}
impl<T> DevExt for T where T: Dev {}
#[derive(Debug, Clone)]
pub enum DeviceOptions {
DirectFile(DirectFileDeviceOptions),
DirectFs(DirectFsDeviceOptions),
}
impl From<DirectFileDeviceOptions> for DeviceOptions {
fn from(value: DirectFileDeviceOptions) -> Self {
Self::DirectFile(value)
}
}
impl From<DirectFsDeviceOptions> for DeviceOptions {
fn from(value: DirectFsDeviceOptions) -> Self {
Self::DirectFs(value)
}
}
impl DevOptions for DeviceOptions {
fn verify(&self) -> Result<()> {
match self {
DeviceOptions::DirectFile(dev) => dev.verify(),
DeviceOptions::DirectFs(dev) => dev.verify(),
}
}
}
#[derive(Debug, Clone)]
pub enum Device {
DirectFile(DirectFileDevice),
DirectFs(DirectFsDevice),
}
impl Dev for Device {
type Options = DeviceOptions;
fn capacity(&self) -> usize {
match self {
Device::DirectFile(dev) => dev.capacity(),
Device::DirectFs(dev) => dev.capacity(),
}
}
fn region_size(&self) -> usize {
match self {
Device::DirectFile(dev) => dev.region_size(),
Device::DirectFs(dev) => dev.region_size(),
}
}
async fn open(options: Self::Options, runtime: Runtime) -> Result<Self> {
match options {
DeviceOptions::DirectFile(opts) => Ok(Self::DirectFile(DirectFileDevice::open(opts, runtime).await?)),
DeviceOptions::DirectFs(opts) => Ok(Self::DirectFs(DirectFsDevice::open(opts, runtime).await?)),
}
}
async fn write(&self, buf: IoBytes, region: RegionId, offset: u64) -> Result<()> {
match self {
Device::DirectFile(dev) => dev.write(buf, region, offset).await,
Device::DirectFs(dev) => dev.write(buf, region, offset).await,
}
}
async fn read(&self, region: RegionId, offset: u64, len: usize) -> Result<IoBytesMut> {
match self {
Device::DirectFile(dev) => dev.read(region, offset, len).await,
Device::DirectFs(dev) => dev.read(region, offset, len).await,
}
}
async fn flush(&self, region: Option<RegionId>) -> Result<()> {
match self {
Device::DirectFile(dev) => dev.flush(region).await,
Device::DirectFs(dev) => dev.flush(region).await,
}
}
}
pub type MonitoredDevice = Monitored<Device>;