deno_libffi/high/
call.rs

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 deno_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::marker::PhantomData;
21
22use crate::middle;
23pub use middle::CodePtr;
24
25/// Encapsulates an argument with its type information.
26///
27/// In order to set up calls using [`call`](index.html#method.call), we
28/// need to wrap (a reference to) each argument in an `Arg`. The usual
29/// way to do this is with function [`arg`](fn.arg.html).
30#[derive(Clone, Debug)]
31pub struct Arg<'a> {
32    // There should be some type T such that type_ is the middle-layer
33    // value of Type<T> and value is T::reify().
34    type_: middle::Type,
35    value: middle::Arg,
36    _marker: PhantomData<&'a ()>,
37}
38
39impl<'a> Arg<'a> {
40    /// Wraps an argument reference for passing to `high::call::call`.
41    ///
42    /// For a shorter alias of the same, see
43    /// [`high::call::arg`](fn.arg.html).
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`](struct.Arg.html) for passing to
54/// [`call`](fn.call.html).
55pub fn arg<T: super::CType>(arg: &T) -> Arg {
56    Arg::new(arg)
57}
58
59/// Performs a dynamic call to a C function.
60///
61/// To reduce boilerplate, see [`ffi_call!`](../../macro.ffi_call!.html).
62///
63/// # Examples
64///
65/// ```
66/// extern "C" fn hypot(x: f32, y: f32) -> f32 {
67///     (x * x + y * y).sqrt()
68/// }
69///
70/// use deno_libffi::high::call::*;
71///
72/// let result = unsafe {
73///     call::<f32>(CodePtr(hypot as *mut _), &[arg(&3f32), arg(&4f32)])
74/// };
75///
76/// assert!((result - 5f32).abs() < 0.0001);
77/// ```
78pub unsafe fn call<R: super::CType>(fun: CodePtr, args: &[Arg]) -> R {
79    let types = args.iter().map(|arg| arg.type_.clone());
80    let cif = middle::Cif::new(types, R::reify().into_middle());
81
82    let values = args.iter().map(|arg| arg.value.clone()).collect::<Vec<_>>();
83    cif.call(fun, &values)
84}
85
86/// Performs a dynamic call to a C function.
87///
88/// This macro provides sugar for `call::arg` and `call::call`. For more
89/// control, see [`high::call::call`](high/call/fn.call.html).
90///
91/// # Examples
92///
93/// ```
94/// extern "C" fn hypot(x: f32, y: f32) -> f32 {
95///     (x * x + y * y).sqrt()
96/// }
97///
98/// use deno_libffi::ffi_call;
99///
100/// let result = unsafe { ffi_call!{ hypot(3f32, 4f32) -> f32 } };
101///
102/// assert!((result - 5f32).abs() < 0.0001);
103/// ```
104#[macro_export]
105macro_rules! ffi_call {
106
107    { ( $fun:expr ) ( $( $arg:expr ),* ) -> $ty:ty }
108    =>
109    {
110        $crate::high::call::call::<$ty>(
111            $crate::high::call::CodePtr($fun as *mut _),
112            &[$($crate::high::call::arg(&$arg)),*])
113    };
114
115    { $fun:ident ( $( $arg:expr ),* ) -> $ty:ty }
116    =>
117    { ffi_call!{ ($fun)($($arg),*) -> $ty } };
118
119    { ( $fun:expr ) ( $( $arg:expr ),* ) }
120    =>
121    { ffi_call!{ ($fun)($(arg),*) -> () } };
122
123    { $fun:ident ( $( $arg:expr ),* ) }
124    =>
125    { ffi_call!{ ($fun)($($arg),*) -> () } };
126
127}