use anyhow::Result;
use crate::embedding::vector_index::SearchHit;
#[async_trait::async_trait]
pub trait AsyncVectorIndex: Send + Sync {
async fn add(&self, vectors: &[Vec<f32>], ids: &[u64]) -> Result<()>;
async fn remove(&self, ids: &[u64]) -> Result<()>;
async fn search(&self, query: &[f32], k: usize) -> Result<Vec<SearchHit>>;
async fn search_filtered(
&self,
query: &[f32],
k: usize,
allowlist: &[u64],
) -> Result<Vec<SearchHit>>;
async fn len(&self) -> Result<usize>;
async fn is_empty(&self) -> Result<bool> {
Ok(self.len().await? == 0)
}
fn dim(&self) -> usize;
}
#[cfg(test)]
mod tests {
use super::*;
struct StubIndex {
d: usize,
}
#[async_trait::async_trait]
impl AsyncVectorIndex for StubIndex {
async fn add(&self, _vectors: &[Vec<f32>], _ids: &[u64]) -> Result<()> {
Ok(())
}
async fn remove(&self, _ids: &[u64]) -> Result<()> {
Ok(())
}
async fn search(&self, _query: &[f32], _k: usize) -> Result<Vec<SearchHit>> {
Ok(Vec::new())
}
async fn search_filtered(
&self,
_query: &[f32],
_k: usize,
_allowlist: &[u64],
) -> Result<Vec<SearchHit>> {
Ok(Vec::new())
}
async fn len(&self) -> Result<usize> {
Ok(0)
}
fn dim(&self) -> usize {
self.d
}
}
#[tokio::test]
async fn dyn_async_vector_index_object_safe() {
let idx: Box<dyn AsyncVectorIndex> = Box::new(StubIndex { d: 4 });
assert_eq!(idx.dim(), 4);
idx.add(&[vec![0.0; 4]], &[1]).await.unwrap();
assert!(idx.is_empty().await.unwrap());
}
}