1//! Simple dynamic calls.
2//!
3//! This API allows us to call a code pointer with an array of
4//! arguments, using libffi to set up the call.
5//!
6//! # Examples
7//!
8//! ```
9//! extern "C" fn hypot(x: f32, y: f32) -> f32 {
10//! (x * x + y * y).sqrt()
11//! }
12//!
13//! use libffi::ffi_call;
14//!
15//! let result = unsafe { ffi_call!{ hypot(3f32, 4f32) -> f32 } };
16//!
17//! assert!((result - 5f32).abs() < 0.0001);
18//! ```
19
20use std::convert::TryInto;
21use std::marker::PhantomData;
22
23use crate::middle;
24pub use middle::CodePtr;
25
26/// Encapsulates an argument with its type information.
27///
28/// In order to set up calls using [`fn@call`], we
29/// need to wrap (a reference to) each argument in an `Arg`. The usual
30/// way to do this is with function [`arg`].
31#[derive(Clone, Debug)]
32pub struct Arg<'a> {
33 // There should be some type T such that type_ is the middle-layer
34 // value of Type<T> and value is T::reify().
35 type_: middle::Type,
36 value: middle::Arg,
37 _marker: PhantomData<&'a ()>,
38}
39
40impl<'a> Arg<'a> {
41 /// Wraps an argument reference for passing to [`fn@call`].
42 ///
43 /// For a shorter alias of the same, see [`fn@arg`].
44 pub fn new<T: super::CType>(arg: &'a T) -> Self {
45 Arg {
46 type_: T::reify().into_middle(),
47 value: middle::Arg::new(arg),
48 _marker: PhantomData,
49 }
50 }
51}
52
53/// Constructs an [`Arg`] for passing to [`fn@call`].
54pub fn arg<T: super::CType>(arg: &T) -> Arg {
55 Arg::new(arg)
56}
57
58/// Performs a dynamic call to a C function.
59///
60/// To reduce boilerplate, see [`ffi_call!`].
61///
62/// # Examples
63///
64/// ```
65/// extern "C" fn hypot(x: f32, y: f32) -> f32 {
66/// (x * x + y * y).sqrt()
67/// }
68///
69/// use libffi::high::call::*;
70///
71/// let result = unsafe {
72/// call::<f32>(CodePtr(hypot as *mut _), &[arg(&3f32), arg(&4f32)])
73/// };
74///
75/// assert!((result - 5f32).abs() < 0.0001);
76/// ```
77pub unsafe fn call<R: super::CType>(fun: CodePtr, args: &[Arg]) -> R {
78 let types: impl Iterator = args.iter().map(|arg: &Arg<'_>| arg.type_.clone());
79 let cif: Cif = middle::Cif::new(args:types, R::reify().into_middle());
80
81 let values: Vec = args.iter().map(|arg: &Arg<'_>| arg.value.clone()).collect::<Vec<_>>();
82 // If `R` is a small integer type, libffi implicitly extends it to
83 // `ffi_arg` or `ffi_sarg`. To account for this, use `R::RetType`
84 // as return type for the low-level call, and convert the result back.
85 cifOption.call::<R::RetType>(fun, &values)
86 .try_into()
87 .ok()
88 .unwrap()
89}
90
91/// Performs a dynamic call to a C function.
92///
93/// This macro provides sugar for [`high::arg`](crate::high::arg) and
94/// [`high::call`](fn@crate::high::call). For more control, see
95/// [`high::call`](fn@crate::high::call).
96///
97/// # Examples
98///
99/// ```
100/// extern "C" fn hypot(x: f32, y: f32) -> f32 {
101/// (x * x + y * y).sqrt()
102/// }
103///
104/// use libffi::ffi_call;
105///
106/// let result = unsafe { ffi_call!{ hypot(3f32, 4f32) -> f32 } };
107///
108/// assert!((result - 5f32).abs() < 0.0001);
109/// ```
110#[macro_export]
111macro_rules! ffi_call {
112
113 { ( $fun:expr ) ( $( $arg:expr ),* ) -> $ty:ty }
114 =>
115 {
116 $crate::high::call::call::<$ty>(
117 $crate::high::call::CodePtr($fun as *mut _),
118 &[$($crate::high::call::arg(&$arg)),*])
119 };
120
121 { $fun:ident ( $( $arg:expr ),* ) -> $ty:ty }
122 =>
123 { ffi_call!{ ($fun)($($arg),*) -> $ty } };
124
125 { ( $fun:expr ) ( $( $arg:expr ),* ) }
126 =>
127 { ffi_call!{ ($fun)($(arg),*) -> () } };
128
129 { $fun:ident ( $( $arg:expr ),* ) }
130 =>
131 { ffi_call!{ ($fun)($($arg),*) -> () } };
132
133}
134