1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
//! Batch completion free functions. Phase R4 Agent B.
//!
//! Wraps the upstream [`blazen_uniffi::batch::complete_batch`] /
//! [`blazen_uniffi::batch::complete_batch_blocking`] functions in C-callable
//! form. Two execution modes:
//!
//! - [`blazen_complete_batch_blocking`] — synchronous, drives the future on
//! the cabi tokio runtime via `runtime().block_on(...)`.
//! - [`blazen_complete_batch`] — returns a `*mut BlazenFuture` immediately and
//! spawns the batch task onto the runtime. The caller observes completion
//! via `blazen_future_poll` / `blazen_future_wait` / `blazen_future_fd` and
//! then pops the typed result with [`blazen_future_take_batch_result`].
//!
//! ## Ownership conventions
//!
//! - `model` is BORROWED; the caller retains ownership of the
//! `BlazenCompletionModel*`. The inner `Arc<CompletionModel>` is cloned into
//! the task so the model handle can be freed independently of the spawned
//! batch.
//! - The `requests` array itself is BORROWED at the array level — the caller
//! frees the outer `BlazenCompletionRequest*` array after the cabi call
//! returns — but each `BlazenCompletionRequest*` element is CONSUMED. The
//! cabi reclaims each via `Box::from_raw`, moves the inner
//! `blazen_uniffi::llm::CompletionRequest` record out, and drops the empty
//! wrapper. Calling
//! [`crate::llm_records::blazen_completion_request_free`] on any element
//! passed to a batch call afterwards is a double-free.
//! - The result handle produced via either the blocking call or
//! [`blazen_future_take_batch_result`] is caller-owned and freed via
//! [`crate::batch_records::blazen_batch_result_free`].
//! - Error handles produced on the failure path are caller-owned and freed
//! via [`crate::error::blazen_error_free`].
use Arc;
use BatchResult as InnerBatchResult;
use BlazenError as InnerError;
use CompletionRequest as InnerCompletionRequest;
use crateBlazenBatchResult;
use crateBlazenError;
use crateBlazenFuture;
use crateBlazenCompletionModel;
use crateBlazenCompletionRequest;
use crateruntime;
// ---------------------------------------------------------------------------
// Local error helpers
//
// Mirror the pattern used in `llm.rs`, `agent.rs`, and `compute_factories.rs`
// rather than reaching for a shared helper — each cabi module stays
// self-contained.
// ---------------------------------------------------------------------------
/// Writes a caller-owned `BlazenError` into `out_err` if the slot is non-null
/// and returns `-1` so the caller can `return write_error(...)` in tail
/// position.
/// Builds + writes a `BlazenError::Internal { message }` into `out_err`.
// ---------------------------------------------------------------------------
// Request-array consumption helper
// ---------------------------------------------------------------------------
/// Drain the C `requests` array, taking ownership of each
/// `BlazenCompletionRequest*` element and moving the inner record out.
///
/// Returns `None` if `requests` is null while `count > 0`, or if any indexed
/// pointer is null. On the `None` path, every `BlazenCompletionRequest*`
/// element that was successfully reclaimed before the first null is dropped
/// (so callers don't leak prefix elements when a later element is invalid).
///
/// An empty array (`count == 0`) is valid and yields `Some(Vec::new())`; the
/// `requests` outer pointer is only required to be non-null when `count > 0`.
///
/// # Safety
///
/// When `count > 0`, `requests` must point to an array of exactly `count`
/// `BlazenCompletionRequest*` entries. Each entry must be null OR a pointer
/// previously produced by [`crate::llm_records::blazen_completion_request_new`]
/// (or equivalent `Box::into_raw` over a `BlazenCompletionRequest`), and
/// ownership of every non-null entry transfers to this function.
unsafe
// ---------------------------------------------------------------------------
// Public surface
// ---------------------------------------------------------------------------
/// Synchronously run a batch of completions on the cabi tokio runtime.
///
/// On success returns `0` and writes a fresh `BlazenBatchResult*` into
/// `*out_result`. On failure returns `-1` and writes a fresh `BlazenError*`
/// into `*out_err`. Both out-parameters may be null to discard the matching
/// side of the result (typically only meaningful on the error path during a
/// smoke test).
///
/// `max_concurrency` is a hard cap on in-flight requests; `0` means unlimited
/// (the upstream default — all dispatched in parallel).
///
/// **Each `BlazenCompletionRequest*` element of `requests` is consumed.** See
/// the module-level docs for the full ownership contract; calling
/// [`crate::llm_records::blazen_completion_request_free`] on any element
/// afterwards is a double-free.
///
/// # Safety
///
/// - `model` must be null OR a live `BlazenCompletionModel` produced by the
/// cabi surface.
/// - When `requests_count > 0`, `requests` must point to an array of exactly
/// `requests_count` `BlazenCompletionRequest*` entries; each entry must be
/// a live `BlazenCompletionRequest` produced by the cabi surface, and
/// ownership of every entry transfers to this function. When
/// `requests_count == 0`, `requests` may be null.
/// - `out_result` and `out_err` must each be null OR point to a writable slot
/// of the matching pointer type.
pub unsafe extern "C"
/// Spawn a batch of completions onto the cabi tokio runtime and return an
/// opaque future handle. Observe completion via `blazen_future_poll` /
/// `blazen_future_wait` / `blazen_future_fd`, then pop the typed result with
/// [`blazen_future_take_batch_result`]. Free the future with
/// `blazen_future_free`.
///
/// Returns null if `model` is null, or if `requests` is null when
/// `requests_count > 0`, or if any indexed `BlazenCompletionRequest*` element
/// is null. On every null-return path, ownership of any
/// `BlazenCompletionRequest*` elements that were already reclaimed is
/// dropped (no leaks).
///
/// **Each `BlazenCompletionRequest*` element of `requests` is consumed** on
/// the success path AND on the validation-failure path (so the caller is
/// always relieved of ownership of every successfully-passed element). See
/// the module-level docs for the full contract.
///
/// # Safety
///
/// Same as [`blazen_complete_batch_blocking`]: `model` must be null OR a live
/// `BlazenCompletionModel`; the `requests` array elements transfer ownership.
pub unsafe extern "C"
/// Pops the [`BlazenBatchResult`] out of a future produced by
/// [`blazen_complete_batch`].
///
/// Returns `0` on success (writes the result into `*out` when non-null) or
/// `-1` on failure (writes a fresh `BlazenError*` into `*err` when non-null).
/// Both out-parameters may be null to discard the corresponding side.
///
/// Calling this against a future produced by any other cabi entry point
/// (e.g. `blazen_completion_model_complete`) yields a `BlazenError::Internal`
/// with a `type mismatch` message — see `BlazenFuture::take_typed`.
///
/// # Safety
///
/// `fut` must be null OR a pointer previously produced by
/// [`blazen_complete_batch`] (and not yet freed, not concurrently freed from
/// another thread). `out` and `err` must each be null OR point to a writable
/// slot of the matching pointer type.
pub unsafe extern "C"