tflite-c-rs 0.0.1

Safe Rust wrapper for the TensorFlow Lite C API via runtime dynamic loading (libloading) — no build-time TFLite link required.
Documentation
//! Loaded `TfLiteModel` handle.

use std::ffi::CString;
use std::path::Path;
use std::sync::Arc;

use crate::error::{Error, Result};
use crate::ffi::TfLiteModel;
use crate::library::TfLiteLibrary;

/// A TensorFlow Lite model loaded from a `.tflite` flatbuffer file.
///
/// The underlying `TfLiteModel*` is released when this value is dropped.
/// Cloning the [`Arc<TfLiteLibrary>`] is cheap and keeps the loaded shared
/// object alive for as long as any [`Model`] or interpreter still uses it.
pub struct Model {
    raw: *mut TfLiteModel,
    lib: Arc<TfLiteLibrary>,
}

// SAFETY: A `TfLiteModel` is read-only after construction and the upstream
// C API is documented as safe to share across threads. The wrapper itself
// is just a raw pointer plus an `Arc`, both of which we mark explicitly.
unsafe impl Send for Model {}
unsafe impl Sync for Model {}

impl Model {
    /// Load a `.tflite` flatbuffer from disk.
    ///
    /// Internally calls `TfLiteModelCreateFromFile`. Returns
    /// [`Error::ModelLoadFailed`] if the C API returns NULL (commonly: the
    /// file does not exist, is unreadable, or is not a valid TFLite model).
    pub fn from_file<P: AsRef<Path>>(path: P, lib: Arc<TfLiteLibrary>) -> Result<Self> {
        let path_ref = path.as_ref();
        let path_str = path_ref
            .to_str()
            .ok_or_else(|| Error::ModelLoadFailed { path: path_ref.to_path_buf() })?;
        let c_path = CString::new(path_str).map_err(Error::InvalidPath)?;

        // SAFETY: `c_path` lives for the duration of this call; the C API
        // copies the string contents it needs.
        let raw = unsafe { (lib.model_create_from_file)(c_path.as_ptr()) };
        if raw.is_null() {
            return Err(Error::ModelLoadFailed { path: path_ref.to_path_buf() });
        }
        Ok(Self { raw, lib })
    }

    /// Returns the raw `TfLiteModel*`. Mostly useful for advanced FFI scenarios.
    pub fn as_ptr(&self) -> *const TfLiteModel {
        self.raw
    }

    pub(crate) fn lib(&self) -> &Arc<TfLiteLibrary> {
        &self.lib
    }
}

impl Drop for Model {
    fn drop(&mut self) {
        // SAFETY: `raw` was allocated by `TfLiteModelCreateFromFile` and is
        // not aliased elsewhere — the interpreter borrows but does not take
        // ownership.
        unsafe {
            (self.lib.model_delete)(self.raw);
        }
    }
}