use std::path::Path;
use tokio::fs::{File, OpenOptions};
use tokio::io::Result as TokioResult;
use tokio::io::{SeekFrom, AsyncSeekExt, AsyncWriteExt, AsyncReadExt};
pub struct Seq {
file: File,
block_size: usize,
}
impl Seq {
pub async fn new(path: impl AsRef<Path>, block_size: usize) ->
TokioResult<Self> {
let file = OpenOptions::new()
.write(true)
.read(true)
.create(true)
.open(path)
.await?;
Ok(Self { file, block_size })
}
pub fn block_size(&self) -> usize {
self.block_size
}
pub async fn size(&self) -> TokioResult<usize> {
let data = self.file.metadata().await?;
Ok(data.len() as usize / self.block_size)
}
pub async fn resize(&self, new_size: usize) -> TokioResult<()> {
let byte_size = (new_size * self.block_size) as u64;
self.file.set_len(byte_size).await?;
Ok(())
}
pub async fn push(&mut self, block: &[u8]) -> TokioResult<usize> {
let pos = SeekFrom::End(0);
let offset = self.file.seek(pos).await?;
self.file.write_all(block).await?;
self.file.flush().await?;
let ix = offset as usize / self.block_size;
Ok(ix)
}
pub async fn get(&mut self, ix: usize, block: &mut [u8]) ->
TokioResult<()> {
let byte_ix = (ix * self.block_size) as u64;
let pos = SeekFrom::Start(byte_ix);
self.file.seek(pos).await?;
self.file.read_exact(block).await?;
Ok(())
}
pub async fn update(&mut self, ix: usize, block: &[u8]) -> TokioResult<()> {
let byte_ix = (ix * self.block_size) as u64;
let pos = SeekFrom::Start(byte_ix);
self.file.seek(pos).await?;
self.file.write_all(block).await?;
self.file.flush().await?;
Ok(())
}
pub async fn push_empty(&mut self, len: usize) -> TokioResult<usize> {
let block = vec![0u8; len * self.block_size];
let ix = self.push(&block).await?;
Ok(ix)
}
}