use std::ops::Range;
use bytes::Bytes;
use object_store::ObjectStore;
use object_store::path::Path;
use crate::{AsyncBackend, PmtResult};
#[derive(Debug)]
pub struct ObjectStoreBackend {
store: Box<dyn ObjectStore>,
path: Path,
}
impl ObjectStoreBackend {
pub fn new<P: Into<Path>>(store: Box<dyn ObjectStore>, path: P) -> Self {
Self {
store,
path: path.into(),
}
}
#[must_use]
pub fn store(&self) -> &dyn ObjectStore {
&self.store
}
#[must_use]
pub fn path(&self) -> &Path {
&self.path
}
}
impl AsyncBackend for ObjectStoreBackend {
async fn read(&self, offset: usize, length: usize) -> PmtResult<Bytes> {
use object_store::ObjectStoreExt;
let range = Range {
start: offset as u64,
end: offset as u64 + length as u64,
};
let result = self.store.get_range(&self.path, range).await?;
Ok(result)
}
}
#[cfg(test)]
mod tests {
use object_store::memory::InMemory;
use super::*;
use crate::PmtError;
#[test]
fn test_new_backend() {
let store = Box::new(InMemory::new());
let backend = ObjectStoreBackend::new(store, "test.pmtiles");
assert_eq!(backend.path().as_ref(), "test.pmtiles");
assert_eq!(backend.store().to_string(), "InMemory");
}
#[tokio::test]
async fn test_error_nonexistant() {
let store = Box::new(InMemory::new());
let backend = ObjectStoreBackend::new(store, "nonexistent.pmtiles");
let result = backend.read(0, 100).await;
assert!(matches!(
result.unwrap_err(),
PmtError::ObjectStore(object_store::Error::NotFound { .. })
));
}
}