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
//! 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()
//! }
//!
//! use libffi::ffi_call;
//!
//! let result = unsafe { ffi_call!{ hypot(3f32, 4f32) -> f32 } };
//!
//! assert!((result - 5f32).abs() < 0.0001);
//! ```

use std::marker::PhantomData;

use crate::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.iter().map(|arg| arg.type_.clone());
    let cif = middle::Cif::new(types, R::reify().into_middle());

    let values = args.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()
/// }
///
/// use libffi::ffi_call;
///
/// 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),*) -> () } };

}