1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! # iqdb-index
//!
//! The index-trait layer for the HiveDB **iqdb** vector-database spine. It
//! defines the shape every concrete index (flat, HNSW, IVF, …) implements so
//! the engine can hold them polymorphically, and exposes [`IndexStats`] for
//! runtime introspection. Its only dependency is
//! [`iqdb-types`](iqdb_types) — the shared vocabulary.
//!
//! ## Why the trait is split
//!
//! [`Index`] carries an associated `type Config: Default + Clone` and a
//! `Self`-returning `fn new(...) -> Result<Self>`. That combination makes a
//! single trait non-object-safe — `Box<dyn Index>` would not compile. The
//! engine needs to hold a heterogeneous set of indexes, so the trait is
//! split:
//!
//! - [`IndexCore`] — the object-safe operational surface: `insert`,
//! `delete`, `search`, `len`, `dim`, `metric`, `flush`, `stats` (plus the
//! default batch shims). The engine stores `Box<dyn IndexCore>` through
//! this trait.
//! - [`Index`] — adds the associated `Config` and `new`. Used where the
//! concrete index type is known.
//!
//! Every concrete index implements **both**.
//!
//! ## Ordering contract on `Hit.distance`
//!
//! [`iqdb_types::Hit::distance`] is documented as **smaller is nearer**.
//! Four of the five metrics (Cosine, Euclidean, Manhattan, Hamming) already
//! satisfy that contract under [`iqdb_types::DistanceMetric`]. For
//! `DotProduct` the raw value is a similarity (larger is more similar), so
//! every index MUST negate it at the boundary — store `-dot` in
//! `Hit.distance` — to keep one ordering invariant across the index family.
//!
//! ## Example
//!
//! ```
//! use std::sync::Arc;
//!
//! use iqdb_index::{Index, IndexCore, IndexStats};
//! use iqdb_types::{
//! DistanceMetric, Hit, IqdbError, Metadata, Result, SearchParams, VectorId,
//! };
//!
//! /// A toy in-memory index used only to document the trait shape.
//! struct Toy {
//! dim: usize,
//! metric: DistanceMetric,
//! ids: Vec<VectorId>,
//! }
//!
//! #[derive(Default, Clone)]
//! struct ToyConfig;
//!
//! impl IndexCore for Toy {
//! fn insert(&mut self, id: VectorId, _v: Arc<[f32]>, _m: Option<Metadata>) -> Result<()> {
//! self.ids.push(id);
//! Ok(())
//! }
//! fn delete(&mut self, id: &VectorId) -> Result<()> {
//! match self.ids.iter().position(|x| x == id) {
//! Some(pos) => {
//! let _removed = self.ids.remove(pos);
//! Ok(())
//! }
//! None => Err(IqdbError::NotFound),
//! }
//! }
//! fn search(&self, _q: &[f32], _p: &SearchParams) -> Result<Vec<Hit>> {
//! Ok(Vec::new())
//! }
//! fn len(&self) -> usize { self.ids.len() }
//! fn dim(&self) -> usize { self.dim }
//! fn metric(&self) -> DistanceMetric { self.metric }
//! fn flush(&mut self) -> Result<()> { Ok(()) }
//! fn stats(&self) -> IndexStats {
//! IndexStats {
//! n_vectors: self.ids.len(),
//! index_type: "toy",
//! ..IndexStats::default()
//! }
//! }
//! }
//!
//! impl Index for Toy {
//! type Config = ToyConfig;
//! fn new(dim: usize, metric: DistanceMetric, _c: Self::Config) -> Result<Self> {
//! Ok(Toy { dim, metric, ids: Vec::new() })
//! }
//! }
//!
//! # fn main() -> Result<()> {
//! let mut idx = Toy::new(3, DistanceMetric::Cosine, ToyConfig)?;
//! assert!(idx.is_empty());
//! idx.insert(VectorId::from(1u64), Arc::<[f32]>::from(&[1.0, 0.0, 0.0][..]), None)?;
//! assert_eq!(idx.len(), 1);
//! idx.delete(&VectorId::from(1u64))?;
//! assert!(idx.is_empty());
//! # Ok(())
//! # }
//! ```
pub use crate;
pub use crateIndexStats;
/// The version of this crate, taken from `Cargo.toml` at compile time.
///
/// Exposed so a consumer can report the exact `iqdb-index` build it links
/// against — useful in diagnostics and version-skew checks across the iqdb
/// crate family.
///
/// # Examples
///
/// ```
/// // Carries a `major.minor.patch` SemVer core.
/// let version = iqdb_index::VERSION;
/// assert_eq!(version.split('.').count(), 3);
/// assert!(version.split('.').all(|part| !part.is_empty()));
/// ```
pub const VERSION: &str = env!;