Skip to main content

foundation_models/ffi/
mod.rs

1//! Raw FFI declarations matching the Swift `@_cdecl` exports in
2//! `swift-bridge/Sources/FoundationModelsBridge`.
3//!
4//! These are intentionally opaque (`*mut c_void`) and unsafe; safe wrappers
5//! live in the parent modules.
6
7use core::ffi::{c_char, c_void};
8
9/// Plain-old-data carrier for [`crate::generation::GenerationOptions`].
10#[derive(Copy, Clone, Debug)]
11pub struct FFIGenerationOptions {
12    pub temperature: f64,
13    pub maximum_response_tokens: i32,
14    pub sampling_mode: i32,
15    pub top_k: i32,
16    pub top_p: f64,
17    pub random_seed: u64,
18    pub has_random_seed: bool,
19}
20
21pub type FmRespondCallback = unsafe extern "C" fn(
22    context: *mut c_void,
23    response: *mut c_char,
24    error: *mut c_char,
25    status: i32,
26);
27
28/// 3-argument async callback used by the `async_api` thunks in `Async.swift`.
29///
30/// - `result`  Non-null on success; semantics are thunk-specific (opaque pointer or C string).
31/// - `error`   Non-null null-terminated UTF-8 error message on failure.
32/// - `ctx`     Opaque context pointer from `AsyncCompletion::create()`.
33pub type FmAsyncCallback =
34    unsafe extern "C" fn(result: *mut c_void, error: *const c_char, ctx: *mut c_void);
35
36pub type FmStreamCallback =
37    unsafe extern "C" fn(context: *mut c_void, chunk: *mut c_char, done: bool, status: i32);
38
39pub type FmToolCallback = unsafe extern "C" fn(
40    context: *mut c_void,
41    tool_name: *const c_char,
42    arguments_json: *const c_char,
43    output_json_out: *mut *mut c_char,
44    error_out: *mut *mut c_char,
45) -> i32;
46
47extern "C" {
48    pub fn fm_string_dup(s: *const c_char) -> *mut c_char;
49    pub fn fm_string_free(s: *mut c_char);
50    pub fn fm_bytes_free(ptr: *mut c_void);
51    pub fn fm_object_release(ptr: *mut c_void);
52
53    pub fn fm_system_model_is_available() -> bool;
54    pub fn fm_system_model_availability_code() -> i32;
55    pub fn fm_system_model_create_default() -> *mut c_void;
56    pub fn fm_system_model_create(
57        use_case: i32,
58        guardrails: i32,
59        error_out: *mut *mut c_char,
60    ) -> *mut c_void;
61    pub fn fm_system_model_create_with_adapter(
62        adapter: *mut c_void,
63        guardrails: i32,
64        error_out: *mut *mut c_char,
65    ) -> *mut c_void;
66    pub fn fm_system_model_availability_code_for(model: *mut c_void) -> i32;
67    pub fn fm_system_model_supported_languages_json(model: *mut c_void) -> *mut c_char;
68    pub fn fm_system_model_supports_locale(
69        model: *mut c_void,
70        locale_identifier: *const c_char,
71    ) -> bool;
72    pub fn fm_system_model_token_count_prompt_async(
73        model: *mut c_void,
74        prompt: *const c_char,
75        ctx: *mut c_void,
76        cb: FmAsyncCallback,
77    );
78
79    pub fn fm_adapter_create_from_file(
80        file_path: *const c_char,
81        error_out: *mut *mut c_char,
82    ) -> *mut c_void;
83    pub fn fm_adapter_create_from_name(
84        name: *const c_char,
85        error_out: *mut *mut c_char,
86    ) -> *mut c_void;
87    pub fn fm_adapter_compile(
88        adapter: *mut c_void,
89        context: *mut c_void,
90        callback: FmRespondCallback,
91    );
92    pub fn fm_adapter_compatible_identifiers_json(name: *const c_char) -> *mut c_char;
93    pub fn fm_adapter_remove_obsolete(error_out: *mut *mut c_char) -> i32;
94    pub fn fm_adapter_metadata_json(adapter: *mut c_void) -> *mut c_char;
95
96    pub fn fm_session_create(instructions: *const c_char) -> *mut c_void;
97    pub fn fm_session_create_ex(
98        model: *mut c_void,
99        instructions_json: *const c_char,
100        transcript_json: *const c_char,
101        tools_json: *const c_char,
102        tool_context: *mut c_void,
103        tool_callback: Option<FmToolCallback>,
104        error_out: *mut *mut c_char,
105    ) -> *mut c_void;
106
107    pub fn fm_session_respond(
108        session: *mut c_void,
109        prompt: *const c_char,
110        temperature: f64,
111        max_tokens: i32,
112        sampling_mode: i32,
113        top_k: i32,
114        top_p: f64,
115        context: *mut c_void,
116        callback: FmRespondCallback,
117    );
118    pub fn fm_session_respond_request_json(
119        session: *mut c_void,
120        request_json: *const c_char,
121        context: *mut c_void,
122        callback: FmRespondCallback,
123    );
124
125    pub fn fm_session_respond_with_schema(
126        session: *mut c_void,
127        prompt: *const c_char,
128        schema_json: *const c_char,
129        include_schema_in_prompt: bool,
130        temperature: f64,
131        max_tokens: i32,
132        sampling_mode: i32,
133        top_k: i32,
134        top_p: f64,
135        context: *mut c_void,
136        callback: FmRespondCallback,
137    );
138
139    pub fn fm_session_stream_response(
140        session: *mut c_void,
141        prompt: *const c_char,
142        temperature: f64,
143        max_tokens: i32,
144        sampling_mode: i32,
145        top_k: i32,
146        top_p: f64,
147        context: *mut c_void,
148        callback: FmStreamCallback,
149    );
150    pub fn fm_session_stream_request_json(
151        session: *mut c_void,
152        request_json: *const c_char,
153        context: *mut c_void,
154        callback: FmStreamCallback,
155    );
156
157    pub fn fm_session_prewarm(session: *mut c_void);
158    pub fn fm_session_prewarm_prompt_json(
159        session: *mut c_void,
160        prompt_json: *const c_char,
161        error_out: *mut *mut c_char,
162    ) -> i32;
163    pub fn fm_session_is_responding(session: *mut c_void) -> bool;
164    pub fn fm_session_transcript_json(session: *mut c_void) -> *mut c_char;
165    pub fn fm_session_log_feedback(
166        session: *mut c_void,
167        sentiment: i32,
168        description: *const c_char,
169    );
170    pub fn fm_session_log_feedback_attachment_json(
171        session: *mut c_void,
172        request_json: *const c_char,
173        length_out: *mut usize,
174        error_out: *mut *mut c_char,
175    ) -> *mut c_void;
176
177    pub fn fm_generation_schema_compile_json(
178        request_json: *const c_char,
179        context: *mut c_void,
180        callback: FmRespondCallback,
181    );
182    pub fn fm_generation_schema_validate_json(
183        schema_json: *const c_char,
184        error_out: *mut *mut c_char,
185    ) -> i32;
186    pub fn fm_generation_schema_create_typed_json(
187        request_json: *const c_char,
188        context: *mut c_void,
189        callback: FmRespondCallback,
190    );
191
192    pub fn fm_generation_id_create(
193        output_out: *mut *mut c_char,
194        error_out: *mut *mut c_char,
195    ) -> i32;
196    pub fn fm_decimal_to_generated_content_json(
197        decimal_string: *const c_char,
198        output_out: *mut *mut c_char,
199        error_out: *mut *mut c_char,
200    ) -> i32;
201    pub fn fm_decimal_from_generated_content_json(
202        generated_content_json: *const c_char,
203        output_out: *mut *mut c_char,
204        error_out: *mut *mut c_char,
205    ) -> i32;
206    pub fn fm_refusal_explanation_json(
207        refusal_token: *const c_char,
208        context: *mut c_void,
209        callback: FmRespondCallback,
210    );
211    pub fn fm_refusal_explanation_from_transcript_json(
212        transcript_json: *const c_char,
213        context: *mut c_void,
214        callback: FmRespondCallback,
215    );
216    pub fn fm_refusal_explanation_stream(
217        refusal_token: *const c_char,
218        context: *mut c_void,
219        callback: FmStreamCallback,
220    );
221    pub fn fm_refusal_explanation_stream_from_transcript_json(
222        transcript_json: *const c_char,
223        context: *mut c_void,
224        callback: FmStreamCallback,
225    );
226
227    // ── Async thunks (Async.swift) ─────────────────────────────────────────
228
229    /// Async version of `Adapter(name:)`.
230    ///
231    /// Calls `cb(retainedAdapterBoxPtr, nil, ctx)` on success or
232    /// `cb(nil, errorCStr, ctx)` on failure.
233    /// Free the result with `fm_object_release`; errors are stack-owned by the callback.
234    pub fn fm_adapter_create_from_name_async(
235        name: *const c_char,
236        ctx: *mut c_void,
237        cb: FmAsyncCallback,
238    );
239
240    /// Async version of `Adapter.compatibleAdapterIdentifiers(name:)`.
241    ///
242    /// Calls `cb(strdupJsonPtr, nil, ctx)` on success where the pointer is a
243    /// heap-allocated UTF-8 JSON array.  Free it with `fm_string_free`.
244    /// On failure calls `cb(nil, errorCStr, ctx)`.
245    pub fn fm_adapter_compatibility_async(
246        name: *const c_char,
247        ctx: *mut c_void,
248        cb: FmAsyncCallback,
249    );
250}
251
252/// Status codes mirrored 1:1 from the `FM_*` constants in Swift.
253pub mod status {
254    pub const OK: i32 = 0;
255    pub const INVALID_ARGUMENT: i32 = -1;
256    pub const MODEL_UNAVAILABLE: i32 = -2;
257    pub const CANCELLED: i32 = -3;
258    pub const GUARDRAIL_VIOLATION: i32 = -4;
259    pub const CONTEXT_WINDOW_EXCEEDED: i32 = -5;
260    pub const UNSUPPORTED_LANGUAGE: i32 = -6;
261    pub const ASSETS_UNAVAILABLE: i32 = -7;
262    pub const RATE_LIMITED: i32 = -8;
263    pub const DECODING_FAILURE: i32 = -9;
264    pub const REFUSAL: i32 = -10;
265    pub const CONCURRENT_REQUESTS: i32 = -11;
266    pub const UNSUPPORTED_GUIDE: i32 = -12;
267    pub const TOOL_CALL_FAILED: i32 = -13;
268    pub const ADAPTER_INVALID_ASSET: i32 = -14;
269    pub const ADAPTER_INVALID_NAME: i32 = -15;
270    pub const ADAPTER_COMPATIBLE_NOT_FOUND: i32 = -16;
271    pub const UNKNOWN: i32 = -99;
272}