use crate::error::*;
use aic_sdk_sys::*;
use std::{
ffi::{CStr, CString},
marker::PhantomData,
path::Path,
ptr,
};
pub struct Model<'a> {
ptr: *mut AicModel,
marker: PhantomData<&'a [u8]>,
}
impl<'a> Model<'a> {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Model<'static>, AicError> {
let mut model_ptr: *mut AicModel = ptr::null_mut();
let c_path = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap();
let error_code = unsafe { aic_model_create_from_file(&mut model_ptr, c_path.as_ptr()) };
handle_error(error_code)?;
assert!(
!model_ptr.is_null(),
"C library returned success but null pointer"
);
Ok(Model {
ptr: model_ptr,
marker: PhantomData,
})
}
pub fn from_buffer(buffer: &'a [u8]) -> Result<Self, AicError> {
let mut model_ptr: *mut AicModel = ptr::null_mut();
let error_code =
unsafe { aic_model_create_from_buffer(&mut model_ptr, buffer.as_ptr(), buffer.len()) };
handle_error(error_code)?;
assert!(
!model_ptr.is_null(),
"C library returned success but null pointer"
);
Ok(Model {
ptr: model_ptr,
marker: PhantomData,
})
}
pub fn id(&self) -> &str {
let id_ptr = unsafe { aic_model_get_id(self.as_const_ptr()) };
if id_ptr.is_null() {
return "unknown";
}
unsafe { CStr::from_ptr(id_ptr).to_str().unwrap_or("unknown") }
}
pub fn optimal_sample_rate(&self) -> u32 {
let mut sample_rate: u32 = 0;
let error_code =
unsafe { aic_model_get_optimal_sample_rate(self.as_const_ptr(), &mut sample_rate) };
assert_success(
error_code,
"`aic_model_get_optimal_sample_rate` failed. This is a bug, please open an issue on GitHub for further investigation.",
);
sample_rate
}
pub fn optimal_num_frames(&self, sample_rate: u32) -> usize {
let mut num_frames: usize = 0;
let error_code = unsafe {
aic_model_get_optimal_num_frames(self.as_const_ptr(), sample_rate, &mut num_frames)
};
assert_success(
error_code,
"`aic_model_get_optimal_num_frames` failed. This is a bug, please open an issue on GitHub for further investigation.",
);
num_frames
}
#[cfg(feature = "download-model")]
pub fn download<P: AsRef<Path>>(
model_id: &str,
download_dir: P,
) -> Result<std::path::PathBuf, AicError> {
let compatible_version = crate::get_compatible_model_version();
crate::download::download(model_id, compatible_version, download_dir)
.map_err(|err| AicError::ModelDownload(err.to_string()))
}
pub(crate) fn as_const_ptr(&self) -> *const AicModel {
self.ptr as *const AicModel
}
}
impl<'a> Drop for Model<'a> {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { aic_model_destroy(self.ptr) };
}
}
}
unsafe impl<'a> Send for Model<'a> {}
unsafe impl<'a> Sync for Model<'a> {}
#[macro_export]
macro_rules! include_model {
($path:expr) => {{
#[repr(C, align(64))]
struct __Aligned<T: ?Sized>(T);
const __DATA: &'static __Aligned<[u8; include_bytes!($path).len()]> =
&__Aligned(*include_bytes!($path));
&__DATA.0
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn include_model_aligns_to_64_bytes() {
let data = include_model!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"));
let ptr = data.as_ptr() as usize;
assert!(
ptr.is_multiple_of(64),
"include_model should align data to 64 bytes"
);
}
#[test]
fn model_is_send_and_sync() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<Model>();
assert_sync::<Model>();
}
}
#[doc(hidden)]
mod _compile_fail_tests {
}