use async_trait::async_trait;
use bytes::Bytes;
use log::error;
use std::ops::Range;
use crate::{
decoder::CogReader,
error::TiffResult,
};
#[cfg(test)]
use tokio::io::{AsyncReadExt, AsyncSeekExt};
#[cfg(test)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl CogReader for tokio::fs::File {
const IFD_REQ_SIZE: u64 = 16 * 1024;
async fn get_range<'a>(&'a self, range: Range<u64>) -> TiffResult<Bytes> {
use crate::error::TiffError;
let mut file: tokio::fs::File = (*self).try_clone().await?;
file.seek(tokio::io::SeekFrom::Start(range.start))
.await
.map_err(|e| TiffError::TransportError(Box::new(e)))?;
let len = (range.end - range.start) as usize;
let mut buffer = vec![0u8; len];
file.read_exact(&mut buffer)
.await
.map_err(|e| TiffError::TransportError(Box::new(e)))?;
Ok(Bytes::copy_from_slice(&buffer))
}
}
#[cfg(not(feature = "object_store"))]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl CogReader for &[u8] {
const IFD_REQ_SIZE: u64 = 16 * 1024;
async fn get_range(&self, range: Range<u64>) -> TiffResult<Bytes> {
if range.end >= self.len().try_into().unwrap() {
error!("tried to get range {range:?} from {self:?}");
}
let end = std::cmp::min(usize::try_from(range.end)?, self.len());
Ok(Bytes::copy_from_slice(
&self[usize::try_from(range.start)?..end],
))
}
}
#[cfg(feature = "object_store")]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<T: object_store::ObjectStore> CogReader for T {
const IFD_REQ_SIZE: u64 = 16 * 1024;
async fn get_range(&self, range: Range<u64>) -> TiffResult<Bytes> {
self.get_range(
&object_store::path::Path::from(""),
range.start as usize..range.end as usize,
)
.await
.map_err(|e| TiffError::TransportError(Box::new(e)))
}
}