Every batch input is a NumKong matrix of a base pointer, a row count and a byte stride, so a memory-mapped dataset feeds the index with no reshape and no copy.
An index owns entries, an Executor owns the threads or streams a call runs on, and an Arena holds what a call writes back.
use usearch::*;
let options = DenseOptions {
dimensions: 4,
metric: DenseMetric::Angular,
quantization: Scalar::I8,
..DenseOptions::default()
};
let index = DenseIndex::init_ram(&options, &[])?;
index.reserve(1_000)?; // Optional capacity hint; inserts grow on demand
let keys = [Key::from(42u64), Key::from(43u64)];
let slab: [f32; 8] = [0.2, 0.1, 0.2, 0.1, 0.1, 0.2, 0.1, 0.2];
index.insert(&keys, &rows(&slab, 4)?)?;
let executor = Executor::for_ram(&[], None, 0)?;
let mut arena = Arena::new_in(&executor)?;
let query: [f32; 4] = [0.2, 0.1, 0.2, 0.1];
let matches = index.on(&executor).search(&rows(&query, 4)?, 10, &mut arena)?; // on an executor, into its arena
let mut local_arena = Arena::new()?;
let local = index.search(&rows(&query, 4)?, 10, &mut local_arena)?; // the calling thread, into host pagesEvery verb but clear comes from the DenseVerbs trait, which use usearch::* brings into scope. clear takes &mut DenseIndex, since no other call on the handle may overlap it.