1use std::ffi::{c_void, c_char};
2use std::path::Path;
3
4#[repr(C)]
5pub struct DB(*mut c_void); extern "C" {
8 fn feather_open(path: *const c_char, dim: usize) -> *mut c_void;
9 fn feather_add(db: *mut c_void, id: u64, vec: *const f32, len: usize);
10 fn feather_add_with_meta(db: *mut c_void, id: u64, vec: *const f32, len: usize,
11 timestamp: i64, importance: f32, context_type: u8,
12 source: *const c_char, content: *const c_char);
13 fn feather_search(db: *mut c_void, query: *const f32, len: usize, k: usize,
14 out_ids: *mut u64, out_dists: *mut f32);
15 fn feather_search_with_filter(db: *mut c_void, query: *const f32, len: usize, k: usize,
16 type_filter: u8, source_filter: *const c_char,
17 out_ids: *mut u64, out_dists: *mut f32);
18 fn feather_save(db: *mut c_void);
19 fn feather_close(db: *mut c_void);
20}
21
22impl DB {
23 pub fn open(path: &Path, dim: usize) -> Option<Self> {
24 let c_path = std::ffi::CString::new(path.to_str()?).ok()?;
25 let ptr = unsafe { feather_open(c_path.as_ptr(), dim) };
26 if ptr.is_null() { None } else { Some(DB(ptr)) }
27 }
28
29 pub fn add(&self, id: u64, vec: &[f32]) {
30 unsafe { feather_add(self.0, id, vec.as_ptr(), vec.len()) }
31 }
32
33 pub fn add_with_meta(&self, id: u64, vec: &[f32], timestamp: i64, importance: f32, context_type: u8, source: Option<&str>, content: Option<&str>) {
34 let c_source = source.and_then(|s| std::ffi::CString::new(s).ok());
35 let c_content = content.and_then(|s| std::ffi::CString::new(s).ok());
36
37 unsafe {
38 feather_add_with_meta(
39 self.0, id, vec.as_ptr(), vec.len(),
40 timestamp, importance, context_type,
41 c_source.map_or(std::ptr::null(), |s| s.as_ptr()),
42 c_content.map_or(std::ptr::null(), |s| s.as_ptr())
43 )
44 }
45 }
46
47 pub fn search(&self, query: &[f32], k: usize) -> (Vec<u64>, Vec<f32>) {
48 let mut ids = vec![0u64; k];
49 let mut dists = vec![0f32; k];
50 unsafe {
51 feather_search(self.0, query.as_ptr(), query.len(), k, ids.as_mut_ptr(), dists.as_mut_ptr())
52 };
53 (ids, dists)
54 }
55
56 pub fn search_with_filter(&self, query: &[f32], k: usize, type_filter: Option<u8>, source_filter: Option<&str>) -> (Vec<u64>, Vec<f32>) {
57 let mut ids = vec![0u64; k];
58 let mut dists = vec![0f32; k];
59 let c_source = source_filter.and_then(|s| std::ffi::CString::new(s).ok());
60
61 unsafe {
62 feather_search_with_filter(
63 self.0, query.as_ptr(), query.len(), k,
64 type_filter.unwrap_or(255),
65 c_source.map_or(std::ptr::null(), |s| s.as_ptr()),
66 ids.as_mut_ptr(), dists.as_mut_ptr()
67 )
68 };
69 (ids, dists)
70 }
71
72 pub fn save(&self) { unsafe { feather_save(self.0) } }
73}
74
75impl Drop for DB {
76 fn drop(&mut self) { unsafe { feather_close(self.0) } }
77}