Skip to main content

libffi_sys/
lib.rs

1#![doc(html_root_url = "https://docs.rs/libffi-sys/4.2.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.2.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.2.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)]
260#[cfg_attr(target_env = "msvc", repr(align(8)))]
261#[derive(Copy, Clone)]
262pub struct ffi_closure {
263    // https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L325
264    // https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/configure.ac#L227
265    // On Apple systems with ARM CPUs, two pointers `trampoline_table` and
266    // `trampoline_table_entry` are used instead of the `ffi_trampoline`.
267    #[cfg(all(
268        target_vendor = "apple",
269        any(target_arch = "arm", target_arch = "aarch64")
270    ))]
271    pub trampoline_table: *mut c_void,
272    #[cfg(all(
273        target_vendor = "apple",
274        any(target_arch = "arm", target_arch = "aarch64")
275    ))]
276    pub trampoline_table_entry: *mut c_void,
277    #[cfg(not(all(
278        target_vendor = "apple",
279        any(target_arch = "arm", target_arch = "aarch64")
280    )))]
281    pub tramp: ffi_trampoline,
282    pub cif: *mut ffi_cif,
283    pub fun: Option<
284        unsafe extern "C" fn(
285            arg1: *mut ffi_cif,
286            arg2: *mut c_void,
287            arg3: *mut *mut c_void,
288            arg4: *mut c_void,
289        ),
290    >,
291    pub user_data: *mut c_void,
292    // https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L337
293    #[cfg(all(target_env = "msvc", target_arch = "x86"))]
294    pub _padding: *mut c_void,
295}
296
297/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
298impl Debug for ffi_closure {
299    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
300        let mut debug_struct = f.debug_struct("ffi_closure");
301
302        #[cfg(all(
303            target_vendor = "apple",
304            any(target_arch = "arm", target_arch = "aarch64")
305        ))]
306        debug_struct
307            .field("trampoline_table", &self.trampoline_table)
308            .field("trampoline_table_entry", &self.trampoline_table_entry);
309        #[cfg(not(all(
310            target_vendor = "apple",
311            any(target_arch = "arm", target_arch = "aarch64")
312        )))]
313        debug_struct
314            // SAFETY: This might be undefined behavior if `tramp` is a `ftramp`. It is probably
315            // okay for debug purposes, however.
316            .field("tramp", unsafe { &self.tramp.tramp });
317
318        debug_struct
319            .field("cif", &self.cif)
320            .field("fun", &self.fun)
321            .field("user_data", &self.user_data)
322            .finish()
323    }
324}
325
326impl Default for ffi_closure {
327    fn default() -> Self {
328        unsafe { zeroed() }
329    }
330}
331
332#[repr(C)]
333#[derive(Copy, Clone)]
334pub struct ffi_raw_closure {
335    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
336    pub cif: *mut ffi_cif,
337    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L364
338    #[cfg(not(target_arch = "x86"))]
339    pub translate_args: Option<
340        unsafe extern "C" fn(
341            arg1: *mut ffi_cif,
342            arg2: *mut c_void,
343            arg3: *mut *mut c_void,
344            arg4: *mut c_void,
345        ),
346    >,
347    #[cfg(not(target_arch = "x86"))]
348    pub this_closure: *mut c_void,
349    pub fun: Option<
350        unsafe extern "C" fn(
351            arg1: *mut ffi_cif,
352            arg2: *mut c_void,
353            arg3: *mut ffi_raw,
354            arg4: *mut c_void,
355        ),
356    >,
357    pub user_data: *mut c_void,
358}
359
360/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
361impl Debug for ffi_raw_closure {
362    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
363        let mut debug_struct = f.debug_struct("ffi_raw_closure");
364        debug_struct
365            .field("tramp", &&self.tramp[..])
366            .field("cif", &self.cif);
367
368        #[cfg(not(target_arch = "x86"))]
369        debug_struct.field("translate_args", &self.translate_args);
370        #[cfg(not(target_arch = "x86"))]
371        debug_struct.field("this_closure", &self.this_closure);
372
373        debug_struct
374            .field("fun", &self.fun)
375            .field("user_data", &self.user_data)
376            .finish()
377    }
378}
379
380impl Default for ffi_raw_closure {
381    fn default() -> Self {
382        unsafe { zeroed() }
383    }
384}
385#[repr(C)]
386#[derive(Copy, Clone)]
387pub struct ffi_java_raw_closure {
388    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
389    pub cif: *mut ffi_cif,
390    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L386
391    #[cfg(not(target_arch = "x86"))]
392    pub translate_args: Option<
393        unsafe extern "C" fn(
394            arg1: *mut ffi_cif,
395            arg2: *mut c_void,
396            arg3: *mut *mut c_void,
397            arg4: *mut c_void,
398        ),
399    >,
400    #[cfg(not(target_arch = "x86"))]
401    pub this_closure: *mut c_void,
402    pub fun: Option<
403        unsafe extern "C" fn(
404            arg1: *mut ffi_cif,
405            arg2: *mut c_void,
406            arg3: *mut ffi_java_raw,
407            arg4: *mut c_void,
408        ),
409    >,
410    pub user_data: *mut c_void,
411}
412
413/// Implements Debug manually since sometimes `FFI_TRAMPOLINE_SIZE` is too large
414impl Debug for ffi_java_raw_closure {
415    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
416        let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
417        debug_struct
418            .field("tramp", &&self.tramp[..])
419            .field("cif", &self.cif);
420
421        #[cfg(not(target_arch = "x86"))]
422        debug_struct.field("translate_args", &self.translate_args);
423        #[cfg(not(target_arch = "x86"))]
424        debug_struct.field("this_closure", &self.this_closure);
425
426        debug_struct
427            .field("fun", &self.fun)
428            .field("user_data", &self.user_data)
429            .finish()
430    }
431}
432
433impl Default for ffi_java_raw_closure {
434    fn default() -> Self {
435        unsafe { zeroed() }
436    }
437}
438
439#[repr(C)]
440#[derive(Debug, Copy, Clone)]
441pub struct ffi_go_closure {
442    pub tramp: *mut c_void,
443    pub cif: *mut ffi_cif,
444    pub fun: Option<
445        unsafe extern "C" fn(
446            arg1: *mut ffi_cif,
447            arg2: *mut c_void,
448            arg3: *mut *mut c_void,
449            arg4: *mut c_void,
450        ),
451    >,
452}
453impl Default for ffi_go_closure {
454    fn default() -> Self {
455        unsafe { zeroed() }
456    }
457}
458
459extern "C" {
460    pub static mut ffi_type_void: ffi_type;
461    pub static mut ffi_type_uint8: ffi_type;
462    pub static mut ffi_type_sint8: ffi_type;
463    pub static mut ffi_type_uint16: ffi_type;
464    pub static mut ffi_type_sint16: ffi_type;
465    pub static mut ffi_type_uint32: ffi_type;
466    pub static mut ffi_type_sint32: ffi_type;
467    pub static mut ffi_type_uint64: ffi_type;
468    pub static mut ffi_type_sint64: ffi_type;
469    pub static mut ffi_type_float: ffi_type;
470    pub static mut ffi_type_double: ffi_type;
471    pub static mut ffi_type_longdouble: ffi_type;
472    pub static mut ffi_type_pointer: ffi_type;
473
474    #[cfg(all(feature = "complex", not(windows)))]
475    pub static mut ffi_type_complex_float: ffi_type;
476
477    #[cfg(all(feature = "complex", not(windows)))]
478    pub static mut ffi_type_complex_double: ffi_type;
479
480    #[cfg(all(feature = "complex", not(windows)))]
481    pub static mut ffi_type_complex_longdouble: ffi_type;
482
483    pub fn ffi_raw_call(
484        cif: *mut ffi_cif,
485        fn_: Option<unsafe extern "C" fn()>,
486        rvalue: *mut c_void,
487        avalue: *mut ffi_raw,
488    );
489
490    pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
491
492    pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
493
494    pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
495
496    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L302
497    #[cfg(not(target_arch = "x86"))]
498    #[deprecated = "Deprecated in libffi 3.3"]
499    pub fn ffi_java_raw_call(
500        cif: *mut ffi_cif,
501        fn_: Option<unsafe extern "C" fn()>,
502        rvalue: *mut c_void,
503        avalue: *mut ffi_java_raw,
504    );
505
506    #[deprecated = "Deprecated in libffi 3.3"]
507    pub fn ffi_java_ptrarray_to_raw(
508        cif: *mut ffi_cif,
509        args: *mut *mut c_void,
510        raw: *mut ffi_java_raw,
511    );
512
513    #[deprecated = "Deprecated in libffi 3.3"]
514    pub fn ffi_java_raw_to_ptrarray(
515        cif: *mut ffi_cif,
516        raw: *mut ffi_java_raw,
517        args: *mut *mut c_void,
518    );
519
520    #[deprecated = "Deprecated in libffi 3.3"]
521    pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
522
523    pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
524
525    pub fn ffi_closure_free(arg1: *mut c_void);
526
527    #[deprecated = "Deprecated in libffi 3.3, use `ffi_prep_closure_loc` instead"]
528    pub fn ffi_prep_closure(
529        arg1: *mut ffi_closure,
530        arg2: *mut ffi_cif,
531        fun: Option<
532            unsafe extern "C" fn(
533                arg1: *mut ffi_cif,
534                arg2: *mut c_void,
535                arg3: *mut *mut c_void,
536                arg4: *mut c_void,
537            ),
538        >,
539        user_data: *mut c_void,
540    ) -> ffi_status;
541
542    pub fn ffi_prep_closure_loc(
543        arg1: *mut ffi_closure,
544        arg2: *mut ffi_cif,
545        fun: Option<
546            unsafe extern "C" fn(
547                arg1: *mut ffi_cif,
548                arg2: *mut c_void,
549                arg3: *mut *mut c_void,
550                arg4: *mut c_void,
551            ),
552        >,
553        user_data: *mut c_void,
554        codeloc: *mut c_void,
555    ) -> ffi_status;
556
557    pub fn ffi_prep_raw_closure(
558        arg1: *mut ffi_raw_closure,
559        cif: *mut ffi_cif,
560        fun: Option<
561            unsafe extern "C" fn(
562                arg1: *mut ffi_cif,
563                arg2: *mut c_void,
564                arg3: *mut ffi_raw,
565                arg4: *mut c_void,
566            ),
567        >,
568        user_data: *mut c_void,
569    ) -> ffi_status;
570
571    pub fn ffi_prep_raw_closure_loc(
572        arg1: *mut ffi_raw_closure,
573        cif: *mut ffi_cif,
574        fun: Option<
575            unsafe extern "C" fn(
576                arg1: *mut ffi_cif,
577                arg2: *mut c_void,
578                arg3: *mut ffi_raw,
579                arg4: *mut c_void,
580            ),
581        >,
582        user_data: *mut c_void,
583        codeloc: *mut c_void,
584    ) -> ffi_status;
585
586    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L441
587    #[cfg(not(target_arch = "x86"))]
588    #[deprecated = "Deprecated in libffi 3.3"]
589    pub fn ffi_prep_java_raw_closure(
590        arg1: *mut ffi_java_raw_closure,
591        cif: *mut ffi_cif,
592        fun: Option<
593            unsafe extern "C" fn(
594                arg1: *mut ffi_cif,
595                arg2: *mut c_void,
596                arg3: *mut ffi_java_raw,
597                arg4: *mut c_void,
598            ),
599        >,
600        user_data: *mut c_void,
601    ) -> ffi_status;
602
603    // See: https://github.com/libffi/libffi/blob/252c0f463641e6100169c3f0a4a590d7df438278/include/ffi.h.in#L449
604    #[cfg(not(target_arch = "x86"))]
605    #[deprecated = "Deprecated in libffi 3.3"]
606    pub fn ffi_prep_java_raw_closure_loc(
607        arg1: *mut ffi_java_raw_closure,
608        cif: *mut ffi_cif,
609        fun: Option<
610            unsafe extern "C" fn(
611                arg1: *mut ffi_cif,
612                arg2: *mut c_void,
613                arg3: *mut ffi_java_raw,
614                arg4: *mut c_void,
615            ),
616        >,
617        user_data: *mut c_void,
618        codeloc: *mut c_void,
619    ) -> ffi_status;
620
621    pub fn ffi_prep_go_closure(
622        arg1: *mut ffi_go_closure,
623        arg2: *mut ffi_cif,
624        fun: Option<
625            unsafe extern "C" fn(
626                arg1: *mut ffi_cif,
627                arg2: *mut c_void,
628                arg3: *mut *mut c_void,
629                arg4: *mut c_void,
630            ),
631        >,
632    ) -> ffi_status;
633
634    pub fn ffi_call_go(
635        cif: *mut ffi_cif,
636        fn_: Option<unsafe extern "C" fn()>,
637        rvalue: *mut c_void,
638        avalue: *mut *mut c_void,
639        closure: *mut c_void,
640    );
641
642    pub fn ffi_prep_cif(
643        cif: *mut ffi_cif,
644        abi: ffi_abi,
645        nargs: c_uint,
646        rtype: *mut ffi_type,
647        atypes: *mut *mut ffi_type,
648    ) -> ffi_status;
649
650    pub fn ffi_prep_cif_var(
651        cif: *mut ffi_cif,
652        abi: ffi_abi,
653        nfixedargs: c_uint,
654        ntotalargs: c_uint,
655        rtype: *mut ffi_type,
656        atypes: *mut *mut ffi_type,
657    ) -> ffi_status;
658
659    pub fn ffi_call(
660        cif: *mut ffi_cif,
661        fn_: Option<unsafe extern "C" fn()>,
662        rvalue: *mut c_void,
663        avalue: *mut *mut c_void,
664    );
665
666    pub fn ffi_get_struct_offsets(
667        abi: ffi_abi,
668        struct_type: *mut ffi_type,
669        offsets: *mut usize,
670    ) -> ffi_status;
671}
672
673#[cfg(all(test, feature = "std"))]
674mod test {
675    use std::{mem::transmute, ptr::addr_of_mut};
676    use std::{vec, vec::Vec};
677
678    use super::*;
679
680    extern "C" fn cast_u8_u32(x: u8) -> u32 {
681        x as u32
682    }
683
684    #[test]
685    fn test_function_sign_extension() {
686        unsafe {
687            let mut cif: ffi_cif = Default::default();
688            let mut arg_types: Vec<*mut ffi_type> = vec![addr_of_mut!(ffi_type_uint8)];
689
690            let prep_status = ffi_prep_cif(
691                &mut cif,
692                ffi_abi_FFI_DEFAULT_ABI,
693                1,
694                addr_of_mut!(ffi_type_uint8),
695                arg_types.as_mut_ptr(),
696            );
697
698            assert_eq!(prep_status, ffi_status_FFI_OK);
699
700            let mut rval: ffi_arg = 0;
701            let func = transmute::<extern "C" fn(u8) -> u32, extern "C" fn()>(cast_u8_u32);
702
703            ffi_call(
704                &mut cif,
705                Some(func),
706                &mut rval as *mut _ as *mut c_void,
707                vec![&mut 256 as *mut _ as *mut c_void].as_mut_ptr(),
708            );
709
710            assert_eq!(rval, 0);
711        }
712    }
713
714    extern "C" fn add(x: u64, y: u64) -> u64 {
715        x + y
716    }
717
718    #[test]
719    fn test_function_with_two_arguments() {
720        unsafe {
721            let mut cif: ffi_cif = Default::default();
722            let mut arg_types: Vec<*mut ffi_type> =
723                vec![addr_of_mut!(ffi_type_uint64), addr_of_mut!(ffi_type_uint64)];
724
725            let prep_status = ffi_prep_cif(
726                &mut cif,
727                ffi_abi_FFI_DEFAULT_ABI,
728                2,
729                addr_of_mut!(ffi_type_uint64),
730                arg_types.as_mut_ptr(),
731            );
732
733            assert_eq!(prep_status, ffi_status_FFI_OK);
734
735            let mut rval = 0u64;
736            let func = transmute::<extern "C" fn(u64, u64) -> u64, extern "C" fn()>(add);
737
738            ffi_call(
739                &mut cif,
740                Some(func),
741                &mut rval as *mut _ as *mut c_void,
742                vec![
743                    &mut 4u64 as *mut _ as *mut c_void,
744                    &mut 5u64 as *mut _ as *mut c_void,
745                ]
746                .as_mut_ptr(),
747            );
748
749            assert_eq!(rval, 9);
750        }
751    }
752
753    // Verify that `ffi_closure` is the correct size. This does not guarantee
754    // that the layout of the struct is correct, but it *should* not matter much
755    // as `ffi_closure` *should* not be modified outside of libffi.
756    // `ffi_get_closure_size` was added in libffi v3.5.0. This test cannot be
757    // executed without the function, so it is disabled when performing dynamic
758    // linking to libffi until version 3.5.0. is required for dynamic linking by
759    // libffi-rs.
760    #[cfg(not(feature = "system"))]
761    #[test]
762    fn verify_ffi_closure_size() {
763        extern "C" {
764            fn ffi_get_closure_size() -> usize;
765        }
766
767        unsafe {
768            assert_eq!(std::mem::size_of::<ffi_closure>(), ffi_get_closure_size());
769        }
770    }
771}