use crate::error::{Error, Result};
use crate::faiss_try;
use crate::index::{
CpuIndex, FromInnerPtr, BinaryIndexImpl, IndexImpl,
NativeIndex,
};
use faiss_sys::*;
use std::ffi::CString;
use std::os::raw::c_int;
use std::ptr;
pub use super::io_flags::IoFlags;
pub fn write_index<I, P>(index: &I, file_name: P) -> Result<()>
where
I: NativeIndex<Inner = FaissIndex>,
I: CpuIndex,
P: AsRef<str>,
{
unsafe {
let f = file_name.as_ref();
let f = CString::new(f).map_err(|_| Error::BadFilePath)?;
faiss_try(faiss_write_index_fname(index.inner_ptr(), f.as_ptr()))?;
Ok(())
}
}
pub fn write_index_binary<I, P>(index: &I, file_name: P) -> Result<()>
where
I: NativeIndex<u8, i32, Inner = FaissIndexBinary>,
I: CpuIndex<u8, i32>,
P: AsRef<str>,
{
unsafe {
let f = file_name.as_ref();
let f = CString::new(f).map_err(|_| Error::BadFilePath)?;
faiss_try(faiss_write_index_binary_fname(
index.inner_ptr(),
f.as_ptr(),
))?;
Ok(())
}
}
pub fn read_index<P>(file_name: P) -> Result<IndexImpl>
where
P: AsRef<str>,
{
unsafe {
let f = file_name.as_ref();
let f = CString::new(f).map_err(|_| Error::BadFilePath)?;
let mut inner = ptr::null_mut();
faiss_try(faiss_read_index_fname(
f.as_ptr(),
IoFlags::MEM_RESIDENT.into(),
&mut inner,
))?;
Ok(IndexImpl::from_inner_ptr(inner))
}
}
pub fn read_index_binary<P>(file_name: P) -> Result<BinaryIndexImpl>
where
P: AsRef<str>,
{
unsafe {
let f = file_name.as_ref();
let f = CString::new(f).map_err(|_| Error::BadFilePath)?;
let mut inner = ptr::null_mut();
faiss_try(faiss_read_index_binary_fname(
f.as_ptr(),
IoFlags::MEM_RESIDENT.into(),
&mut inner,
))?;
Ok(BinaryIndexImpl::from_inner_ptr(inner))
}
}
pub fn read_index_with_flags<P>(file_name: P, io_flags: IoFlags) -> Result<IndexImpl>
where
P: AsRef<str>,
{
unsafe {
let f = file_name.as_ref();
let f = CString::new(f).map_err(|_| Error::BadFilePath)?;
let mut inner = ptr::null_mut();
faiss_try(faiss_read_index_fname(
f.as_ptr(),
io_flags.0 as c_int,
&mut inner,
))?;
Ok(IndexImpl::from_inner_ptr(inner))
}
}
pub fn read_index_binary_with_flags<P>(file_name: P, io_flags: IoFlags) -> Result<BinaryIndexImpl>
where
P: AsRef<str>,
{
unsafe {
let f = file_name.as_ref();
let f = CString::new(f).map_err(|_| Error::BadFilePath)?;
let mut inner = ptr::null_mut();
faiss_try(faiss_read_index_binary_fname(
f.as_ptr(),
io_flags.0 as c_int,
&mut inner,
))?;
Ok(BinaryIndexImpl::from_inner_ptr(inner))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::index::flat::FlatIndex;
use crate::index::Index;
use crate::index_binary_factory;
const D: u32 = 8;
#[test]
fn write_read() {
let mut index = FlatIndex::new_l2(D).unwrap();
assert_eq!(index.d(), D);
assert_eq!(index.ntotal(), 0);
let some_data = &[
7.5_f32, -7.5, 7.5, -7.5, 7.5, 7.5, 7.5, 7.5, -1., 1., 1., 1., 1., 1., 1., -1., 4.,
-4., -8., 1., 1., 2., 4., -1., 8., 8., 10., -10., -10., 10., -10., 10., 16., 16., 32.,
25., 20., 20., 40., 15.,
];
index.add(some_data).unwrap();
assert_eq!(index.ntotal(), 5);
let filepath = ::std::env::temp_dir().join("test_write_read.index");
let filename = filepath.to_str().unwrap();
write_index(&index, filename).unwrap();
let index = read_index(&filename).unwrap();
assert_eq!(index.ntotal(), 5);
::std::fs::remove_file(&filepath).unwrap();
}
#[test]
fn test_read_with_flags() {
let index = read_index_with_flags("file_name", IoFlags::MEM_MAP | IoFlags::READ_ONLY);
assert!(index.is_err());
}
#[test]
fn write_read_binary() {
let mut index = index_binary_factory(D, "BFlat").unwrap();
assert_eq!(index.d(), D);
assert_eq!(index.ntotal(), 0);
let some_data: &[u8; 5] = &[0, 1, 2, 3, 4];
index.add(some_data).unwrap();
assert_eq!(index.ntotal(), 5);
let filepath = ::std::env::temp_dir().join("test_write_read_binary.index");
let filename = filepath.to_str().unwrap();
write_index_binary(&index, filename).unwrap();
let index = read_index_binary(&filename).unwrap();
assert_eq!(index.ntotal(), 5);
::std::fs::remove_file(&filepath).unwrap();
}
#[test]
fn test_read_binary_with_flags() {
let index =
read_index_binary_with_flags("file_name", IoFlags::MEM_MAP | IoFlags::READ_ONLY);
assert!(index.is_err());
}
}