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
//! Simple dynamic calls.
//!
//! This API allows us to call a code pointer with an array of
//! arguments, using libffi to set up the call.
//!
//! # Examples
//!
//! ```
//! extern "C" fn hypot(x: f32, y: f32) -> f32 {
//!     (x * x + y * y).sqrt()
//! }
//!
//! # #[macro_use] extern crate libffi;
//! # fn main() {
//! let result = unsafe { ffi_call!{ hypot(3f32, 4f32) -> f32 } };
//!
//! assert!((result - 5f32).abs() < 0.0001);
//! # }
//! ```

use std::marker::PhantomData;

use middle;
pub use middle::CodePtr;

/// Encapsulates an argument with its type information.
///
/// In order to set up calls using [`call`](index.html#method.call), we
/// need to wrap (a reference to) each argument in an `Arg`. The usual
/// way to do this is with function [`arg`](fn.arg.html).
#[derive(Clone, Debug)]
pub struct Arg<'a> {
    // There should be some type T such that type_ is the middle-layer
    // value of Type<T> and value is T::reify().
    type_: middle::Type,
    value: middle::Arg,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Arg<'a> {
    /// Wraps an argument reference for passing to `high::call::call`.
    ///
    /// For a shorter alias of the same, see
    /// [`high::call::arg`](fn.arg.html).
    pub fn new<T: super::CType>(arg: &'a T) -> Self {
        Arg {
            type_: T::reify().into_middle(),
            value: middle::Arg::new(arg),
            _marker: PhantomData,
        }
    }
}

/// Constructs an [`Arg`](struct.Arg.html) for passing to
/// [`call`](fn.call.html).
pub fn arg<T: super::CType>(arg: &T) -> Arg {
    Arg::new(arg)
}

/// Performs a dynamic call to a C function.
///
/// To reduce boilerplate, see [`ffi_call!`](../../macro.ffi_call!.html).
///
/// # Examples
///
/// ```
/// extern "C" fn hypot(x: f32, y: f32) -> f32 {
///     (x * x + y * y).sqrt()
/// }
///
/// use libffi::high::call::*;
///
/// let result = unsafe {
///     call::<f32>(CodePtr(hypot as *mut _), &[arg(&3f32), arg(&4f32)])
/// };
///
/// assert!((result - 5f32).abs() < 0.0001);
/// ```
pub unsafe fn call<R: super::CType>(fun: CodePtr, args: &[Arg]) -> R {
    let types = args.into_iter().map(|arg| arg.type_.clone());
    let cif = middle::Cif::new(types, R::reify().into_middle());

    let values = args.into_iter().map(|arg| arg.value.clone())
                     .collect::<Vec<_>>();
    cif.call(fun, &values)
}

/// Performs a dynamic call to a C function.
///
/// This macro provides sugar for `call::arg` and `call::call`. For more
/// control, see [`high::call::call`](high/call/fn.call.html).
///
/// # Examples
///
/// ```
/// extern "C" fn hypot(x: f32, y: f32) -> f32 {
///     (x * x + y * y).sqrt()
/// }
///
/// # #[macro_use] extern crate libffi;
/// # fn main() {
/// let result = unsafe { ffi_call!{ hypot(3f32, 4f32) -> f32 } };
///
/// assert!((result - 5f32).abs() < 0.0001);
/// # }
/// ```
#[macro_export]
macro_rules! ffi_call {

    { ( $fun:expr ) ( $( $arg:expr ),* ) -> $ty:ty }
    =>
    {
        $crate::high::call::call::<$ty>(
            $crate::high::call::CodePtr($fun as *mut _),
            &[$($crate::high::call::arg(&$arg)),*])
    };

    { $fun:ident ( $( $arg:expr ),* ) -> $ty:ty }
    =>
    { ffi_call!{ ($fun)($($arg),*) -> $ty } };

    { ( $fun:expr ) ( $( $arg:expr ),* ) }
    =>
    { ffi_call!{ ($fun)($(arg),*) -> () } };

    { $fun:ident ( $( $arg:expr ),* ) }
    =>
    { ffi_call!{ ($fun)($($arg),*) -> () } };

}