Skip to main content

mnemo_core/index/
mod.rs

1pub mod usearch;
2
3use crate::error::Result;
4use uuid::Uuid;
5
6/// A pluggable approximate-nearest-neighbour index over memory embeddings.
7///
8/// `search` / `filtered_search` are **async** (v0.5.18). The PostgreSQL
9/// (pgvector) backend runs a real `sqlx` query on the *ambient* Tokio runtime,
10/// so the read path `.await`s it directly instead of bridging through a
11/// `block_on` — which, inside the server/CLI `#[tokio::main]` runtime, could
12/// panic ("Cannot start a runtime from within a runtime") or deadlock. The
13/// in-memory USearch backend does synchronous CPU work inside its async method,
14/// so it needs no runtime and assumes no runtime flavor. `add` / `remove` /
15/// `save` / `load` / `len` remain synchronous.
16///
17/// The `filter` for `filtered_search` must be `Send + Sync` because it is held
18/// across the `.await` inside the resulting `Send` future.
19#[async_trait::async_trait]
20pub trait VectorIndex: Send + Sync {
21    fn add(&self, id: Uuid, vector: &[f32]) -> Result<()>;
22    fn remove(&self, id: Uuid) -> Result<()>;
23    async fn search(&self, query: &[f32], limit: usize) -> Result<Vec<(Uuid, f32)>>;
24    async fn filtered_search(
25        &self,
26        query: &[f32],
27        limit: usize,
28        filter: &(dyn Fn(Uuid) -> bool + Send + Sync),
29    ) -> Result<Vec<(Uuid, f32)>>;
30    fn save(&self, path: &std::path::Path) -> Result<()>;
31    fn load(&self, path: &std::path::Path) -> Result<()>;
32    fn len(&self) -> usize;
33    fn is_empty(&self) -> bool {
34        self.len() == 0
35    }
36}