use std::os::raw::c_int;
use std::sync::Arc;
use crate::error::{Error, Result};
use crate::ffi::{TfLiteInterpreter, TfLiteInterpreterOptions, TfLiteStatus};
use crate::library::{ExternalDelegate, TfLiteLibrary};
use crate::model::Model;
use crate::tensor::{Tensor, TensorMut};
pub struct InterpreterOptions {
raw: *mut TfLiteInterpreterOptions,
lib: Arc<TfLiteLibrary>,
}
unsafe impl Send for InterpreterOptions {}
unsafe impl Sync for InterpreterOptions {}
impl InterpreterOptions {
pub fn new(lib: Arc<TfLiteLibrary>) -> Self {
let raw = unsafe { (lib.options_create)() };
Self { raw, lib }
}
pub fn num_threads(&mut self, n: i32) -> &mut Self {
unsafe {
(self.lib.options_set_num_threads)(self.raw, n as c_int);
}
self
}
pub fn add_delegate(&mut self, delegate: ExternalDelegate) -> &mut Self {
unsafe {
(self.lib.options_add_delegate)(self.raw, delegate.as_ptr());
}
std::mem::forget(delegate);
self
}
pub fn as_ptr(&self) -> *const TfLiteInterpreterOptions {
self.raw
}
}
impl Drop for InterpreterOptions {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe {
(self.lib.options_delete)(self.raw);
}
}
}
}
pub struct Interpreter {
raw: *mut TfLiteInterpreter,
lib: Arc<TfLiteLibrary>,
_model: Model,
_options: InterpreterOptions,
}
unsafe impl Send for Interpreter {}
unsafe impl Sync for Interpreter {}
impl Interpreter {
pub fn new(model: Model, options: InterpreterOptions) -> Result<Self> {
let lib = model.lib().clone();
let raw = unsafe { (lib.interpreter_create)(model.as_ptr(), options.as_ptr()) };
if raw.is_null() {
return Err(Error::InterpreterCreateFailed);
}
let status = unsafe { (lib.interpreter_allocate_tensors)(raw) };
if status != TfLiteStatus::Ok {
unsafe {
(lib.interpreter_delete)(raw);
}
return Err(Error::AllocateTensorsFailed);
}
Ok(Self { raw, lib, _model: model, _options: options })
}
pub fn input_count(&self) -> usize {
unsafe { (self.lib.interpreter_get_input_tensor_count)(self.raw) as usize }
}
pub fn output_count(&self) -> usize {
unsafe { (self.lib.interpreter_get_output_tensor_count)(self.raw) as usize }
}
pub fn input(&self, index: usize) -> Result<Tensor<'_>> {
let count = self.input_count();
if index >= count {
return Err(Error::TensorIndexOutOfBounds { index, count });
}
unsafe {
let raw = (self.lib.interpreter_get_input_tensor)(self.raw, index as c_int);
if raw.is_null() {
return Err(Error::NullTensor);
}
Ok(Tensor::from_raw(raw as *const _, self.lib.clone()))
}
}
pub fn input_mut(&mut self, index: usize) -> Result<TensorMut<'_>> {
let count = self.input_count();
if index >= count {
return Err(Error::TensorIndexOutOfBounds { index, count });
}
unsafe {
let raw = (self.lib.interpreter_get_input_tensor)(self.raw, index as c_int);
if raw.is_null() {
return Err(Error::NullTensor);
}
Ok(TensorMut::from_raw(raw, self.lib.clone()))
}
}
pub fn output(&self, index: usize) -> Result<Tensor<'_>> {
let count = self.output_count();
if index >= count {
return Err(Error::TensorIndexOutOfBounds { index, count });
}
unsafe {
let raw = (self.lib.interpreter_get_output_tensor)(self.raw, index as c_int);
if raw.is_null() {
return Err(Error::NullTensor);
}
Ok(Tensor::from_raw(raw, self.lib.clone()))
}
}
pub fn invoke(&mut self) -> Result<()> {
let status = unsafe { (self.lib.interpreter_invoke)(self.raw) };
if status == TfLiteStatus::Ok {
Ok(())
} else {
Err(Error::InvokeFailed { status })
}
}
}
impl Drop for Interpreter {
fn drop(&mut self) {
unsafe {
(self.lib.interpreter_delete)(self.raw);
}
}
}