pub use zvec_sys as ffi;
pub mod collection;
pub mod doc;
pub mod error;
pub mod query;
pub mod rerank;
pub mod schema;
pub mod types;
#[cfg(feature = "sync")]
pub mod sync;
pub mod fts;
pub mod multi_query;
pub use collection::Collection;
pub use collection::CollectionStats;
pub use collection::IndexParams;
pub use doc::Doc;
pub use error::{Error, Result, StatusCode};
pub use fts::Fts;
pub use multi_query::{MultiQuery, SubQuery};
pub use query::{
FlatQueryParam, FtsQueryParam, GroupByVectorQuery, HnswQueryParam, IVFQueryParam, QueryParam,
VectorQuery,
};
pub use rerank::{RrfReRanker, WeightedReRanker};
pub use schema::{CollectionSchema, FieldSchema, VectorSchema};
pub use types::{DataType, IndexType, LogLevel, LogType, MetricType, QuantizeType};
#[cfg(feature = "sync")]
pub use sync::{create_and_open_shared, open_shared, SharedCollection};
pub fn init() -> Result<()> {
let code = unsafe { ffi::zvec_initialize(std::ptr::null()) };
crate::error::check_error(code as std::os::raw::c_int)
}
pub fn is_initialized() -> bool {
unsafe { ffi::zvec_is_initialized() }
}
pub fn shutdown() -> Result<()> {
let code = unsafe { ffi::zvec_shutdown() };
crate::error::check_error(code as std::os::raw::c_int)
}
pub fn version() -> String {
unsafe {
let ptr = ffi::zvec_get_version();
if ptr.is_null() {
return String::new();
}
std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}
pub fn version_tuple() -> (u32, u32, u32) {
unsafe {
(
ffi::zvec_get_version_major() as u32,
ffi::zvec_get_version_minor() as u32,
ffi::zvec_get_version_patch() as u32,
)
}
}
pub fn check_version(major: u32, minor: u32, patch: u32) -> bool {
unsafe {
ffi::zvec_check_version(
major as std::os::raw::c_int,
minor as std::os::raw::c_int,
patch as std::os::raw::c_int,
)
}
}
pub fn set_default_jieba_dict_dir(path: Option<&str>) {
let cstr = match path {
Some(s) if !s.is_empty() => {
Some(std::ffi::CString::new(s).expect("jieba dict dir contains NUL byte"))
}
_ => None,
};
let ptr = cstr
.as_ref()
.map(|c| c.as_ptr())
.unwrap_or(std::ptr::null());
unsafe { ffi::zvec_set_default_jieba_dict_dir(ptr) };
}
pub struct LogConfig {
level: LogLevel,
is_file: bool,
dir: Option<String>,
basename: Option<String>,
max_file_size_mb: u32,
overdue_days: u32,
}
impl LogConfig {
pub fn console(level: LogLevel) -> Self {
Self {
level,
is_file: false,
dir: None,
basename: None,
max_file_size_mb: 0,
overdue_days: 0,
}
}
pub fn file(level: LogLevel, dir: &str, basename: &str) -> Self {
Self {
level,
is_file: true,
dir: Some(dir.to_string()),
basename: Some(basename.to_string()),
max_file_size_mb: 100,
overdue_days: 7,
}
}
pub fn with_max_file_size(mut self, size: u64) -> Self {
self.max_file_size_mb = ((size + (1 << 20) - 1) >> 20) as u32;
self
}
pub fn with_overdue_days(mut self, days: u32) -> Self {
self.overdue_days = days;
self
}
pub fn apply(self) -> Result<()> {
use std::os::raw::c_int;
let log_config = if self.is_file {
let dir = self
.dir
.as_ref()
.expect("file logger requires dir; this is a LogConfig bug");
let basename = self
.basename
.as_ref()
.expect("file logger requires basename; this is a LogConfig bug");
let dir_c = std::ffi::CString::new(dir.as_str())
.map_err(|e| Error::InvalidArgument(e.to_string()))?;
let basename_c = std::ffi::CString::new(basename.as_str())
.map_err(|e| Error::InvalidArgument(e.to_string()))?;
unsafe {
ffi::zvec_config_log_create_file(
self.level.into(),
dir_c.as_ptr(),
basename_c.as_ptr(),
self.max_file_size_mb,
self.overdue_days,
)
}
} else {
unsafe { ffi::zvec_config_log_create_console(self.level.into()) }
};
if log_config.is_null() {
return Err(Error::InternalError(
"zvec_config_log_create_* returned null".into(),
));
}
let config_data = unsafe { ffi::zvec_config_data_create() };
if config_data.is_null() {
unsafe { ffi::zvec_config_log_destroy(log_config) };
return Err(Error::InternalError(
"zvec_config_data_create returned null".into(),
));
}
let mut overall: Result<()> = Ok(());
let set_code = unsafe { ffi::zvec_config_data_set_log_config(config_data, log_config) };
if let Err(e) = crate::error::check_error(set_code as c_int) {
overall = Err(e);
} else {
let init_code = unsafe { ffi::zvec_initialize(config_data) };
if let Err(e) = crate::error::check_error(init_code as c_int) {
overall = Err(e);
}
}
unsafe { ffi::zvec_config_data_destroy(config_data) };
overall
}
}
#[deprecated(note = "upstream zvec v0.5.0 does not expose a metric listing API")]
pub fn list_registered_metrics() -> Vec<String> {
Vec::new()
}
pub fn create_and_open<P: AsRef<std::path::Path>>(
path: P,
schema: CollectionSchema,
) -> Result<Collection> {
Collection::create_and_open(path, schema)
}
pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Collection> {
Collection::open(path)
}
#[macro_export]
macro_rules! doc {
($pk:expr) => {{
let mut doc = $crate::Doc::new();
doc.set_pk($pk)?;
::std::result::Result::Ok::<_, $crate::Error>(doc)
}};
($pk:expr, $($setter:expr),* $(,)?) => {{
let mut doc = $crate::Doc::new();
doc.set_pk($pk)?;
$($setter(&mut doc)?;)*
::std::result::Result::Ok::<_, $crate::Error>(doc)
}};
}
pub mod field {
use crate::doc::Doc;
use crate::error::Result;
pub fn vector<'a>(
field: &'a str,
values: &'a [f32],
) -> impl FnOnce(&mut Doc) -> Result<()> + 'a {
move |doc| doc.set_vector(field, values)
}
pub fn string<'a>(field: &'a str, value: &'a str) -> impl FnOnce(&mut Doc) -> Result<()> + 'a {
move |doc| doc.set_string(field, value)
}
pub fn int64(field: &str, value: i64) -> impl FnOnce(&mut Doc) -> Result<()> + '_ {
move |doc| doc.set_int64(field, value)
}
pub fn float(field: &str, value: f32) -> impl FnOnce(&mut Doc) -> Result<()> + '_ {
move |doc| doc.set_float(field, value)
}
pub fn boolean(field: &str, value: bool) -> impl FnOnce(&mut Doc) -> Result<()> + '_ {
move |doc| doc.set_bool(field, value)
}
pub fn double(field: &str, value: f64) -> impl FnOnce(&mut Doc) -> Result<()> + '_ {
move |doc| doc.set_double(field, value)
}
pub fn int32(field: &str, value: i32) -> impl FnOnce(&mut Doc) -> Result<()> + '_ {
move |doc| doc.set_int32(field, value)
}
pub fn sparse_vector<'a>(
field: &'a str,
indices: &'a [u32],
values: &'a [f32],
) -> impl FnOnce(&mut Doc) -> Result<()> + 'a {
move |doc| doc.set_sparse_vector(field, indices, values)
}
}