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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
use crateValue;
/// Frees a heap-allocated buffer previously returned from Rust.
///
/// # Parameters
/// - `ptr`: Pointer to the buffer to free.
///
/// # Safety
/// - `ptr` must be a pointer previously returned from Rust (e.g., a buffer from `yad_as_buffer` or `row_as_buffer`) or null.
/// - After calling this function, `ptr` must not be used again to avoid undefined behavior.
///
/// # Example
/// ```c
/// const uint8_t* buf = yad_as_buffer(yad);
/// // ... use the buffer ...
/// free_buffer((uint8_t*)buf);
/// ```
pub extern "C"
/// A C-compatible wrapper around a Rust `Vec<Value>`
///
/// This struct is intended to be used across FFI boundaries.
/// The layout is compatible with C (`#[repr(C)]`), and it exposes
/// a raw pointer, length, and capacity.
///
/// # Fields
/// - `ptr`: Pointer to the first element in the array. Can be null if empty.
/// - `len`: Number of valid elements in the array.
/// - `cap`: Allocated capacity of the array.
///
/// # Safety
/// Accessing `ptr` directly is unsafe. Always use the provided FFI functions
/// to manipulate the array safely.
/// Creates a new empty `CArray`.
///
/// # Returns
/// - A raw pointer to a heap-allocated `CArray`.
///
/// # Safety
/// - The returned pointer must eventually be freed using `free_c_array` to prevent memory leaks.
pub extern "C"
/// Inserts a `Value` into the `CArray` at the specified index.
///
/// # Parameters
/// - `arr`: Pointer to the `CArray`.
/// - `index`: The position to insert the value.
/// - `value`: Pointer to the `Value` to insert.
///
/// # Returns
/// - `true` if insertion succeeded.
/// - `false` if the array pointer or value pointer is null, or if the index is out of bounds.
///
/// # Safety
/// - Both `arr` and `value` must be valid, non-null pointers.
pub extern "C"
/// Pushes a new `Value` into a `CArray`.
///
/// # Parameters
/// - `arr`: A raw pointer to a mutable [`CArray`].
/// - `value`: A raw pointer to a heap-allocated [`Value`].
///
/// # Returns
/// - `true` if the operation succeeded.
/// - `false` if:
/// - Either pointer is null.
/// - The array has reached `isize::MAX` capacity (overflow safeguard).
///
/// # Behavior
/// - Takes ownership of the `value` pointer (frees the original `Box`).
/// - Converts the internal raw pointer of the `CArray` into a temporary [`Vec<Value>`].
/// - If the vector is at capacity, calls [`Vec::reserve`] to allocate more space.
/// - Pushes the new value into the vector.
/// - Updates the `ptr`, `len`, and `cap` fields of the `CArray` with the new vector state.
/// - Calls [`std::mem::forget`] to prevent the temporary `Vec` from freeing its buffer,
/// since ownership is transferred back to the `CArray`.
///
/// # Safety
/// - `arr` must be a valid, non-null pointer to a properly initialized `CArray`.
/// - `value` must be a valid, non-null pointer to a heap-allocated `Value`.
/// - After this call, the caller must not use the original `value` pointer again,
/// as its ownership has been transferred.
/// - Misuse can lead to undefined behavior, memory leaks, or double frees.
///
/// # Example (pseudo-usage in C/FFI)
/// ```c
/// CArray* arr = c_array_new();
/// Value* val = value_from_int(42);
/// bool ok = c_array_push(arr, val);
/// ```
pub extern "C"
/// Returns a heap-allocated clone of the `Value` stored in the `CArray` at `index`.
///
/// This function does **not** expose a direct pointer into the internal buffer. Instead,
/// it clones the element and returns ownership of a newly allocated `Value*` to the caller.
/// The caller is responsible for destroying that `Value*` with this library's designated
/// deallocator (e.g., `value_free`).
///
/// # Parameters
/// - `arr`: Pointer to a valid `CArray` whose internal buffer was created by this library.
/// - `index`: Zero-based index of the element to retrieve.
///
/// # Returns
/// - On success: a non-null `*mut Value` pointing to a freshly allocated clone of the element.
/// - On failure (null `arr`, out-of-bounds index, or panic during clone): `null_mut()`.
///
/// # Complexity
/// - O(1) for indexing, plus the cost of `Value::clone()`.
///
/// # Ownership & Lifetime
/// - The returned pointer owns its storage and must be freed by the caller using the
/// appropriate destructor from this library.
/// - This function does **not** transfer or modify ownership of the underlying `CArray` buffer.
///
/// # Safety
/// - `arr` must be a non-null pointer to a well-formed `CArray` with fields (`ptr`, `len`, `cap`)
/// describing a buffer allocated by the same Rust allocator.
/// - No other thread may mutate the `CArray` concurrently while this function executes.
/// - `Value` must implement `Clone` and cloning must not unwind across the FFI boundary.
/// - Invoking this function with an invalid `arr` or corrupted invariants constitutes undefined behavior.
///
/// # Notes
/// - The implementation now avoids temporary ownership of the buffer by using
/// `slice::from_raw_parts` instead of `Vec::from_raw_parts`.
/// - The body is wrapped in `catch_unwind` to prevent panics from propagating
/// across the FFI boundary.
pub extern "C"
/// Removes a value from the `CArray` at the specified index.
///
/// # Parameters
/// - `arr`: Pointer to the `CArray`.
/// - `index`: Index of the element to remove.
/// - `out`: Optional pointer to a `Value` where the removed element will be written.
///
/// # Returns
/// - `true` if removal succeeded.
/// - `false` if the index is out of bounds or `arr` is null.
///
/// # Safety
/// - `arr` must be a valid pointer.
/// - `out` can be null if the removed value does not need to be retrieved.
pub extern "C"
/// Returns the number of elements in the `CArray`.
///
/// # Parameters
/// - `arr`: Pointer to the `CArray`.
///
/// # Returns
/// - Length of the array, or 0 if the pointer is null.
pub extern "C"
/// Returns the capacity of the `CArray`.
///
/// # Parameters
/// - `arr`: Pointer to the `CArray`.
///
/// # Returns
/// - Capacity of the array, or 0 if the pointer is null.
pub extern "C"
/// Returns a raw pointer to the internal buffer of the CArray and its length.
///
/// # Parameters
/// - `arr`: Pointer to a valid CArray.
///
/// # Returns
/// - Tuple `(ptr, len)` as `(Value**, usize)`; returns `(null_mut(), 0)` if `arr` is null.
///
/// # Safety
/// - The caller must not mutate the returned pointers.
/// - The caller does not own the Values; they are still owned by the CArray.
/// - Thread-safety: the CArray must not be mutated concurrently.
pub extern "C"
/// Frees a `CArray` and its underlying memory.
///
/// # Parameters
/// - `arr`: Pointer to the `CArray` to free.
///
/// # Safety
/// - `arr` must be a pointer previously returned by `c_array_new`.
/// - After calling this function, `arr` must not be used again.
pub extern "C"