extern crate libc;
use dim4::Dim4;
use defines::{AfError, DType, Backend};
use error::HANDLE_ERROR;
use util::{AfArray, DimT, HasAfEnum, MutAfArray, MutVoidPtr};
use self::libc::{c_void, c_int, c_uint, c_longlong, c_char};
use std::marker::PhantomData;
use std::ffi::CString;
#[allow(dead_code)]
extern {
fn af_create_array(out: MutAfArray, data: *const c_void,
ndims: c_uint, dims: *const DimT, aftype: c_uint) -> c_int;
fn af_create_handle(out: MutAfArray, ndims: c_uint, dims: *const DimT, aftype: c_uint) -> c_int;
fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int;
fn af_get_type(out: *mut c_uint, arr: AfArray) -> c_int;
fn af_get_dims(dim0: *mut c_longlong, dim1: *mut c_longlong, dim2: *mut c_longlong,
dim3: *mut c_longlong, arr: AfArray) -> c_int;
fn af_get_numdims(result: *mut c_uint, arr: AfArray) -> c_int;
fn af_is_empty(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_scalar(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_row(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_column(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_vector(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_complex(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_real(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_double(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_single(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_realfloating(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_floating(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_integer(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_bool(result: *mut c_int, arr: AfArray) -> c_int;
fn af_get_data_ptr(data: *mut c_void, arr: AfArray) -> c_int;
fn af_eval(arr: AfArray) -> c_int;
fn af_eval_multiple(num: c_int, arrays: *const AfArray) -> c_int;
fn af_set_manual_eval_flag(flag: c_int) -> c_int;
fn af_get_manual_eval_flag(flag: *mut c_int) -> c_int;
fn af_retain_array(out: MutAfArray, arr: AfArray) -> c_int;
fn af_copy_array(out: MutAfArray, arr: AfArray) -> c_int;
fn af_release_array(arr: AfArray) -> c_int;
fn af_print_array(arr: AfArray) -> c_int;
fn af_print_array_gen(exp: *const c_char, arr: AfArray, precision: c_int) -> c_int;
fn af_cast(out: MutAfArray, arr: AfArray, aftype: c_uint) -> c_int;
fn af_get_backend_id(backend: *mut c_uint, input: AfArray) -> c_int;
fn af_get_device_id(device: *mut c_int, input: AfArray) -> c_int;
fn af_create_strided_array(arr: MutAfArray, data: *const c_void, offset: DimT,
ndims: c_uint, dims: *const DimT, strides: *const DimT,
aftype: c_uint, stype: c_uint) -> c_int;
fn af_get_strides(s0: *mut DimT, s1: *mut DimT, s2: *mut DimT, s3: *mut DimT,
arr: AfArray) -> c_int;
fn af_get_offset(offset: *mut DimT, arr: AfArray) -> c_int;
fn af_is_linear(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_owner(result: *mut c_int, arr: AfArray) -> c_int;
fn af_is_sparse(result: *mut c_int, arr: AfArray) -> c_int;
fn af_lock_array(arr: AfArray) -> c_int;
fn af_unlock_array(arr: AfArray) -> c_int;
fn af_get_device_ptr(ptr: MutVoidPtr, arr: AfArray) -> c_int;
fn af_get_allocated_bytes(result: *mut usize, arr: AfArray) -> c_int;
}
pub struct Array<T: HasAfEnum> {
handle: i64,
_marker: PhantomData<T>,
}
macro_rules! is_func {
($doc_str: expr, $fn_name: ident, $ffi_fn: ident) => (
#[doc=$doc_str]
pub fn $fn_name(&self) -> bool {
unsafe {
let mut ret_val: i32 = 0;
let err_val = $ffi_fn(&mut ret_val as *mut c_int, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val>0
}
}
)
}
impl<T> Array<T> where T: HasAfEnum {
#[allow(unused_mut)]
pub fn new(slice: &[T], dims: Dim4) -> Array<T> {
let aftype = T::get_af_dtype();
let mut temp: i64 = 0;
unsafe {
let err_val = af_create_array(&mut temp as MutAfArray,
slice.as_ptr() as *const c_void,
dims.ndims() as c_uint,
dims.get().as_ptr() as * const c_longlong,
aftype as c_uint);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn new_strided(slice: &[T], offset: i64,
dims: Dim4, strides: Dim4) -> Array<T> {
let aftype = T::get_af_dtype();
let mut temp: i64 = 0;
unsafe {
let err_val = af_create_strided_array(&mut temp as MutAfArray,
slice.as_ptr() as *const c_void,
offset as DimT,
dims.ndims() as c_uint,
dims.get().as_ptr() as * const c_longlong,
strides.get().as_ptr() as * const c_longlong,
aftype as c_uint, 1 as c_uint);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn new_empty(dims: Dim4) -> Array<T> {
let aftype = T::get_af_dtype();
unsafe {
let mut temp: i64 = 0;
let err_val = af_create_handle(&mut temp as MutAfArray,
dims.ndims() as c_uint,
dims.get().as_ptr() as * const c_longlong,
aftype as c_uint);
HANDLE_ERROR(AfError::from(err_val));
temp.into()
}
}
pub fn get_backend(&self) -> Backend {
unsafe {
let mut ret_val: u32 = 0;
let err_val = af_get_backend_id(&mut ret_val as *mut c_uint, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
match (err_val, ret_val) {
(0, 1) => Backend::CPU,
(0, 2) => Backend::CUDA,
(0, 3) => Backend::OPENCL,
_ => Backend::DEFAULT,
}
}
}
pub fn get_device_id(&self) -> i32 {
unsafe {
let mut ret_val: i32 = 0;
let err_val = af_get_device_id(&mut ret_val as *mut c_int, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val
}
}
pub fn elements(&self) -> usize {
unsafe {
let mut ret_val: i64 = 0;
let err_val = af_get_elements(&mut ret_val as MutAfArray, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val as usize
}
}
pub fn get_type(&self) -> DType {
unsafe {
let mut ret_val: u32 = 0;
let err_val = af_get_type(&mut ret_val as *mut c_uint, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
DType::from(ret_val)
}
}
pub fn dims(&self) -> Dim4 {
unsafe {
let mut ret0: i64 = 0;
let mut ret1: i64 = 0;
let mut ret2: i64 = 0;
let mut ret3: i64 = 0;
let err_val = af_get_dims(&mut ret0 as *mut DimT, &mut ret1 as *mut DimT,
&mut ret2 as *mut DimT, &mut ret3 as *mut DimT,
self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])
}
}
pub fn strides(&self) -> Dim4 {
unsafe {
let mut ret0: i64 = 0;
let mut ret1: i64 = 0;
let mut ret2: i64 = 0;
let mut ret3: i64 = 0;
let err_val = af_get_strides(&mut ret0 as *mut DimT, &mut ret1 as *mut DimT,
&mut ret2 as *mut DimT, &mut ret3 as *mut DimT,
self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])
}
}
pub fn numdims(&self) -> u32 {
unsafe {
let mut ret_val: u32 = 0;
let err_val = af_get_numdims(&mut ret_val as *mut c_uint, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val
}
}
pub fn offset(&self) -> i64 {
unsafe {
let mut ret_val: i64 = 0;
let err_val = af_get_offset(&mut ret_val as *mut DimT, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
ret_val
}
}
pub fn get(&self) -> i64 {
self.handle
}
pub fn host<O: HasAfEnum>(&self, data: &mut [O]) {
if data.len() != self.elements() {
HANDLE_ERROR(AfError::ERR_SIZE);
}
unsafe {
let err_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn eval(&self) {
unsafe {
let err_val = af_eval(self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn copy(&self) -> Array<T> {
unsafe {
let mut temp: i64 = 0;
let err_val = af_copy_array(&mut temp as MutAfArray, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp.into()
}
}
is_func!("Check if Array is empty", is_empty, af_is_empty);
is_func!("Check if Array is scalar", is_scalar, af_is_scalar);
is_func!("Check if Array is a row", is_row, af_is_row);
is_func!("Check if Array is a column", is_column, af_is_column);
is_func!("Check if Array is a vector", is_vector, af_is_vector);
is_func!("Check if Array is of complex type", is_complex, af_is_complex);
is_func!("Check if Array's numerical type is of double precision", is_double, af_is_double);
is_func!("Check if Array's numerical type is of single precision", is_single, af_is_single);
is_func!("Check if Array is of real type", is_real, af_is_real);
is_func!("Check if Array is of single precision", is_floating, af_is_floating);
is_func!("Check if Array is of integral type", is_integer, af_is_integer);
is_func!("Check if Array is of boolean type", is_bool, af_is_bool);
is_func!("Check if Array's memory layout is continuous and one dimensional", is_linear, af_is_linear);
is_func!("Check if Array's memory is owned by it and not a view of another Array", is_owner, af_is_owner);
pub fn cast<O: HasAfEnum>(&self) -> Array<O> {
let trgt_type = O::get_af_dtype();
let mut temp: i64 = 0;
unsafe {
let err_val = af_cast(&mut temp as MutAfArray, self.handle as AfArray, trgt_type as c_uint);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
pub fn is_sparse(&self) -> bool {
unsafe {
let mut temp: i32 = 0;
let err_val = af_is_sparse(&mut temp as *mut c_int, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp > 0
}
}
pub fn lock(&self) {
unsafe {
let err_val = af_lock_array(self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn unlock(&self) {
unsafe {
let err_val = af_unlock_array(self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn device_ptr(&self) -> u64 {
unsafe {
let mut temp: u64 = 0;
let err_val = af_get_device_ptr(&mut temp as MutVoidPtr, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
pub fn get_allocated_bytes(&self) -> usize {
unsafe {
let mut temp: usize = 0;
let err_val = af_get_allocated_bytes(&mut temp as *mut usize, self.handle as AfArray);
HANDLE_ERROR(AfError::from(err_val));
temp
}
}
}
impl<T: HasAfEnum> Into<Array<T>> for i64 {
fn into(self) -> Array<T> {
Array {handle: self, _marker: PhantomData}
}
}
impl<T> Clone for Array<T> where T: HasAfEnum {
fn clone(&self) -> Array<T> {
unsafe {
let mut temp: i64 = 0;
let ret_val = af_retain_array(&mut temp as MutAfArray, self.handle as AfArray);
match ret_val {
0 => temp.into(),
_ => panic!("Weak copy of Array failed with error code: {}", ret_val),
}
}
}
}
impl<T> Drop for Array<T> where T: HasAfEnum {
fn drop(&mut self) {
unsafe {
let ret_val = af_release_array(self.handle);
match ret_val {
0 => (),
_ => panic!("Array<T> drop failed with error code: {}", ret_val),
}
}
}
}
pub fn print<T: HasAfEnum>(input: &Array<T>) {
let emptystring = CString::new("").unwrap();
unsafe {
let err_val = af_print_array_gen(emptystring.to_bytes_with_nul().as_ptr() as *const c_char,
input.get() as AfArray, 4);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn print_gen<T: HasAfEnum>(msg: String, input: &Array<T>, precision: Option<i32>) {
let emptystring = CString::new(msg.as_bytes()).unwrap();
unsafe {
let err_val = af_print_array_gen(emptystring.to_bytes_with_nul().as_ptr() as *const c_char,
input.get() as AfArray,
match precision {Some(p)=>p, None=>4} as c_int);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn eval_multiple<T: HasAfEnum>(inputs: Vec<&Array<T>>) {
unsafe {
let mut v = Vec::new();
for i in inputs {
v.push(i.get());
}
let err_val = af_eval_multiple(v.len() as c_int, v.as_ptr() as *const AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn set_manual_eval(flag: bool) {
unsafe {
let err_val = af_set_manual_eval_flag(flag as c_int);
HANDLE_ERROR(AfError::from(err_val));
}
}
pub fn is_eval_manual() -> bool {
unsafe {
let mut ret_val: i32 = 0;
let err_val = af_get_manual_eval_flag(&mut ret_val as *mut c_int);
HANDLE_ERROR(AfError::from(err_val));
ret_val > 0
}
}