use crate::api::HttpClient;
use crate::error::BioLibError;
use super::remote_endpoints::RemoteEndpoint;
pub trait IndexableBuffer {
fn get_data(&self, start: u64, length: u64) -> crate::Result<Vec<u8>>;
}
pub struct RemoteIndexableBuffer {
endpoint: Box<dyn RemoteEndpoint>,
http: HttpClient,
}
impl RemoteIndexableBuffer {
pub fn new(endpoint: Box<dyn RemoteEndpoint>) -> Self {
Self {
endpoint,
http: HttpClient::shared(),
}
}
}
impl IndexableBuffer for RemoteIndexableBuffer {
fn get_data(&self, start: u64, length: u64) -> crate::Result<Vec<u8>> {
if length == 0 {
return Ok(Vec::new());
}
let url = self.endpoint.get_remote_url()?;
let end = start + length - 1;
crate::logging::debug(&format!("Fetching bytes {start}-{end} ({length} bytes)"));
let response = self.http.get_with_range(&url, start, end)?;
if response.body.len() != length as usize {
return Err(BioLibError::BinaryFormat(format!(
"Expected {} bytes, got {}",
length,
response.body.len()
)));
}
Ok(response.body)
}
}
pub struct InMemoryIndexableBuffer {
data: Vec<u8>,
}
impl InMemoryIndexableBuffer {
pub fn new(data: Vec<u8>) -> Self {
Self { data }
}
}
impl IndexableBuffer for InMemoryIndexableBuffer {
fn get_data(&self, start: u64, length: u64) -> crate::Result<Vec<u8>> {
if length == 0 {
return Ok(Vec::new());
}
let s = start as usize;
let e = s + length as usize;
if e > self.data.len() {
return Err(BioLibError::BinaryFormat(
"Read past end of buffer".to_string(),
));
}
Ok(self.data[s..e].to_vec())
}
}