use std::any::Any;
use std::os::raw::c_void;
use std::marker::PhantomData;
use low;
pub use low::{Callback, CallbackMut, CodePtr,
ffi_abi as FfiAbi, ffi_abi_FFI_DEFAULT_ABI};
#[cfg(not(feature = "unique"))]
mod util;
mod types;
pub use self::types::Type;
mod builder;
pub use self::builder::Builder;
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Arg(*mut c_void);
impl Arg {
pub fn new<T>(r: &T) -> Self {
Arg(r as *const T as *mut c_void)
}
}
pub fn arg<T>(r: &T) -> Arg {
Arg::new(r)
}
#[derive(Debug)]
pub struct Cif {
cif: low::ffi_cif,
args: types::TypeArray,
result: Type,
}
impl Clone for Cif {
fn clone(&self) -> Self {
let mut copy = Cif {
cif: self.cif,
args: self.args.clone(),
result: self.result.clone(),
};
copy.cif.arg_types = copy.args.as_raw_ptr();
copy.cif.rtype = copy.result.as_raw_ptr();
copy
}
}
impl Cif {
pub fn new<I>(args: I, result: Type) -> Self
where I: ExactSizeIterator<Item=Type>
{
let nargs = args.len();
let args = types::TypeArray::new(args);
let mut cif: low::ffi_cif = Default::default();
unsafe {
low::prep_cif(&mut cif,
low::ffi_abi_FFI_DEFAULT_ABI,
nargs,
result.as_raw_ptr(),
args.as_raw_ptr())
}.expect("low::prep_cif");
Cif {
cif: cif,
args: args,
result: result,
}
}
pub unsafe fn call<R>(&self, fun: CodePtr, args: &[Arg]) -> R {
use std::mem;
assert!(self.cif.nargs as usize == args.len(),
"Cif::call: passed wrong number of arguments");
low::call::<R>(&self.cif as *const _ as *mut _,
fun,
mem::transmute::<*const Arg,
*mut *mut c_void>(args.as_ptr()))
}
pub fn set_abi(&mut self, abi: FfiAbi) {
self.cif.abi = abi;
}
pub fn as_raw_ptr(&self) -> *mut low::ffi_cif {
&self.cif as *const _ as *mut _
}
}
#[derive(Debug)]
pub struct Closure<'a> {
_cif: Box<Cif>,
alloc: *mut ::low::ffi_closure,
code: CodePtr,
_marker: PhantomData<&'a ()>,
}
impl<'a> Drop for Closure<'a> {
fn drop(&mut self) {
unsafe {
low::closure_free(self.alloc);
}
}
}
impl<'a> Closure<'a> {
pub fn new<U, R>(cif: Cif,
callback: Callback<U, R>,
userdata: &'a U) -> Self
{
let cif = Box::new(cif);
let (alloc, code) = low::closure_alloc();
unsafe {
low::prep_closure(alloc,
cif.as_raw_ptr(),
callback,
userdata as *const U,
code).unwrap();
}
Closure {
_cif: cif,
alloc: alloc,
code: code,
_marker: PhantomData,
}
}
pub fn new_mut<U, R>(cif: Cif,
callback: CallbackMut<U, R>,
userdata: &'a mut U) -> Self
{
let cif = Box::new(cif);
let (alloc, code) = low::closure_alloc();
unsafe {
low::prep_closure_mut(alloc,
cif.as_raw_ptr(),
callback,
userdata as *mut U,
code).unwrap();
}
Closure {
_cif: cif,
alloc: alloc,
code: code,
_marker: PhantomData,
}
}
pub fn code_ptr(&self) -> &unsafe extern "C" fn() {
self.code.as_fun()
}
}
pub type CallbackOnce<U, R> = CallbackMut<Option<U>, R>;
#[derive(Debug)]
pub struct ClosureOnce {
alloc: *mut ::low::ffi_closure,
code: CodePtr,
_cif: Box<Cif>,
_userdata: Box<Any>,
}
impl Drop for ClosureOnce {
fn drop(&mut self) {
unsafe {
low::closure_free(self.alloc);
}
}
}
impl ClosureOnce {
pub fn new<U: Any, R>(cif: Cif,
callback: CallbackOnce<U, R>,
userdata: U)
-> Self
{
let cif = Box::new(cif);
let userdata = Box::new(Some(userdata)) as Box<Any>;
let (alloc, code) = low::closure_alloc();
assert!(!alloc.is_null(), "closure_alloc: returned null");
{
let borrow = userdata.downcast_ref::<Option<U>>().unwrap();
unsafe {
low::prep_closure_mut(alloc,
cif.as_raw_ptr(),
callback,
borrow as *const _ as *mut _,
code).unwrap();
}
}
ClosureOnce {
alloc: alloc,
code: code,
_cif: cif,
_userdata: userdata,
}
}
pub fn code_ptr(&self) -> &unsafe extern "C" fn() {
self.code.as_fun()
}
}
#[cfg(test)]
mod test {
use low;
use super::*;
use std::mem;
use std::os::raw::c_void;
#[test]
fn call() {
let cif = Cif::new(vec![Type::i64(), Type::i64()].into_iter(),
Type::i64());
let f = |m: i64, n: i64| -> i64 {
unsafe { cif.call(CodePtr(add_it as *mut c_void),
&[arg(&m), arg(&n)]) }
};
assert_eq!(12, f(5, 7));
assert_eq!(13, f(6, 7));
assert_eq!(15, f(8, 7));
}
extern "C" fn add_it(n: i64, m: i64) -> i64 {
return n + m;
}
#[test]
fn closure() {
let cif = Cif::new(vec![Type::u64()].into_iter(), Type::u64());
let env: u64 = 5;
let closure = Closure::new(cif, callback, &env);
unsafe {
let fun: &unsafe extern "C" fn(u64) -> u64
= mem::transmute(closure.code_ptr());
assert_eq!(11, fun(6));
assert_eq!(12, fun(7));
}
}
unsafe extern "C" fn callback(_cif: &low::ffi_cif,
result: &mut u64,
args: *const *const c_void,
userdata: &u64)
{
let args: *const &u64 = mem::transmute(args);
*result = **args + *userdata;
}
#[test]
fn rust_lambda() {
let cif = Cif::new(vec![Type::u64(), Type::u64()].into_iter(),
Type::u64());
let env = |x: u64, y: u64| x + y;
let closure = Closure::new(cif, callback2, &env);
unsafe {
let fun: &unsafe extern "C" fn (u64, u64) -> u64
= mem::transmute(closure.code_ptr());
assert_eq!(11, fun(5, 6));
}
}
unsafe extern "C" fn callback2<F: Fn(u64, u64) -> u64>
(_cif: &low::ffi_cif,
result: &mut u64,
args: *const *const c_void,
userdata: &F)
{
let args: *const &u64 = mem::transmute(args);
let arg1 = **args.offset(0);
let arg2 = **args.offset(1);
*result = userdata(arg1, arg2);
}
}