use std::path::Path;
use crate::core::format::{HEADER_SIZE, VERSION};
use crate::core::{FuseError, FuseResult, ReaderCore};
use super::stats::Stats;
#[cfg(feature = "msgpack")]
use serde::de::DeserializeOwned;
pub struct FuseReader {
core: ReaderCore,
}
impl FuseReader {
pub fn open(path: impl AsRef<Path>) -> FuseResult<Self> {
Ok(Self {
core: ReaderCore::open(path, true)?,
})
}
pub fn open_unverified(path: impl AsRef<Path>) -> FuseResult<Self> {
Ok(Self {
core: ReaderCore::open(path, false)?,
})
}
#[inline]
pub fn core(&self) -> &ReaderCore {
&self.core
}
pub fn get_raw(&self, key: impl AsRef<[u8]>) -> FuseResult<Option<Vec<u8>>> {
self.core.get(key.as_ref())
}
#[inline]
pub fn exists(&self, key: impl AsRef<[u8]>) -> bool {
self.core.exists(key.as_ref())
}
#[inline]
pub fn len(&self) -> usize {
self.core.num_keys() as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.core.num_keys() == 0
}
#[inline]
pub fn keys_raw(&self) -> &[Vec<u8>] {
self.core.sorted_keys()
}
pub fn keys(&self) -> Vec<String> {
self.core.keys()
}
pub fn items_raw(&self) -> FuseResult<Vec<(String, Vec<u8>)>> {
self.core.items()
}
pub fn objects_raw(&self) -> FuseResult<Vec<Vec<u8>>> {
self.core.objects()
}
pub fn prefix_raw(&self, prefix: impl AsRef<[u8]>) -> FuseResult<Vec<(String, Vec<u8>)>> {
self.core.prefix(prefix.as_ref())
}
pub fn prefix_iter(&self, prefix: impl AsRef<[u8]>) -> PrefixIter<'_> {
let prefix = prefix.as_ref().to_vec();
let pos = self.core.lower_bound(&prefix);
PrefixIter {
reader: &self.core,
prefix,
pos,
}
}
#[cfg(feature = "msgpack")]
pub fn get<T: DeserializeOwned>(&self, key: impl AsRef<[u8]>) -> FuseResult<Option<T>> {
match self.core.get(key.as_ref())? {
None => Ok(None),
Some(raw) => Ok(Some(super::codec::decode(&raw)?)),
}
}
#[cfg(feature = "msgpack")]
pub fn prefix<T: DeserializeOwned>(
&self,
prefix: impl AsRef<[u8]>,
) -> FuseResult<Vec<(String, T)>> {
self.core
.prefix(prefix.as_ref())?
.into_iter()
.map(|(k, raw)| Ok((k, super::codec::decode(&raw)?)))
.collect()
}
#[cfg(feature = "msgpack")]
pub fn items<T: DeserializeOwned>(&self) -> FuseResult<Vec<(String, T)>> {
self.core
.items()?
.into_iter()
.map(|(k, raw)| Ok((k, super::codec::decode(&raw)?)))
.collect()
}
#[cfg(feature = "msgpack")]
pub fn objects<T: DeserializeOwned>(&self) -> FuseResult<Vec<T>> {
self.core
.objects()?
.into_iter()
.map(|raw| super::codec::decode(&raw))
.collect()
}
pub fn stats(&self) -> Stats {
Stats {
path: self.core.path().to_path_buf(),
version: VERSION,
num_keys: self.core.num_keys(),
num_objects: self.core.num_objects(),
index_offset: self.core.index_offset(),
data_offset: HEADER_SIZE as u64,
file_size: self.core.file_size(),
file_crc32: self.core.stored_crc(),
}
}
#[inline]
pub fn path(&self) -> &Path {
self.core.path()
}
pub fn verify(&self) -> FuseResult<()> {
self.core.verify().map(|_| ())
}
pub fn is_valid(&self) -> bool {
matches!(self.core.verify(), Ok(true))
}
}
impl std::fmt::Debug for FuseReader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FuseReader")
.field("path", &self.core.path())
.field("keys", &self.core.num_keys())
.field("objects", &self.core.num_objects())
.finish()
}
}
pub struct PrefixIter<'a> {
reader: &'a ReaderCore,
prefix: Vec<u8>,
pos: usize,
}
impl Iterator for PrefixIter<'_> {
type Item = Result<(String, Vec<u8>), FuseError>;
fn next(&mut self) -> Option<Self::Item> {
let keys = self.reader.sorted_keys();
if self.pos >= keys.len() || !keys[self.pos].starts_with(&self.prefix) {
return None;
}
let key = String::from_utf8_lossy(&keys[self.pos]).into_owned();
let offset = self.reader.sorted_offsets()[self.pos];
self.pos += 1;
Some(self.reader.read_at(offset).map(|raw| (key, raw)))
}
}