libffi_sys/
lib.rs

1#![doc(html_root_url = "https://docs.rs/libffi-sys/4.0.0")]
2//! Low-level Rust bindings for [libffi](https://sourceware.org/libffi/)
3//!
4//! The C libffi library provides two main facilities: assembling calls
5//! to functions dynamically, and creating closures that can be called
6//! as ordinary C functions.
7//!
8//! This is a mostly undocumented wrapper, originally generated by bindgen then
9//! cleaned up manually, intended as the basis for higher-level bindings.
10//!
11//! See [the libffi crate](https://crates.io/crates/libffi/) for a
12//! higher-level API.
13//!
14//! # Usage
15//!
16//! `libffi-sys` can either build its own copy of the libffi C library [from
17//! github](https://github.com/libffi/libffi) or it can link against your
18//! system's C libffi. By default it builds its own because many systems ship
19//! with an old C libffi; this requires that you have a working make, C
20//! compiler, automake, and autoconf first. If your system libffi is recent
21//! enough (v3.2.1 as of October 2019), you can instead enable the `system`
22//! feature flag to use that.
23//!
24//! On Windows, it is not supported to link against a shared libffi library as
25//! it is generally not available. Automake and autoconf are not required when
26//! building for the `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`
27//! targets.
28//!
29//! If you want this crate to build a C libffi for you, add
30//!
31//! ```toml
32//! [dependencies]
33//! libffi-sys = "4.0.0"
34//! ```
35//!
36//! to your `Cargo.toml`. If you want to use your system C libffi, then
37//!
38//! ```toml
39//! [dependencies.libffi-sys]
40//! version = "4.0.0"
41//! features = ["system"]
42//! ```
43//!
44//! to your `Cargo.toml` instead.
45//!
46//! This crate supports Rust version 1.78 and later.
47
48#![allow(non_camel_case_types)]
49#![allow(non_snake_case)]
50#![allow(non_upper_case_globals)]
51#![allow(improper_ctypes)]
52#![allow(unused_imports)]
53#![no_std]
54
55#[cfg(feature = "std")]
56extern crate std;
57
58use core::ffi::{c_char, c_int, c_long, c_schar, c_uint, c_ulong, c_ushort, c_void};
59use core::fmt::{self, Debug, Formatter};
60use core::mem::zeroed;
61
62mod arch;
63pub use arch::*;
64
65/// The smallest unsigned integer type returned by [`ffi_call`].
66pub type ffi_arg = c_ulong;
67/// The smallest signed integer type returned by [`ffi_call`].
68pub type ffi_sarg = c_long;
69/// The type used to convey the ABI of a function.
70pub type ffi_abi = u32;
71/// The return type of `libffi`'s functions that may return an error.
72pub type ffi_status = u32;
73pub type ffi_type_enum = u16;
74
75pub const FFI_64_BIT_MAX: u64 = 9_223_372_036_854_775_807;
76pub const FFI_CLOSURES: u32 = 1;
77pub const FFI_SIZEOF_ARG: usize = core::mem::size_of::<c_long>();
78// NOTE: This only differs from FFI_SIZEOF_ARG on ILP platforms, which Rust does not support
79pub const FFI_SIZEOF_JAVA_RAW: usize = FFI_SIZEOF_ARG;
80
81pub const FFI_TYPE_VOID: u16 = 0;
82pub const FFI_TYPE_INT: u16 = 1;
83pub const FFI_TYPE_FLOAT: u16 = 2;
84pub const FFI_TYPE_DOUBLE: u16 = 3;
85pub const FFI_TYPE_LONGDOUBLE: u16 = 4;
86pub const FFI_TYPE_UINT8: u16 = 5;
87pub const FFI_TYPE_SINT8: u16 = 6;
88pub const FFI_TYPE_UINT16: u16 = 7;
89pub const FFI_TYPE_SINT16: u16 = 8;
90pub const FFI_TYPE_UINT32: u16 = 9;
91pub const FFI_TYPE_SINT32: u16 = 10;
92pub const FFI_TYPE_UINT64: u16 = 11;
93pub const FFI_TYPE_SINT64: u16 = 12;
94pub const FFI_TYPE_STRUCT: u16 = 13;
95pub const FFI_TYPE_POINTER: u16 = 14;
96pub const FFI_TYPE_COMPLEX: u16 = 15;
97pub const FFI_TYPE_LAST: u16 = 15;
98
99pub const ffi_status_FFI_OK: ffi_status = 0;
100pub const ffi_status_FFI_BAD_TYPEDEF: ffi_status = 1;
101pub const ffi_status_FFI_BAD_ABI: ffi_status = 2;
102pub const ffi_status_FFI_BAD_ARGTYPE: ffi_status = 3;
103
104pub const ffi_type_enum_STRUCT: ffi_type_enum = 13;
105pub const ffi_type_enum_COMPLEX: ffi_type_enum = 15;
106
107/// A struct used by `libffi` to describe types and their memory layout.
108///
109/// New `ffi_type` variables should only be constructed for describing the
110/// layout of custom structs. For plain scalar types it is recommended to refer
111/// to the `static` variables defined by libffi instead of creating new
112/// `ffi_type`s.
113///
114/// When creating new `ffi_type`s, the `size` and `alignment` fields should be
115/// left at their default values, as `libffi` will fill out these fields during
116/// [`ffi_prep_cif`].
117///
118/// # Example
119///
120/// ```
121/// use std::ptr;
122///
123/// #[repr(C)]
124/// struct CustomStruct {
125///     num: u32,
126///     num2: i64,
127///     float_num: f32,
128/// }
129///
130/// // We need to describe the types of the values in `CustomStruct`. The order
131/// // must be the same as the order in the struct definition. Note that this
132/// // array must be alive and at the same address for the entire lifetime of
133/// // the resulting `ffi_type`.
134/// let mut elements_array = unsafe {[
135///     // `libffi::low::types::uint32`, `sint64`, and `float` can be used
136///     // instead if using libffi (not -sys)
137///     ptr::addr_of_mut!(libffi_sys::ffi_type_uint32),
138///     ptr::addr_of_mut!(libffi_sys::ffi_type_sint64),
139///     ptr::addr_of_mut!(libffi_sys::ffi_type_float),
140///     // The last element in the array must be a `NULL` since `ffi_type` does
141///     // not store the number of elements in the struct.
142///     ptr::null_mut(),
143/// ]};
144///
145/// let mut custom_struct_description = libffi_sys::ffi_type {
146///     // `libffi::low::type_tag::STRUCT` can be used instead if using libffi
147///     type_: libffi_sys::FFI_TYPE_STRUCT,
148///     elements: elements_array.as_mut_ptr(),
149///     ..Default::default()
150/// };
151///
152/// // `custom_struct_description` can now be used in a [`ffi_cif`] to send
153/// // `CustomStruct` as an argument or receive a `CustomStruct` as response.
154/// ```
155#[repr(C)]
156#[derive(Copy, Clone)]
157pub struct ffi_type {
158    pub size: usize,
159    pub alignment: c_ushort,
160    pub type_: c_ushort,
161    pub elements: *mut *mut ffi_type,
162}
163
164impl Default for ffi_type {
165    fn default() -> Self {
166        unsafe { zeroed() }
167    }
168}
169
170/// A struct used by `libffi` to describe a function's ABI and type signature.
171///
172/// It is recommended to not fill out the fields in a `ffi_cif` manually, but
173/// rather supply the correct arguments to [`ffi_prep_cif`].
174#[repr(C)]
175#[derive(Debug, Copy, Clone)]
176pub struct ffi_cif {
177    pub abi: ffi_abi,
178    pub nargs: c_uint,
179    pub arg_types: *mut *mut ffi_type,
180    pub rtype: *mut ffi_type,
181    pub bytes: c_uint,
182    pub flags: c_uint,
183    #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
184    pub is_variadic: c_uint,
185    #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
186    pub aarch64_nfixedargs: c_uint,
187    #[cfg(target_arch = "arm")]
188    pub vfp_used: c_int,
189    #[cfg(target_arch = "arm")]
190    pub vfp_reg_free: c_ushort,
191    #[cfg(target_arch = "arm")]
192    pub vfp_nargs: c_ushort,
193    #[cfg(target_arch = "arm")]
194    pub vfp_args: [c_schar; 16],
195    #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
196    pub nfixedargs: c_uint,
197    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
198    pub riscv_nfixedargs: c_uint,
199    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
200    pub riscv_unused: c_uint,
201    #[cfg(target_arch = "sparc64")]
202    pub nfixedargs: c_uint,
203    #[cfg(target_arch = "loongarch64")]
204    pub loongarch_nfixedargs: c_uint,
205    #[cfg(target_arch = "loongarch64")]
206    pub loongarch_unused: c_uint,
207    #[cfg(any(
208        target_arch = "mips",
209        target_arch = "mips32r6",
210        target_arch = "mips64",
211        target_arch = "mips64r6"
212    ))]
213    pub mips_nfixedargs: c_uint,
214}
215
216impl Default for ffi_cif {
217    fn default() -> Self {
218        unsafe { zeroed() }
219    }
220}
221
222#[repr(C)]
223#[derive(Copy, Clone)]
224pub union ffi_raw {
225    pub sint: ffi_sarg,
226    pub uint: ffi_arg,
227    pub flt: f32,
228    pub data: [c_char; FFI_SIZEOF_ARG],
229    pub ptr: *mut c_void,
230}
231
232impl Default for ffi_raw {
233    fn default() -> Self {
234        unsafe { zeroed() }
235    }
236}
237
238pub type ffi_java_raw = ffi_raw;
239
240#[repr(C)]
241#[derive(Copy, Clone)]
242pub union ffi_trampoline {
243    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
244    pub ftramp: *mut c_void,
245}
246
247/// A struct used by `libffi` to describe and manage closures.
248///
249/// Closures in libffi can be used to create function pointers to functions with
250/// arbitrary signatures that can also have some custom data embedded.
251///
252/// `ffi_closure` should not be created manually. Instead, [`ffi_closure_alloc`]
253/// should be invoked to allocate memory for the `ffi_closure` before its fields
254/// are populated by [`ffi_prep_closure`].
255///
256/// **Caution** `ffi_closure` should not be generated or modified manually, but
257/// allocated by `ffi_closure_alloc` and passed around to libffi functions as a
258/// pointer.
259#[repr(C, align(8))]
260#[derive(Copy, Clone)]
261pub struct ffi_closure {
262    // https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L325
263    // https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/configure.ac#L227
264    // On Apple systems with ARM CPUs, two pointers `trampoline_table` and
265    // `trampoline_table_entry` are used instead of the `ffi_trampoline`.
266    #[cfg(all(
267        target_vendor = "apple",
268        any(target_arch = "arm", target_arch = "aarch64")
269    ))]
270    pub trampoline_table: *mut c_void,
271    #[cfg(all(
272        target_vendor = "apple",
273        any(target_arch = "arm", target_arch = "aarch64")
274    ))]
275    pub trampoline_table_entry: *mut c_void,
276    #[cfg(not(all(
277        target_vendor = "apple",
278        any(target_arch = "arm", target_arch = "aarch64")
279    )))]
280    pub tramp: ffi_trampoline,
281    pub cif: *mut ffi_cif,
282    pub fun: Option<
283        unsafe extern "C" fn(
284            arg1: *mut ffi_cif,
285            arg2: *mut c_void,
286            arg3: *mut *mut c_void,
287            arg4: *mut c_void,
288        ),
289    >,
290    pub user_data: *mut c_void,
291    // https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L337
292    #[cfg(all(target_env = "msvc", target_arch = "x86"))]
293    pub _padding: *mut c_void,
294}
295
296/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
297impl Debug for ffi_closure {
298    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
299        let mut debug_struct = f.debug_struct("ffi_closure");
300
301        #[cfg(all(
302            target_vendor = "apple",
303            any(target_arch = "arm", target_arch = "aarch64")
304        ))]
305        debug_struct
306            .field("trampoline_table", &self.trampoline_table)
307            .field("trampoline_table_entry", &self.trampoline_table_entry);
308        #[cfg(not(all(
309            target_vendor = "apple",
310            any(target_arch = "arm", target_arch = "aarch64")
311        )))]
312        debug_struct
313            // SAFETY: This might be undefined behavior if `tramp` is a `ftramp`. It is probably
314            // okay for debug purposes, however.
315            .field("tramp", unsafe { &self.tramp.tramp });
316
317        debug_struct
318            .field("cif", &self.cif)
319            .field("fun", &self.fun)
320            .field("user_data", &self.user_data)
321            .finish()
322    }
323}
324
325impl Default for ffi_closure {
326    fn default() -> Self {
327        unsafe { zeroed() }
328    }
329}
330
331#[repr(C)]
332#[derive(Copy, Clone)]
333pub struct ffi_raw_closure {
334    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
335    pub cif: *mut ffi_cif,
336    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L364
337    #[cfg(not(target_arch = "x86"))]
338    pub translate_args: Option<
339        unsafe extern "C" fn(
340            arg1: *mut ffi_cif,
341            arg2: *mut c_void,
342            arg3: *mut *mut c_void,
343            arg4: *mut c_void,
344        ),
345    >,
346    #[cfg(not(target_arch = "x86"))]
347    pub this_closure: *mut c_void,
348    pub fun: Option<
349        unsafe extern "C" fn(
350            arg1: *mut ffi_cif,
351            arg2: *mut c_void,
352            arg3: *mut ffi_raw,
353            arg4: *mut c_void,
354        ),
355    >,
356    pub user_data: *mut c_void,
357}
358
359/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
360impl Debug for ffi_raw_closure {
361    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
362        let mut debug_struct = f.debug_struct("ffi_raw_closure");
363        debug_struct
364            .field("tramp", &&self.tramp[..])
365            .field("cif", &self.cif);
366
367        #[cfg(not(target_arch = "x86"))]
368        debug_struct.field("translate_args", &self.translate_args);
369        #[cfg(not(target_arch = "x86"))]
370        debug_struct.field("this_closure", &self.this_closure);
371
372        debug_struct
373            .field("fun", &self.fun)
374            .field("user_data", &self.user_data)
375            .finish()
376    }
377}
378
379impl Default for ffi_raw_closure {
380    fn default() -> Self {
381        unsafe { zeroed() }
382    }
383}
384#[repr(C)]
385#[derive(Copy, Clone)]
386pub struct ffi_java_raw_closure {
387    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
388    pub cif: *mut ffi_cif,
389    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L386
390    #[cfg(not(target_arch = "x86"))]
391    pub translate_args: Option<
392        unsafe extern "C" fn(
393            arg1: *mut ffi_cif,
394            arg2: *mut c_void,
395            arg3: *mut *mut c_void,
396            arg4: *mut c_void,
397        ),
398    >,
399    #[cfg(not(target_arch = "x86"))]
400    pub this_closure: *mut c_void,
401    pub fun: Option<
402        unsafe extern "C" fn(
403            arg1: *mut ffi_cif,
404            arg2: *mut c_void,
405            arg3: *mut ffi_java_raw,
406            arg4: *mut c_void,
407        ),
408    >,
409    pub user_data: *mut c_void,
410}
411
412/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
413impl Debug for ffi_java_raw_closure {
414    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
415        let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
416        debug_struct
417            .field("tramp", &&self.tramp[..])
418            .field("cif", &self.cif);
419
420        #[cfg(not(target_arch = "x86"))]
421        debug_struct.field("translate_args", &self.translate_args);
422        #[cfg(not(target_arch = "x86"))]
423        debug_struct.field("this_closure", &self.this_closure);
424
425        debug_struct
426            .field("fun", &self.fun)
427            .field("user_data", &self.user_data)
428            .finish()
429    }
430}
431
432impl Default for ffi_java_raw_closure {
433    fn default() -> Self {
434        unsafe { zeroed() }
435    }
436}
437
438#[repr(C)]
439#[derive(Debug, Copy, Clone)]
440pub struct ffi_go_closure {
441    pub tramp: *mut c_void,
442    pub cif: *mut ffi_cif,
443    pub fun: Option<
444        unsafe extern "C" fn(
445            arg1: *mut ffi_cif,
446            arg2: *mut c_void,
447            arg3: *mut *mut c_void,
448            arg4: *mut c_void,
449        ),
450    >,
451}
452impl Default for ffi_go_closure {
453    fn default() -> Self {
454        unsafe { zeroed() }
455    }
456}
457
458extern "C" {
459    pub static mut ffi_type_void: ffi_type;
460    pub static mut ffi_type_uint8: ffi_type;
461    pub static mut ffi_type_sint8: ffi_type;
462    pub static mut ffi_type_uint16: ffi_type;
463    pub static mut ffi_type_sint16: ffi_type;
464    pub static mut ffi_type_uint32: ffi_type;
465    pub static mut ffi_type_sint32: ffi_type;
466    pub static mut ffi_type_uint64: ffi_type;
467    pub static mut ffi_type_sint64: ffi_type;
468    pub static mut ffi_type_float: ffi_type;
469    pub static mut ffi_type_double: ffi_type;
470    pub static mut ffi_type_longdouble: ffi_type;
471    pub static mut ffi_type_pointer: ffi_type;
472
473    #[cfg(all(feature = "complex", not(windows)))]
474    pub static mut ffi_type_complex_float: ffi_type;
475
476    #[cfg(all(feature = "complex", not(windows)))]
477    pub static mut ffi_type_complex_double: ffi_type;
478
479    #[cfg(all(feature = "complex", not(windows)))]
480    pub static mut ffi_type_complex_longdouble: ffi_type;
481
482    pub fn ffi_raw_call(
483        cif: *mut ffi_cif,
484        fn_: Option<unsafe extern "C" fn()>,
485        rvalue: *mut c_void,
486        avalue: *mut ffi_raw,
487    );
488
489    pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
490
491    pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
492
493    pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
494
495    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L302
496    #[cfg(not(target_arch = "x86"))]
497    #[deprecated = "Deprecated in libffi 3.3"]
498    pub fn ffi_java_raw_call(
499        cif: *mut ffi_cif,
500        fn_: Option<unsafe extern "C" fn()>,
501        rvalue: *mut c_void,
502        avalue: *mut ffi_java_raw,
503    );
504
505    #[deprecated = "Deprecated in libffi 3.3"]
506    pub fn ffi_java_ptrarray_to_raw(
507        cif: *mut ffi_cif,
508        args: *mut *mut c_void,
509        raw: *mut ffi_java_raw,
510    );
511
512    #[deprecated = "Deprecated in libffi 3.3"]
513    pub fn ffi_java_raw_to_ptrarray(
514        cif: *mut ffi_cif,
515        raw: *mut ffi_java_raw,
516        args: *mut *mut c_void,
517    );
518
519    #[deprecated = "Deprecated in libffi 3.3"]
520    pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
521
522    pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
523
524    pub fn ffi_closure_free(arg1: *mut c_void);
525
526    #[deprecated = "Deprecated in libffi 3.3, use `ffi_prep_closure_loc` instead"]
527    pub fn ffi_prep_closure(
528        arg1: *mut ffi_closure,
529        arg2: *mut ffi_cif,
530        fun: Option<
531            unsafe extern "C" fn(
532                arg1: *mut ffi_cif,
533                arg2: *mut c_void,
534                arg3: *mut *mut c_void,
535                arg4: *mut c_void,
536            ),
537        >,
538        user_data: *mut c_void,
539    ) -> ffi_status;
540
541    pub fn ffi_prep_closure_loc(
542        arg1: *mut ffi_closure,
543        arg2: *mut ffi_cif,
544        fun: Option<
545            unsafe extern "C" fn(
546                arg1: *mut ffi_cif,
547                arg2: *mut c_void,
548                arg3: *mut *mut c_void,
549                arg4: *mut c_void,
550            ),
551        >,
552        user_data: *mut c_void,
553        codeloc: *mut c_void,
554    ) -> ffi_status;
555
556    pub fn ffi_prep_raw_closure(
557        arg1: *mut ffi_raw_closure,
558        cif: *mut ffi_cif,
559        fun: Option<
560            unsafe extern "C" fn(
561                arg1: *mut ffi_cif,
562                arg2: *mut c_void,
563                arg3: *mut ffi_raw,
564                arg4: *mut c_void,
565            ),
566        >,
567        user_data: *mut c_void,
568    ) -> ffi_status;
569
570    pub fn ffi_prep_raw_closure_loc(
571        arg1: *mut ffi_raw_closure,
572        cif: *mut ffi_cif,
573        fun: Option<
574            unsafe extern "C" fn(
575                arg1: *mut ffi_cif,
576                arg2: *mut c_void,
577                arg3: *mut ffi_raw,
578                arg4: *mut c_void,
579            ),
580        >,
581        user_data: *mut c_void,
582        codeloc: *mut c_void,
583    ) -> ffi_status;
584
585    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L441
586    #[cfg(not(target_arch = "x86"))]
587    #[deprecated = "Deprecated in libffi 3.3"]
588    pub fn ffi_prep_java_raw_closure(
589        arg1: *mut ffi_java_raw_closure,
590        cif: *mut ffi_cif,
591        fun: Option<
592            unsafe extern "C" fn(
593                arg1: *mut ffi_cif,
594                arg2: *mut c_void,
595                arg3: *mut ffi_java_raw,
596                arg4: *mut c_void,
597            ),
598        >,
599        user_data: *mut c_void,
600    ) -> ffi_status;
601
602    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L449
603    #[cfg(not(target_arch = "x86"))]
604    #[deprecated = "Deprecated in libffi 3.3"]
605    pub fn ffi_prep_java_raw_closure_loc(
606        arg1: *mut ffi_java_raw_closure,
607        cif: *mut ffi_cif,
608        fun: Option<
609            unsafe extern "C" fn(
610                arg1: *mut ffi_cif,
611                arg2: *mut c_void,
612                arg3: *mut ffi_java_raw,
613                arg4: *mut c_void,
614            ),
615        >,
616        user_data: *mut c_void,
617        codeloc: *mut c_void,
618    ) -> ffi_status;
619
620    pub fn ffi_prep_go_closure(
621        arg1: *mut ffi_go_closure,
622        arg2: *mut ffi_cif,
623        fun: Option<
624            unsafe extern "C" fn(
625                arg1: *mut ffi_cif,
626                arg2: *mut c_void,
627                arg3: *mut *mut c_void,
628                arg4: *mut c_void,
629            ),
630        >,
631    ) -> ffi_status;
632
633    pub fn ffi_call_go(
634        cif: *mut ffi_cif,
635        fn_: Option<unsafe extern "C" fn()>,
636        rvalue: *mut c_void,
637        avalue: *mut *mut c_void,
638        closure: *mut c_void,
639    );
640
641    pub fn ffi_prep_cif(
642        cif: *mut ffi_cif,
643        abi: ffi_abi,
644        nargs: c_uint,
645        rtype: *mut ffi_type,
646        atypes: *mut *mut ffi_type,
647    ) -> ffi_status;
648
649    pub fn ffi_prep_cif_var(
650        cif: *mut ffi_cif,
651        abi: ffi_abi,
652        nfixedargs: c_uint,
653        ntotalargs: c_uint,
654        rtype: *mut ffi_type,
655        atypes: *mut *mut ffi_type,
656    ) -> ffi_status;
657
658    pub fn ffi_call(
659        cif: *mut ffi_cif,
660        fn_: Option<unsafe extern "C" fn()>,
661        rvalue: *mut c_void,
662        avalue: *mut *mut c_void,
663    );
664
665    pub fn ffi_get_struct_offsets(
666        abi: ffi_abi,
667        struct_type: *mut ffi_type,
668        offsets: *mut usize,
669    ) -> ffi_status;
670}
671
672#[cfg(all(test, feature = "std"))]
673mod test {
674    use std::{mem::transmute, ptr::addr_of_mut};
675    use std::{vec, vec::Vec};
676
677    use super::*;
678
679    extern "C" fn cast_u8_u32(x: u8) -> u32 {
680        x as u32
681    }
682
683    #[test]
684    fn test_function_sign_extension() {
685        unsafe {
686            let mut cif: ffi_cif = Default::default();
687            let mut arg_types: Vec<*mut ffi_type> = vec![addr_of_mut!(ffi_type_uint8)];
688
689            let prep_status = ffi_prep_cif(
690                &mut cif,
691                ffi_abi_FFI_DEFAULT_ABI,
692                1,
693                addr_of_mut!(ffi_type_uint8),
694                arg_types.as_mut_ptr(),
695            );
696
697            assert_eq!(prep_status, ffi_status_FFI_OK);
698
699            let mut rval: ffi_arg = 0;
700            let func = transmute::<extern "C" fn(u8) -> u32, extern "C" fn()>(cast_u8_u32);
701
702            ffi_call(
703                &mut cif,
704                Some(func),
705                &mut rval as *mut _ as *mut c_void,
706                vec![&mut 256 as *mut _ as *mut c_void].as_mut_ptr(),
707            );
708
709            assert_eq!(rval, 0);
710        }
711    }
712
713    extern "C" fn add(x: u64, y: u64) -> u64 {
714        x + y
715    }
716
717    #[test]
718    fn test_function_with_two_arguments() {
719        unsafe {
720            let mut cif: ffi_cif = Default::default();
721            let mut arg_types: Vec<*mut ffi_type> =
722                vec![addr_of_mut!(ffi_type_uint64), addr_of_mut!(ffi_type_uint64)];
723
724            let prep_status = ffi_prep_cif(
725                &mut cif,
726                ffi_abi_FFI_DEFAULT_ABI,
727                2,
728                addr_of_mut!(ffi_type_uint64),
729                arg_types.as_mut_ptr(),
730            );
731
732            assert_eq!(prep_status, ffi_status_FFI_OK);
733
734            let mut rval = 0u64;
735            let func = transmute::<extern "C" fn(u64, u64) -> u64, extern "C" fn()>(add);
736
737            ffi_call(
738                &mut cif,
739                Some(func),
740                &mut rval as *mut _ as *mut c_void,
741                vec![
742                    &mut 4u64 as *mut _ as *mut c_void,
743                    &mut 5u64 as *mut _ as *mut c_void,
744                ]
745                .as_mut_ptr(),
746            );
747
748            assert_eq!(rval, 9);
749        }
750    }
751
752    // Verify that `ffi_closure` is the correct size. This does not guarantee
753    // that the layout of the struct is correct, but it *should* not matter much
754    // as `ffi_closure` *should* not be modified outside of libffi.
755    // `ffi_get_closure_size` was added in libffi v3.5.0. This test cannot be
756    // executed without the function, so it is disabled when performing dynamic
757    // linking to libffi until version 3.5.0. is required for dynamic linking by
758    // libffi-rs.
759    #[cfg(not(feature = "system"))]
760    #[test]
761    fn verify_ffi_closure_size() {
762        extern "C" {
763            fn ffi_get_closure_size() -> usize;
764        }
765
766        unsafe {
767            assert_eq!(std::mem::size_of::<ffi_closure>(), ffi_get_closure_size());
768        }
769    }
770}