#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::collections::HashMap;
use std::ffi::CStr;
use std::os::raw::c_char;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use crate::error::{ERR_GENERIC, ERR_INTERNAL_PANIC, ERR_INVALID_PATH, ERR_SUCCESS};
use super::schema::FeatureValue;
use super::{FeatureStore, FeatureStoreConfig};
static FS_REGISTRY: Lazy<Mutex<HashMap<String, FeatureStore>>> =
Lazy::new(|| Mutex::new(HashMap::new()));
#[no_mangle]
pub extern "C" fn SYNA_fs_new(path: *const c_char) -> i32 {
std::panic::catch_unwind(|| {
if path.is_null() {
return ERR_INVALID_PATH;
}
let c_str = unsafe { CStr::from_ptr(path) };
let path_str = match c_str.to_str() {
Ok(s) => s,
Err(_) => return ERR_INVALID_PATH,
};
let mut registry = FS_REGISTRY.lock();
if registry.contains_key(path_str) {
return ERR_SUCCESS;
}
let config = FeatureStoreConfig::default();
match FeatureStore::new(path_str, config) {
Ok(store) => {
registry.insert(path_str.to_string(), store);
ERR_SUCCESS
}
Err(_) => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_close(path: *const c_char) -> i32 {
std::panic::catch_unwind(|| {
if path.is_null() {
return ERR_INVALID_PATH;
}
let c_str = unsafe { CStr::from_ptr(path) };
let path_str = match c_str.to_str() {
Ok(s) => s,
Err(_) => return ERR_INVALID_PATH,
};
let mut registry = FS_REGISTRY.lock();
match registry.remove(path_str) {
Some(store) => match store.close() {
Ok(_) => ERR_SUCCESS,
Err(_) => ERR_GENERIC,
},
None => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_ingest_float(
path: *const c_char,
group: *const c_char,
entity_key: *const c_char,
feature: *const c_char,
value: f64,
event_ts: u64,
) -> i32 {
std::panic::catch_unwind(|| {
let path_str = match ptr_to_str(path) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let group_str = match ptr_to_str(group) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let entity_str = match ptr_to_str(entity_key) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let feature_str = match ptr_to_str(feature) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let mut registry = FS_REGISTRY.lock();
let store = match registry.get_mut(path_str) {
Some(s) => s,
None => return ERR_GENERIC,
};
match store.ingest(
group_str,
entity_str,
event_ts,
&[(feature_str, FeatureValue::Float64(value))],
) {
Ok(_) => ERR_SUCCESS,
Err(_) => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_ingest_int(
path: *const c_char,
group: *const c_char,
entity_key: *const c_char,
feature: *const c_char,
value: i64,
event_ts: u64,
) -> i32 {
std::panic::catch_unwind(|| {
let path_str = match ptr_to_str(path) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let group_str = match ptr_to_str(group) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let entity_str = match ptr_to_str(entity_key) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let feature_str = match ptr_to_str(feature) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let mut registry = FS_REGISTRY.lock();
let store = match registry.get_mut(path_str) {
Some(s) => s,
None => return ERR_GENERIC,
};
match store.ingest(
group_str,
entity_str,
event_ts,
&[(feature_str, FeatureValue::Int64(value))],
) {
Ok(_) => ERR_SUCCESS,
Err(_) => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_serve_float(
path: *const c_char,
group: *const c_char,
entity_key: *const c_char,
feature: *const c_char,
out: *mut f64,
) -> i32 {
std::panic::catch_unwind(|| {
if out.is_null() {
return ERR_INVALID_PATH;
}
let path_str = match ptr_to_str(path) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let group_str = match ptr_to_str(group) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let entity_str = match ptr_to_str(entity_key) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let feature_str = match ptr_to_str(feature) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let mut registry = FS_REGISTRY.lock();
let store = match registry.get_mut(path_str) {
Some(s) => s,
None => return ERR_GENERIC,
};
match store.serve(group_str, entity_str, &[feature_str]) {
Ok(vector) => {
if let Some((_, FeatureValue::Float64(v))) = vector.values.first() {
unsafe { *out = *v };
ERR_SUCCESS
} else {
ERR_GENERIC
}
}
Err(_) => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_get_at_version(
path: *const c_char,
group: *const c_char,
entity_key: *const c_char,
feature: *const c_char,
version: i64,
out: *mut f64,
) -> i32 {
std::panic::catch_unwind(|| {
if out.is_null() {
return ERR_INVALID_PATH;
}
let path_str = match ptr_to_str(path) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let group_str = match ptr_to_str(group) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let entity_str = match ptr_to_str(entity_key) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let feature_str = match ptr_to_str(feature) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let registry = FS_REGISTRY.lock();
let store = match registry.get(path_str) {
Some(s) => s,
None => return ERR_GENERIC,
};
match store.get_at_version(group_str, entity_str, feature_str, version) {
Some(FeatureValue::Float64(v)) => {
unsafe { *out = v };
ERR_SUCCESS
}
_ => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_get_at_timestamp(
path: *const c_char,
group: *const c_char,
entity_key: *const c_char,
feature: *const c_char,
timestamp: u64,
out: *mut f64,
) -> i32 {
std::panic::catch_unwind(|| {
if out.is_null() {
return ERR_INVALID_PATH;
}
let path_str = match ptr_to_str(path) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let group_str = match ptr_to_str(group) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let entity_str = match ptr_to_str(entity_key) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let feature_str = match ptr_to_str(feature) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let registry = FS_REGISTRY.lock();
let store = match registry.get(path_str) {
Some(s) => s,
None => return ERR_GENERIC,
};
match store.get_at_timestamp(group_str, entity_str, feature_str, timestamp) {
Some(FeatureValue::Float64(v)) => {
unsafe { *out = v };
ERR_SUCCESS
}
_ => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
#[no_mangle]
pub extern "C" fn SYNA_fs_flush(path: *const c_char) -> i32 {
std::panic::catch_unwind(|| {
let path_str = match ptr_to_str(path) {
Some(s) => s,
None => return ERR_INVALID_PATH,
};
let mut registry = FS_REGISTRY.lock();
let store = match registry.get_mut(path_str) {
Some(s) => s,
None => return ERR_GENERIC,
};
match store.flush() {
Ok(_) => ERR_SUCCESS,
Err(_) => ERR_GENERIC,
}
})
.unwrap_or(ERR_INTERNAL_PANIC)
}
fn ptr_to_str<'a>(ptr: *const c_char) -> Option<&'a str> {
if ptr.is_null() {
return None;
}
unsafe { CStr::from_ptr(ptr) }.to_str().ok()
}