use core::fmt;
pub type BlockId = u64;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum StorageError {
OutOfBounds {
block_id: BlockId,
block_count: u64,
},
ShortRead {
got: usize,
expected: usize,
},
ShortWrite {
got: usize,
expected: usize,
},
Io {
kind: u8,
},
SyncFailed,
AllFramesPinned,
Unsupported,
}
impl fmt::Display for StorageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StorageError::OutOfBounds {
block_id,
block_count,
} => write!(
f,
"block id {block_id} out of bounds (device has {block_count} blocks)"
),
StorageError::ShortRead { got, expected } => {
write!(f, "short read: buffer len {got}, expected {expected}")
}
StorageError::ShortWrite { got, expected } => {
write!(f, "short write: data len {got}, expected {expected}")
}
StorageError::Io { kind } => write!(f, "i/o error (kind {kind})"),
StorageError::SyncFailed => write!(f, "sync to durable storage failed"),
StorageError::AllFramesPinned => {
write!(f, "buffer pool full: all frames are pinned")
}
StorageError::Unsupported => {
write!(f, "operation not supported by this backend")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for StorageError {}
pub trait BlockDevice {
const BLOCK_SIZE: usize = 4096;
fn read_block(&self, block_id: BlockId, buffer: &mut [u8]) -> Result<(), StorageError>;
fn write_block(&mut self, block_id: BlockId, data: &[u8]) -> Result<(), StorageError>;
fn sync(&mut self) -> Result<(), StorageError>;
fn block_count(&self) -> u64;
}
mod memory;
pub use memory::InMemoryBlockDevice;
#[cfg(feature = "std")]
mod file;
#[cfg(feature = "std")]
pub use file::FileBlockDevice;
#[cfg(all(feature = "std", feature = "mmap"))]
mod mmap;
#[cfg(all(feature = "std", feature = "mmap"))]
pub use mmap::MmapBlockDevice;