tenferro_capi/
lib.rs

1//! C-API (FFI) for tenferro.
2//!
3//! Exposes tensor lifecycle, einsum, SVD (including AD rules), and DLPack
4//! interop to host languages such as Julia, Python (JAX, PyTorch), and C/C++.
5//!
6//! # Design principles
7//!
8//! - **Opaque pointers**: `TfeTensorF64` is an opaque handle wrapping
9//!   `Tensor<f64>`. Host languages never see Rust internals.
10//! - **Status codes**: Every function takes a `*mut tfe_status_t` as its
11//!   last argument. Rust panics are caught with `catch_unwind` and
12//!   converted to `TFE_INTERNAL_ERROR`.
13//! - **Stateless AD rules**: Only `rrule` (VJP) and `frule` (JVP) are
14//!   exposed. The AD tape / `TrackedValue` / `DualValue` are Rust-internal
15//!   and **not** exposed via FFI.
16//! - **f64 only** in this POC phase. All functions carry the `_f64` suffix.
17//! - **DLPack interop**: Zero-copy tensor exchange via [`DLManagedTensorVersioned`].
18//! - **Copy semantics** for convenience functions: `tfe_tensor_f64_from_data`
19//!   copies the caller's data into a Rust-owned buffer.
20//!
21//! # Header generation
22//!
23//! ```text
24//! cbindgen --config cbindgen.toml --crate tenferro-capi --output tenferro.h
25//! ```
26//!
27//! # Examples
28//!
29//! ```c
30//! tfe_status_t status;
31//! size_t shape[] = {3, 4};
32//! double data[12] = { /* ... */ };
33//! tfe_tensor_f64 *a = tfe_tensor_f64_from_data(data, 12, shape, 2, &status);
34//! const tfe_tensor_f64 *ops[] = {a, a};
35//! tfe_tensor_f64 *c = tfe_einsum_f64("ij,jk->ik", ops, 2, &status);
36//! tfe_tensor_f64_release(c);
37//! tfe_tensor_f64_release(a);
38//! ```
39
40#![allow(clippy::missing_safety_doc)]
41#![allow(non_camel_case_types)]
42
43mod dlpack;
44mod einsum_api;
45mod ffi_utils;
46mod handle;
47mod status;
48mod svd_api;
49mod tensor_api;
50
51pub use dlpack::{
52    tfe_tensor_f64_from_dlpack, tfe_tensor_f64_to_dlpack, DLDataType, DLDevice,
53    DLManagedTensorVersioned, DLPackVersion, DLTensor, DLPACK_FLAG_BITMASK_IS_COPIED,
54    DLPACK_FLAG_BITMASK_READ_ONLY, KDLCOMPLEX, KDLCPU, KDLCUDA, KDLCUDA_HOST, KDLCUDA_MANAGED,
55    KDLFLOAT, KDLINT, KDLROCM, KDLROCM_HOST,
56};
57pub use einsum_api::{tfe_einsum_f64, tfe_einsum_frule_f64, tfe_einsum_rrule_f64};
58pub use handle::TfeTensorF64;
59pub use status::{
60    tfe_last_error_message, tfe_status_t, TFE_BUFFER_TOO_SMALL, TFE_INTERNAL_ERROR,
61    TFE_INVALID_ARGUMENT, TFE_SHAPE_MISMATCH, TFE_SUCCESS,
62};
63pub use svd_api::{tfe_svd_f64, tfe_svd_frule_f64, tfe_svd_rrule_f64};
64pub use tensor_api::{
65    tfe_tensor_f64_clone, tfe_tensor_f64_data, tfe_tensor_f64_from_data, tfe_tensor_f64_len,
66    tfe_tensor_f64_ndim, tfe_tensor_f64_release, tfe_tensor_f64_shape, tfe_tensor_f64_zeros,
67};
68
69#[cfg(test)]
70pub(crate) use handle::{handle_to_ref, tensor_to_handle};
71
72#[cfg(test)]
73mod tests;