ripvec_core/searchable.rs
1//! Engine-agnostic searchable-index trait.
2//!
3//! Both [`HybridIndex`](crate::hybrid::HybridIndex) (transformer
4//! engines) and [`RipvecIndex`](crate::encoder::ripvec::index::RipvecIndex)
5//! (the cacheless ripvec engine) expose the same operational surface
6//! to downstream consumers: a slice of chunks, the embedding row for
7//! a chunk by index, and a search method that returns `(chunk_idx,
8//! score)` pairs ranked descending.
9//!
10//! Naming the surface as a trait lets LSP / MCP code (navigation,
11//! symbols, hover, references, calls) take `&dyn SearchableIndex`
12//! instead of `&HybridIndex` and work transparently across engines.
13//! Without it, every engine swap requires touching every LSP module.
14
15use crate::chunk::CodeChunk;
16use crate::hybrid::SearchMode;
17
18/// Engine-agnostic searchable index.
19///
20/// Implementations: [`HybridIndex`](crate::hybrid::HybridIndex) for
21/// transformer engines,
22/// [`RipvecIndex`](crate::encoder::ripvec::index::RipvecIndex) for
23/// the ripvec engine.
24pub trait SearchableIndex: Send + Sync {
25 /// Borrow the indexed chunks.
26 fn chunks(&self) -> &[CodeChunk];
27
28 /// Search by text query.
29 ///
30 /// Returns `(chunk_idx, score)` pairs ranked descending. Score is
31 /// normalized to `[0, 1]` regardless of mode so callers can apply
32 /// a single threshold consistently.
33 fn search(&self, query_text: &str, top_k: usize, mode: SearchMode) -> Vec<(usize, f32)>;
34
35 /// Search by similarity to an existing chunk's embedding.
36 ///
37 /// Caller passes the chunk index whose embedding should be used
38 /// as the query vector. The canonical `goto_definition` pattern:
39 /// the LSP layer identifies the chunk at the cursor, then asks
40 /// the index for structurally similar chunks elsewhere.
41 ///
42 /// If `chunk_idx` is out of range or the engine cannot provide
43 /// an embedding for it (keyword-only mode, embedding row not
44 /// stored), implementations fall back to text-only search via
45 /// [`Self::search`].
46 fn search_from_chunk(
47 &self,
48 chunk_idx: usize,
49 query_text: &str,
50 top_k: usize,
51 mode: SearchMode,
52 ) -> Vec<(usize, f32)>;
53}