use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyDict, PyList};
use crate::core::format::{HEADER_SIZE, VERSION};
use crate::core::ReaderCore;
use super::util::extract_key;
#[pyclass(name = "_FuseReader")]
pub struct FuseReader {
inner: ReaderCore,
}
#[pymethods]
impl FuseReader {
#[new]
#[pyo3(signature = (path, verify = true))]
fn new(path: &str, verify: bool) -> PyResult<Self> {
Ok(Self {
inner: ReaderCore::open(path, verify)?,
})
}
fn get_raw<'py>(
&self,
py: Python<'py>,
key: &Bound<'_, PyAny>,
) -> PyResult<Option<Bound<'py, PyBytes>>> {
let k = extract_key(key)?;
match self.inner.get(&k)? {
None => Ok(None),
Some(raw) => Ok(Some(PyBytes::new(py, &raw))),
}
}
fn exists(&self, key: &Bound<'_, PyAny>) -> PyResult<bool> {
Ok(self.inner.exists(&extract_key(key)?))
}
fn prefix_raw(&self, py: Python<'_>, prefix: &Bound<'_, PyAny>) -> PyResult<Py<PyList>> {
let p = extract_key(prefix)?;
let list = PyList::empty(py);
for (key_str, raw) in self.inner.prefix(&p)? {
list.append((key_str, PyBytes::new(py, &raw)))?;
}
Ok(list.into())
}
fn keys(&self) -> Vec<String> {
self.inner.keys()
}
fn items_raw(&self, py: Python<'_>) -> PyResult<Py<PyList>> {
let list = PyList::empty(py);
for (key_str, raw) in self.inner.items()? {
list.append((key_str, PyBytes::new(py, &raw)))?;
}
Ok(list.into())
}
fn items_raw_bytes(&self, py: Python<'_>) -> PyResult<Py<PyList>> {
let core = &self.inner;
let list = PyList::empty(py);
for (key, &offset) in core.sorted_keys().iter().zip(core.sorted_offsets()) {
let raw = core.read_at(offset)?;
list.append((PyBytes::new(py, key), PyBytes::new(py, &raw)))?;
}
Ok(list.into())
}
fn objects_raw(&self, py: Python<'_>) -> PyResult<Py<PyList>> {
let list = PyList::empty(py);
for raw in self.inner.objects()? {
list.append(PyBytes::new(py, &raw))?;
}
Ok(list.into())
}
fn stats<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
let d = PyDict::new(py);
d.set_item("path", self.inner.path().to_string_lossy().as_ref())?;
d.set_item("version", VERSION)?;
d.set_item("num_keys", self.inner.num_keys())?;
d.set_item("num_objects", self.inner.num_objects())?;
d.set_item("index_offset", self.inner.index_offset())?;
d.set_item("data_offset", HEADER_SIZE as u64)?;
d.set_item("file_size_kb", self.inner.file_size() as f64 / 1024.0)?;
d.set_item("file_crc32", format!("{:#010x}", self.inner.stored_crc()))?;
Ok(d)
}
fn verify(&self) -> PyResult<bool> {
Ok(self.inner.verify()?)
}
fn close(&self) {}
fn __enter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __exit__(
&self,
_exc_type: Option<Bound<'_, PyAny>>,
_exc_val: Option<Bound<'_, PyAny>>,
_exc_tb: Option<Bound<'_, PyAny>>,
) -> bool {
false }
fn __repr__(&self) -> String {
format!(
"_FuseReader('{}', keys={}, objects={})",
self.inner.path().display(),
self.inner.num_keys(),
self.inner.num_objects(),
)
}
}