use std::io;
use bytes::Bytes;
use crate::tree::{BaoTree, TreeNode};
pub trait ReadAt {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize>;
fn read_exact_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<()> {
let n = self.read_at(offset, buf)?;
if n < buf.len() {
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"short read in read_exact_at",
))
} else {
Ok(())
}
}
}
pub trait WriteAt {
fn write_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<usize>;
fn flush(&mut self) -> io::Result<()>;
fn write_all_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<()> {
let n = self.write_at(offset, buf)?;
if n < buf.len() {
Err(io::Error::new(
io::ErrorKind::WriteZero,
"short write in write_all_at",
))
} else {
Ok(())
}
}
}
pub trait Size {
fn size(&self) -> io::Result<Option<u64>>;
}
pub trait ReadBytesAt {
fn read_bytes_at(&self, offset: u64, size: usize) -> io::Result<Bytes>;
}
pub trait Outboard {
type Hash: AsRef<[u8]> + Clone + Eq + std::fmt::Debug;
fn root(&self) -> Self::Hash;
fn tree(&self) -> BaoTree;
fn load(&self, node: TreeNode) -> io::Result<Option<(Self::Hash, Self::Hash)>>;
}
impl<O: Outboard> Outboard for &O {
type Hash = O::Hash;
fn root(&self) -> Self::Hash {
(**self).root()
}
fn tree(&self) -> BaoTree {
(**self).tree()
}
fn load(&self, node: TreeNode) -> io::Result<Option<(Self::Hash, Self::Hash)>> {
(**self).load(node)
}
}
pub trait OutboardMut: Sized {
type Hash: AsRef<[u8]> + Clone + Eq;
fn save(&mut self, node: TreeNode, hash_pair: &(Self::Hash, Self::Hash)) -> io::Result<()>;
fn sync(&mut self) -> io::Result<()>;
}
impl ReadAt for Vec<u8> {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
let offset = offset as usize;
if offset >= self.len() {
return Ok(0);
}
let available = &self[offset..];
let n = buf.len().min(available.len());
buf[..n].copy_from_slice(&available[..n]);
Ok(n)
}
}
impl WriteAt for Vec<u8> {
fn write_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<usize> {
let offset = offset as usize;
let end = offset + buf.len();
if end > self.len() {
self.resize(end, 0);
}
self[offset..end].copy_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Size for Vec<u8> {
fn size(&self) -> io::Result<Option<u64>> {
Ok(Some(self.len() as u64))
}
}
impl ReadBytesAt for Vec<u8> {
fn read_bytes_at(&self, offset: u64, size: usize) -> io::Result<Bytes> {
let offset = offset as usize;
if offset + size > self.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"read_bytes_at out of bounds",
));
}
Ok(Bytes::copy_from_slice(&self[offset..offset + size]))
}
}
impl ReadAt for &[u8] {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
let offset = offset as usize;
if offset >= self.len() {
return Ok(0);
}
let available = &self[offset..];
let n = buf.len().min(available.len());
buf[..n].copy_from_slice(&available[..n]);
Ok(n)
}
}
impl ReadBytesAt for &[u8] {
fn read_bytes_at(&self, offset: u64, size: usize) -> io::Result<Bytes> {
let offset = offset as usize;
if offset + size > self.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"read_bytes_at out of bounds",
));
}
Ok(Bytes::copy_from_slice(&self[offset..offset + size]))
}
}
impl ReadAt for Bytes {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
let offset = offset as usize;
if offset >= self.len() {
return Ok(0);
}
let available = &self[offset..];
let n = buf.len().min(available.len());
buf[..n].copy_from_slice(&available[..n]);
Ok(n)
}
}
impl ReadBytesAt for Bytes {
fn read_bytes_at(&self, offset: u64, size: usize) -> io::Result<Bytes> {
let offset = offset as usize;
if offset + size > self.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"read_bytes_at out of bounds",
));
}
Ok(self.slice(offset..offset + size))
}
}
impl Size for Bytes {
fn size(&self) -> io::Result<Option<u64>> {
Ok(Some(self.len() as u64))
}
}
impl<T: WriteAt> WriteAt for &mut T {
fn write_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<usize> {
(**self).write_at(offset, buf)
}
fn flush(&mut self) -> io::Result<()> {
(**self).flush()
}
}
#[cfg(not(target_family = "wasm"))]
impl ReadAt for std::fs::File {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
#[cfg(unix)]
{
std::os::unix::fs::FileExt::read_at(self, buf, offset)
}
#[cfg(windows)]
{
std::os::windows::fs::FileExt::seek_read(self, buf, offset)
}
}
}
#[cfg(not(target_family = "wasm"))]
impl WriteAt for std::fs::File {
fn write_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<usize> {
#[cfg(unix)]
{
std::os::unix::fs::FileExt::write_at(self, buf, offset)
}
#[cfg(windows)]
{
std::os::windows::fs::FileExt::seek_write(self, buf, offset)
}
}
fn flush(&mut self) -> io::Result<()> {
io::Write::flush(self)
}
}
#[cfg(not(target_family = "wasm"))]
impl Size for std::fs::File {
fn size(&self) -> io::Result<Option<u64>> {
Ok(Some(self.metadata()?.len()))
}
}
#[cfg(not(target_family = "wasm"))]
impl ReadAt for &std::fs::File {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
#[cfg(unix)]
{
std::os::unix::fs::FileExt::read_at(*self, buf, offset)
}
#[cfg(windows)]
{
std::os::windows::fs::FileExt::seek_read(*self, buf, offset)
}
}
}
#[cfg(not(target_family = "wasm"))]
impl ReadBytesAt for std::fs::File {
fn read_bytes_at(&self, offset: u64, size: usize) -> io::Result<Bytes> {
let mut buf = vec![0u8; size];
self.read_exact_at(offset, &mut buf)?;
Ok(Bytes::from(buf))
}
}
#[cfg(not(target_family = "wasm"))]
impl ReadBytesAt for &std::fs::File {
fn read_bytes_at(&self, offset: u64, size: usize) -> io::Result<Bytes> {
let mut buf = vec![0u8; size];
self.read_exact_at(offset, &mut buf)?;
Ok(Bytes::from(buf))
}
}