Skip to main content

latexsnipper_runtime_plugin_api/
abi.rs

1//! Frozen version 1 C ABI.
2//!
3//! Every pointer is borrowed only for the documented call unless ownership is
4//! explicitly represented by `LatexSnipperOwnedTensorListV1::owner`.
5
6use std::ffi::c_void;
7
8pub const LATEXSNIPPER_RUNTIME_PLUGIN_ABI_V1: u32 = 1;
9pub const LATEXSNIPPER_RUNTIME_PLUGIN_ENTRY_V1: &[u8] = b"latexsnipper_runtime_plugin_entry_v1\0";
10
11pub const LS_RUNTIME_OK: i32 = 0;
12pub const LS_RUNTIME_ERROR: i32 = -1;
13
14pub const LS_DTYPE_FLOAT32: i32 = 0;
15pub const LS_DTYPE_FLOAT16: i32 = 1;
16pub const LS_DTYPE_INT64: i32 = 2;
17pub const LS_DTYPE_INT32: i32 = 3;
18pub const LS_DTYPE_UINT8: i32 = 4;
19pub const LS_DTYPE_BOOL: i32 = 5;
20
21pub const LS_DEVICE_AUTO: i32 = 0;
22pub const LS_DEVICE_CPU: i32 = 1;
23pub const LS_DEVICE_GPU: i32 = 2;
24pub const LS_DEVICE_NPU: i32 = 3;
25
26#[repr(C)]
27#[derive(Debug, Clone, Copy)]
28pub struct LatexSnipperBytesV1 {
29    pub data: *const u8,
30    pub len: usize,
31}
32
33impl LatexSnipperBytesV1 {
34    pub const fn empty() -> Self {
35        Self {
36            data: std::ptr::null(),
37            len: 0,
38        }
39    }
40
41    pub fn from_slice(bytes: &[u8]) -> Self {
42        Self {
43            data: bytes.as_ptr(),
44            len: bytes.len(),
45        }
46    }
47}
48
49#[repr(C)]
50#[derive(Debug, Clone, Copy)]
51pub struct LatexSnipperTensorViewV1 {
52    pub name: LatexSnipperBytesV1,
53    pub dtype: i32,
54    pub shape: *const i64,
55    pub rank: usize,
56    pub data: *const c_void,
57    pub byte_len: usize,
58}
59
60#[repr(C)]
61#[derive(Debug, Clone, Copy)]
62pub struct LatexSnipperArtifactV1 {
63    pub role: LatexSnipperBytesV1,
64    pub path: LatexSnipperBytesV1,
65}
66
67#[repr(C)]
68#[derive(Debug, Clone, Copy)]
69pub struct LatexSnipperSessionCreateRequestV1 {
70    pub artifacts: *const LatexSnipperArtifactV1,
71    pub artifact_count: usize,
72    pub artifact_options_json: LatexSnipperBytesV1,
73    pub runtime_options_json: LatexSnipperBytesV1,
74}
75
76#[repr(C)]
77#[derive(Debug, Clone, Copy)]
78pub struct LatexSnipperSessionV1 {
79    pub handle: *mut c_void,
80    /// UTF-8 JSON encoding of `latexsnipper_runtime::SessionMetadata`.
81    /// Owned by the session and valid until `destroy_session`.
82    pub metadata_json: LatexSnipperBytesV1,
83}
84
85impl LatexSnipperSessionV1 {
86    pub const fn empty() -> Self {
87        Self {
88            handle: std::ptr::null_mut(),
89            metadata_json: LatexSnipperBytesV1::empty(),
90        }
91    }
92}
93
94#[repr(C)]
95#[derive(Debug, Clone, Copy)]
96pub struct LatexSnipperRunRequestV1 {
97    pub has_method: u8,
98    pub method: LatexSnipperBytesV1,
99    pub inputs: *const LatexSnipperTensorViewV1,
100    pub input_count: usize,
101    pub has_requested_outputs: u8,
102    pub requested_outputs: *const LatexSnipperBytesV1,
103    pub requested_output_count: usize,
104}
105
106#[repr(C)]
107#[derive(Debug, Clone, Copy)]
108pub struct LatexSnipperOwnedTensorListV1 {
109    /// Plugin-defined allocation token. A non-null value transfers ownership
110    /// to the host even when `tensor_count == 0`.
111    pub owner: *mut c_void,
112    pub tensors: *const LatexSnipperTensorViewV1,
113    pub tensor_count: usize,
114}
115
116impl LatexSnipperOwnedTensorListV1 {
117    pub const fn empty() -> Self {
118        Self {
119            owner: std::ptr::null_mut(),
120            tensors: std::ptr::null(),
121            tensor_count: 0,
122        }
123    }
124
125    pub const fn owns_allocation(self) -> bool {
126        !self.owner.is_null() || !self.tensors.is_null() || self.tensor_count != 0
127    }
128}
129
130#[repr(C)]
131#[derive(Debug, Clone, Copy)]
132pub struct LatexSnipperRuntimeDeviceV1 {
133    pub name: LatexSnipperBytesV1,
134    pub kind: i32,
135    pub has_memory_bytes: u8,
136    pub memory_bytes: u64,
137}
138
139// SAFETY: Probe device records are immutable borrowed descriptors whose byte
140// views must remain live until the next plugin call.
141unsafe impl Sync for LatexSnipperRuntimeDeviceV1 {}
142
143#[repr(C)]
144#[derive(Debug, Clone, Copy)]
145pub struct LatexSnipperRuntimeProbeV1 {
146    pub available: u8,
147    pub version: LatexSnipperBytesV1,
148    pub reason_unavailable: LatexSnipperBytesV1,
149    pub devices: *const LatexSnipperRuntimeDeviceV1,
150    pub device_count: usize,
151    /// UTF-8 JSON encoding of `RuntimeCapabilities`.
152    pub capabilities_json: LatexSnipperBytesV1,
153}
154
155impl LatexSnipperRuntimeProbeV1 {
156    pub const fn empty() -> Self {
157        Self {
158            available: 0,
159            version: LatexSnipperBytesV1::empty(),
160            reason_unavailable: LatexSnipperBytesV1::empty(),
161            devices: std::ptr::null(),
162            device_count: 0,
163            capabilities_json: LatexSnipperBytesV1::empty(),
164        }
165    }
166}
167
168pub type RuntimeProbeV1 = unsafe extern "C" fn(output: *mut LatexSnipperRuntimeProbeV1) -> i32;
169pub type RuntimeCreateSessionV1 = unsafe extern "C" fn(
170    request: *const LatexSnipperSessionCreateRequestV1,
171    output: *mut LatexSnipperSessionV1,
172) -> i32;
173pub type RuntimeDestroySessionV1 = unsafe extern "C" fn(session: *mut c_void);
174pub type RuntimeRunV1 = unsafe extern "C" fn(
175    session: *mut c_void,
176    request: *const LatexSnipperRunRequestV1,
177    output: *mut LatexSnipperOwnedTensorListV1,
178) -> i32;
179pub type RuntimeFreeOutputV1 =
180    unsafe extern "C" fn(session: *mut c_void, output: *mut LatexSnipperOwnedTensorListV1);
181pub type RuntimeLastErrorV1 = unsafe extern "C" fn() -> LatexSnipperBytesV1;
182
183#[repr(C)]
184#[derive(Clone, Copy)]
185pub struct LatexSnipperRuntimePluginV1 {
186    pub struct_size: usize,
187    pub abi_version: u32,
188    pub runtime_id: LatexSnipperBytesV1,
189    pub plugin_version: LatexSnipperBytesV1,
190    pub probe: Option<RuntimeProbeV1>,
191    pub create_session: Option<RuntimeCreateSessionV1>,
192    pub destroy_session: Option<RuntimeDestroySessionV1>,
193    pub run: Option<RuntimeRunV1>,
194    pub free_output: Option<RuntimeFreeOutputV1>,
195    pub last_error: Option<RuntimeLastErrorV1>,
196}
197
198// SAFETY: A v1 function table is immutable process-lifetime data. The byte
199// views must point to immutable process-lifetime identity strings.
200unsafe impl Sync for LatexSnipperRuntimePluginV1 {}
201
202pub type RuntimePluginEntryV1 = unsafe extern "C" fn() -> *const LatexSnipperRuntimePluginV1;
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    #[test]
209    fn abi_struct_layout_is_frozen_by_explicit_size_contract() {
210        assert!(
211            std::mem::size_of::<LatexSnipperRuntimePluginV1>() >= 10 * usize::BITS as usize / 8
212        );
213        assert_eq!(LATEXSNIPPER_RUNTIME_PLUGIN_ABI_V1, 1);
214    }
215}