use std::collections::HashMap;
use std::io::{Read, Seek, SeekFrom};
use std::sync::Arc;
use crate::error::{LaurusError, Result};
use crate::storage::Storage;
use crate::vector::core::vector::Vector;
#[derive(Debug, Clone)]
pub enum VectorStorage {
Owned(Arc<HashMap<(u64, String), Vector>>),
OnDemand {
storage: Arc<dyn Storage>,
file_name: String,
offsets: Arc<HashMap<(u64, String), u64>>,
},
}
impl VectorStorage {
pub fn keys(&self) -> Vec<(u64, String)> {
match self {
VectorStorage::Owned(map) => map.keys().cloned().collect(),
VectorStorage::OnDemand { offsets, .. } => offsets.keys().cloned().collect(),
}
}
pub fn len(&self) -> usize {
match self {
VectorStorage::Owned(map) => map.len(),
VectorStorage::OnDemand { offsets, .. } => offsets.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn contains_key(&self, key: &(u64, String)) -> bool {
match self {
VectorStorage::Owned(map) => map.contains_key(key),
VectorStorage::OnDemand { offsets, .. } => offsets.contains_key(key),
}
}
pub fn get(&self, key: &(u64, String), dimension: usize) -> Result<Option<Vector>> {
match self {
VectorStorage::Owned(map) => Ok(map.get(key).cloned()),
VectorStorage::OnDemand {
storage,
file_name,
offsets,
} => {
if let Some(&offset) = offsets.get(key) {
let mut input = storage.open_input(file_name).map_err(|e| {
LaurusError::internal(format!("Failed to open vector file: {e}"))
})?;
input
.seek(SeekFrom::Start(offset))
.map_err(LaurusError::Io)?;
let mut doc_id_buf = [0u8; 8];
input.read_exact(&mut doc_id_buf)?;
let mut field_name_len_buf = [0u8; 4];
input.read_exact(&mut field_name_len_buf)?;
let field_name_len = u32::from_le_bytes(field_name_len_buf) as usize;
let mut field_name_buf = vec![0u8; field_name_len];
input.read_exact(&mut field_name_buf)?;
let mut values = vec![0.0f32; dimension];
for value in &mut values {
let mut value_buf = [0u8; 4];
input.read_exact(&mut value_buf)?;
*value = f32::from_le_bytes(value_buf);
}
Ok(Some(Vector::new(values)))
} else {
Ok(None)
}
}
}
}
}