diff --git a/Cargo.toml b/Cargo.toml index 93fd8e562..3950700d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "arrayfire" description = "ArrayFire is a high performance software library for parallel computing with an easy-to-use API. Its array based function set makes parallel programming simple. ArrayFire's multiple backends (CUDA, OpenCL and native CPU) make it platform independent and highly portable. A few lines of code in ArrayFire can replace dozens of lines of parallel computing code, saving you valuable time and lowering development costs. This crate provides Rust bindings for ArrayFire library." -version = "3.2.0" +version = "3.3.2" documentation = "http://arrayfire.github.io/arrayfire-rust/arrayfire/index.html" homepage = "https://github.com/arrayfire/arrayfire" repository = "https://github.com/arrayfire/arrayfire-rust" @@ -10,14 +10,18 @@ readme = "./README.md" keywords = ["CUDA", "OpenCL", "ArrayFire", "Compute"] license = "BSD-3-Clause" build = "build.rs" +exclude = [ + "arrayfire/*", +] [dependencies] -libc = "0.1.10" -num = "0.1.27" -time = "0.1.32" +libc = "0.2.11" +num = "0.1.32" +lazy_static = "0.2.1" -[build-dependencies.rustc-serialize] -rustc-serialize = "0.3.16" +[build-dependencies] +rustc-serialize = "0.3.19" +rustc_version = "0.1.7" [lib] name = "arrayfire" diff --git a/README.md b/README.md index 381f883e4..a55cf2315 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -# Arrayfire Rust Bindings +# Arrayfire Rust Bindings [![Join the chat at https://gitter.im/arrayfire/arrayfire-rust](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/arrayfire/arrayfire-rust?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +| Linux | Windows | OSX | +|:-------:|:-------:|:---:| +| [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-linux)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-linux/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-windows)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-windows/) | [![Build Status](http://ci.arrayfire.org/buildStatus/icon?job=arrayfire-wrappers/rust-osx)](http://ci.arrayfire.org/view/All/job/arrayfire-wrappers/job/rust-osx/) | -[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Rust bindings for the ArrayFire library. The wrapper is currently compliant with ArrayFire 3.2 API. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues). +[ArrayFire](https://github.com/arrayfire/arrayfire) is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific computing code that is portable across CUDA, OpenCL and CPU devices. This project provides Rust bindings for the ArrayFire library. The wrapper is currently compliant with ArrayFire 3.3 API. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues). ## Documentation @@ -13,6 +16,9 @@ You can find the most recent updated documentation [here](http://arrayfire.githu We recommend using Rust 1.5 and higher. +Rust 1.8 stabilized the traits for compound assignment operations. These are automatically enabled +based on the rust version you are using. + ## Use from Crates.io [![](http://meritbadge.herokuapp.com/arrayfire)](https://crates.io/crates/arrayfire) To use the rust bindings for ArrayFire from crates.io, the following requirements are to be met @@ -24,7 +30,7 @@ first. 3. Make sure you add the path to library files to your path environment variables. - On Linux & OSX: do `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib` - On Windows: Add `%AF_PATH%\lib` to your PATH environment variable. -4. Add `arrayfire = "3.2.0"` to the dependencies section of your project's Cargo.toml file. +4. Add `arrayfire = "3.3.2"` to the dependencies section of your project's Cargo.toml file. Once step (4) is over, you should be able to use ArrayFire in your Rust project. If you find any bugs, please report them [here](https://github.com/arrayfire/arrayfire-rust/issues). @@ -80,20 +86,6 @@ Create a 5-by-3 matrix of random floats on the GPU ... ``` -## Issues - -You might see something along the lines of : - -```bash -dyld: Library not loaded: @rpath/libafopencl.3.dylib -``` - -You need to add the location of libaf.{dylib, so, dll} to your LD_LIBRARY_PATH. - -## Note - -This is a work in progress and is not intended for production use. - ## Acknowledgements The ArrayFire library is written by developers at [ArrayFire](http://arrayfire.com) LLC diff --git a/arrayfire b/arrayfire index f263db079..5842ed251 160000 --- a/arrayfire +++ b/arrayfire @@ -1 +1 @@ -Subproject commit f263db079443f7818a73ee94e237dd53ef017d01 +Subproject commit 5842ed25195848653148fa9b3a8270255d83f5b8 diff --git a/build.rs b/build.rs index b45c5e5ad..3a4df9cca 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,6 @@ /* -- Lots of reuse from: https://github.com/alexcrichton/git2-rs/blob/master/libgit2-sys/build.rs */ extern crate rustc_serialize; +extern crate rustc_version; use std::env; use std::fs; @@ -450,4 +451,8 @@ fn main() { for backend_dir in backend_dirs.iter() { println!("cargo:rustc-link-search=native={}", backend_dir); } + // Directly check a semver version requirment + if rustc_version::version_matches(">= 1.8.0") { + println!("cargo:rustc-cfg=op_assign"); + } } diff --git a/examples/helloworld.rs b/examples/helloworld.rs index 6ed726019..be21558cd 100644 --- a/examples/helloworld.rs +++ b/examples/helloworld.rs @@ -1,3 +1,4 @@ +#[macro_use(af_print)] extern crate arrayfire as af; use af::*; @@ -9,79 +10,64 @@ fn main() { let num_rows: u64 = 5; let num_cols: u64 = 3; - let values: &[f32] = &[1.0, 2.0, 3.0]; - let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); + let values: [f32; 3] = [1.0, 2.0, 3.0]; + let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); let dims = Dim4::new(&[num_rows, num_cols, 1, 1]); - println!("Create a 5-by-3 matrix of random floats on the GPU"); - let a = match randu(dims, Aftype::F32) { - Ok(value) => value, - Err(error) => panic!("{}", error), - }; - print(&a); + let a = randu::(dims); + af_print!("Create a 5-by-3 matrix of random floats on the GPU", a); println!("Element-wise arithmetic"); - let b = sin(&a) - .and_then(|x| add(&x, &1.5, false)) - .unwrap(); + let b = add(&sin(&a), &1.5f32, false); - let b2 = sin(&a). - and_then(|x| { - cos(&a) - .and_then(|y| add(&x, &y, false)) - }) - .unwrap(); + let b2 = add(&sin(&a), &cos(&a), false); let b3 = ! &a; - println!("sin(a) + 1.5 => "); print(&b); - println!("sin(a) + cos(a) => "); print(&b2); - println!("!a => "); print(&b3); + af_print!("sin(a) + 1.5 => ", b); + af_print!("sin(a) + cos(a) => ", b2); + af_print!("!a => ", b3); - let test = &a + &b; - println!("a + b"); print(&test); + let test = a.clone() + b.clone(); + af_print!("a + b", test); // Index array using sequences - let seqs = &[Seq::new(1.0, 3.0, 1.0), Seq::default()]; - let sub = index(&a, seqs).unwrap(); - println!("a(seq(1,3,1), span)"); print(&sub); + let seqs = &[Seq::new(1u32, 3, 1), Seq::default()]; + let sub = index(&a, seqs); + af_print!("a(seq(1,3,1), span)", sub); //Index array using array and sequence - let seq4gen = Seq::new(0.0, 2.0, 1.0); + let seq4gen = Seq::new(0u32, 2, 1); - let mut idxrs = match Indexer::new() { - Ok(v) => v, - Err(e) => panic!("{}",e), - }; + let mut idxrs = Indexer::new(); idxrs.set_index(&indices, 0, None); idxrs.set_index(&seq4gen, 1, Some(false)); - let sub2 = index_gen(&a, idxrs).unwrap(); - println!("a(indices, seq(0, 2, 1))"); print(&sub2); + let sub2 = index_gen(&a, idxrs); + af_print!("a(indices, seq(0, 2, 1))", sub2); // printf("Negate the first three elements of second column\n"); // B(seq(0, 2), 1) = B(seq(0, 2), 1) * -1; // af_print(B); println!("Fourier transform the result"); - fft(&b, 1.0, 0).map(|x| print(&x)); + print(&fft(&b, 1.0, 0)); println!("Grab last row & col of the random matrix"); print(&a); - print(&row(&a, num_rows - 1).unwrap()); - print(&col(&a, num_cols - 1).unwrap()); + print(&row(&a, num_rows - 1)); + print(&col(&a, num_cols - 1)); - println!("Set last row to 1's"); let r_dims = Dim4::new(&[3, 1, 1, 1]); let r_input: [f32; 3] = [1.0, 1.0, 1.0]; - let r = Array::new(r_dims, &r_input, Aftype::F32).unwrap(); - print(&set_row(&a, &r, num_rows - 1).unwrap()); + let r = Array::new(&r_input, r_dims); + let ur = set_row(&a, &r, num_rows - 1); + af_print!("Set last row to 1's", ur); - println!("Create 2-by-3 matrix from host data"); let d_dims = Dim4::new(&[2, 3, 1, 1]); let d_input: [i32; 6] = [1, 2, 3, 4, 5, 6]; - let d = &Array::new(d_dims, &d_input, Aftype::S32).unwrap(); - print(d); + let d = Array::new(&d_input, d_dims); + af_print!("Create 2-by-3 matrix from host data", d); // printf("Copy last column onto first\n"); // D.col(0) = D.col(end); @@ -89,14 +75,11 @@ fn main() { // // Sort A println!("Sort A and print sorted array and corresponding indices"); - sort_index(&a, 0, true) - .map(| x | { - print(&x.0); - print(&x.1); - }); - - println!("u8 constant array"); - let u8_cnst = &constant(1 as u8, dims).unwrap(); - print(u8_cnst); - println!("Is u8_cnst array float precision type ? {}", u8_cnst.is_single().unwrap()); + let x = sort_index(&a, 0, true); + print(&x.0); + print(&x.1); + + let u8_cnst = &constant(1 as u8, dims); + af_print!("u8 constant array", u8_cnst); + println!("Is u8_cnst array float precision type ? {}", u8_cnst.is_single()); } diff --git a/examples/histogram.rs b/examples/histogram.rs index 5a32b6820..e17f243b5 100644 --- a/examples/histogram.rs +++ b/examples/histogram.rs @@ -13,34 +13,22 @@ fn main() { let assets_dir = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap()) .join("arrayfire").join("assets").join("examples").join("images"); - let img_wnd = match Window::new(480, 640, String::from("Input Image")) { - Ok(v) => { v.set_position(100, 100).unwrap(); v }, - Err(e)=> panic!("Window creation failed, exiting: {}", e), - }; - - let hst_wnd = match Window::new(512, 512, String::from("Input Image Histogram")) { - Ok(v) => { v.set_position(600, 100).unwrap(); v }, - Err(e)=> panic!("Window creation failed, exiting: {}", e), - }; - - let (man, hst) = match load_image(format!("{}/man.jpg", assets_dir.display()), false) { - Ok(v) => match histogram(&v, 256, 0.0, 255.0) { - Ok(h) => (v, h), - Err(e)=> panic!("Histogram computation failed, exiting: {}", e), - }, - Err(e)=> panic!("Image loading failed, exiting: {}", e), - }; - - let disp_img = man.dims() - .and_then(|x| constant(255 as f32, x)) - .and_then(|x| div(&man, &x, false)) - .unwrap(); + let img_wnd = Window::new(480, 640, String::from("Input Image")); + img_wnd.set_position(100, 100); + + let hst_wnd = Window::new(512, 512, String::from("Input Image Histogram")); + hst_wnd.set_position(600, 100); + + let man = load_image(format!("{}/man.jpg", assets_dir.display()), false); + let hst = histogram(&man, 256, 0.0, 255.0); + + let disp_img = div(&man, &constant(255 as f32, man.dims()), false); loop { img_wnd.draw_image(&disp_img, None); hst_wnd.draw_hist(&hst, 0.0, 255.0, None); - if img_wnd.is_closed().unwrap() == true { break; } - if hst_wnd.is_closed().unwrap() == true { break; } + if img_wnd.is_closed() == true { break; } + if hst_wnd.is_closed() == true { break; } } } diff --git a/examples/pi.rs b/examples/pi.rs index 9ec60d61d..5fe1c79e4 100644 --- a/examples/pi.rs +++ b/examples/pi.rs @@ -1,7 +1,7 @@ +#[macro_use(mem_info)] extern crate arrayfire as af; -extern crate time; -use time::PreciseTime; +use std::time::Instant; use af::*; #[allow(unused_must_use)] @@ -12,21 +12,24 @@ fn main() { let samples = 20_000_000; let dims = Dim4::new(&[samples, 1, 1, 1]); - let x = &randu(dims, Aftype::F32).unwrap(); - let y = &randu(dims, Aftype::F32).unwrap(); + let x = &randu::(dims); + let y = &randu::(dims); - let start = PreciseTime::now(); + let start = Instant::now(); + + mem_info!("Before benchmark"); for bench_iter in 0..100 { - let pi_val = add(&mul(x, x, false).unwrap(), &mul(y, y, false).unwrap(), false) - .and_then( |z| sqrt(&z) ) - .and_then( |z| le(&z, &constant(1, dims).unwrap(), false) ) - .and_then( |z| sum_all(&z) ) - .map( |z| z.0 * 4.0/(samples as f64) ) - .unwrap(); + let xsqrd = &mul(x, x, false); + let ysqrd = &mul(y, y, false); + let xplusy = &add(xsqrd, ysqrd, false); + let root = &sqrt(xplusy); + let cnst = &constant(1, dims); + let (real, imag) = sum_all(&le(root, cnst, false)); + let pi_val = real*4.0/(samples as f64); } - let end = PreciseTime::now(); + println!("Estimated Pi Value in {:?}", start.elapsed()); - println!("Estimated Pi Value in {} seconds", start.to(end) / 100); + mem_info!("After benchmark"); } diff --git a/examples/snow.rs b/examples/snow.rs index d812680d9..bdeb394f6 100644 --- a/examples/snow.rs +++ b/examples/snow.rs @@ -8,17 +8,13 @@ fn main() { set_device(0); info(); - let wnd = match Window::new(1280, 720, String::from("Snow")) { - Ok(v) => v, - Err(e)=> panic!("Window creation failed, exiting"), - }; + let wnd = Window::new(1280, 720, String::from("Snow")); let dims = Dim4::new(&[1280, 720, 3, 1]); loop { - randu(dims, Aftype::F32).as_ref() - .map(|arr| wnd.draw_image(arr, None)); + wnd.draw_image(&randu::(dims), None); - if wnd.is_closed().unwrap() == true { break; } + if wnd.is_closed() == true { break; } } } diff --git a/examples/unified.rs b/examples/unified.rs index 713a6f068..6ed0e0b77 100644 --- a/examples/unified.rs +++ b/examples/unified.rs @@ -2,55 +2,58 @@ extern crate arrayfire as af; use af::*; +#[cfg(op_assign)] +fn helper(dims: Dim4) { + let mut a = randu::(dims); + let b = randu::(dims); + print(&a); + print(&b); + a += b; + print(&a); +} + +#[cfg(not(op_assign))] +fn helper(dims: Dim4) { + let b = randu::(dims); + print(&b); +} + #[allow(unused_must_use)] fn test_backend(){ info(); + println!("Create a 10-by-10 matrix of random floats on the compute device"); let num_rows: u64 = 10; let num_cols: u64 = 10; let dims = Dim4::new(&[num_rows, num_cols, 1, 1]); - println!("Create a 10-by-10 matrix of random floats on the compute device"); - let a = match randu(dims, Aftype::F32) { - Ok(value) => value, - Err(error) => panic!("{}", error), - }; - print(&a); + helper(dims) } #[allow(unused_must_use)] fn main() { - println!("There are {:?} available backends", get_backend_count().unwrap()); - let available = get_available_backends().unwrap(); + println!("There are {:?} available backends", get_backend_count()); + let available = get_available_backends(); - if available.contains(&Backend::AF_BACKEND_CPU){ + if available.contains(&Backend::CPU) { println!("Evaluating CPU Backend..."); - let err = set_backend(Backend::AF_BACKEND_CPU); - println!("There are {} CPU compute devices", device_count().unwrap()); - match err { - Ok(_) => test_backend(), - Err(e) => println!("CPU backend error: {}", e), - }; + set_backend(Backend::CPU); + println!("There are {} CPU compute devices", device_count()); + test_backend(); } - if available.contains(&Backend::AF_BACKEND_CUDA){ + if available.contains(&Backend::CUDA) { println!("Evaluating CUDA Backend..."); - let err = set_backend(Backend::AF_BACKEND_CUDA); - println!("There are {} CUDA compute devices", device_count().unwrap()); - match err { - Ok(_) => test_backend(), - Err(e) => println!("CUDA backend error: {}", e), - }; + set_backend(Backend::CUDA); + println!("There are {} CUDA compute devices", device_count()); + test_backend(); } - if available.contains(&Backend::AF_BACKEND_OPENCL){ + if available.contains(&Backend::OPENCL) { println!("Evaluating OpenCL Backend..."); - let err = set_backend(Backend::AF_BACKEND_OPENCL); - println!("There are {} OpenCL compute devices", device_count().unwrap()); - match err { - Ok(_) => test_backend(), - Err(e) => println!("OpenCL backend error: {}", e), - }; + set_backend(Backend::OPENCL); + println!("There are {} OpenCL compute devices", device_count()); + test_backend(); } } diff --git a/src/algorithm/mod.rs b/src/algorithm/mod.rs index 62d3f983b..98284daed 100644 --- a/src/algorithm/mod.rs +++ b/src/algorithm/mod.rs @@ -2,6 +2,7 @@ extern crate libc; use array::Array; use defines::AfError; +use error::HANDLE_ERROR; use self::libc::{c_int, c_uint, c_double}; type MutAfArray = *mut self::libc::c_longlong; @@ -60,15 +61,13 @@ macro_rules! dim_reduce_func_def { /// /// Reduced Array #[allow(unused_mut)] - pub fn $fn_name(input: &Array, dim: i32) -> Result { + pub fn $fn_name(input: &Array, dim: i32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, input.get() as AfArray, dim as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -99,15 +98,13 @@ dim_reduce_func_def!(diff2, af_diff2); /// # Return Values /// /// Reduced Array -pub fn sum_nan(input: &Array, dim: i32, nanval: f64) -> Result { +pub fn sum_nan(input: &Array, dim: i32, nanval: f64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_sum_nan(&mut temp as MutAfArray, input.get() as AfArray, dim as c_int, nanval as c_double); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -124,15 +121,13 @@ pub fn sum_nan(input: &Array, dim: i32, nanval: f64) -> Result { /// # Return Values /// /// Reduced Array -pub fn product_nan(input: &Array, dim: i32, nanval: f64) -> Result { +pub fn product_nan(input: &Array, dim: i32, nanval: f64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_product_nan(&mut temp as MutAfArray, input.get() as AfArray, dim as c_int, nanval as c_double); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -149,16 +144,14 @@ macro_rules! all_reduce_func_def { /// A tuple of reduction result. For non-complex data type Arrays, second value of tuple is /// zero. #[allow(unused_mut)] - pub fn $fn_name(input: &Array) -> Result<(f64, f64), AfError> { + pub fn $fn_name(input: &Array) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = $ffi_name(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } ) @@ -186,16 +179,14 @@ all_reduce_func_def!(count_all, af_count_all); /// /// A tuple of reduction result. For non-complex data type Arrays, second value of tuple is /// zero. -pub fn sum_nan_all(input: &Array, val: f64) -> Result<(f64, f64), AfError> { +pub fn sum_nan_all(input: &Array, val: f64) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = af_sum_nan_all(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray, val as c_double); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } @@ -213,16 +204,14 @@ pub fn sum_nan_all(input: &Array, val: f64) -> Result<(f64, f64), AfError> { /// /// A tuple of reduction result. For non-complex data type Arrays, second value of tuple is /// zero. -pub fn product_nan_all(input: &Array, val: f64) -> Result<(f64, f64), AfError> { +pub fn product_nan_all(input: &Array, val: f64) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = af_product_nan_all(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray, val as c_double); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } @@ -241,16 +230,14 @@ macro_rules! dim_ireduce_func_def { /// /// The indices Array has the index of the result element along the reduction dimension. #[allow(unused_mut)] - pub fn $fn_name(input: &Array, dim: i32) -> Result<(Array, Array), AfError> { + pub fn $fn_name(input: &Array, dim: i32) -> (Array, Array) { unsafe { let mut temp: i64 = 0; let mut idx: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, &mut idx as MutAfArray, input.get() as AfArray, dim as c_int); - match err_val { - 0 => Ok((Array::from(temp), Array::from(idx))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(temp), Array::from(idx)) } } ) @@ -275,17 +262,15 @@ macro_rules! all_ireduce_func_def { /// /// The third value of triplet is the index of result element from reduction operation. #[allow(unused_mut)] - pub fn $fn_name(input: &Array) -> Result<(f64, f64, u32), AfError> { + pub fn $fn_name(input: &Array) -> (f64, f64, u32) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let mut temp: u32 = 0; let err_val = $ffi_name(&mut real as MutDouble, &mut imag as MutDouble, &mut temp as MutUint, input.get() as AfArray); - match err_val { - 0 => Ok((real, imag, temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag, temp) } } ) @@ -306,14 +291,12 @@ all_ireduce_func_def!(imax_all, af_imax_all); /// /// Array of indices where the input Array has non-zero values. #[allow(unused_mut)] -pub fn locate(input: &Array) -> Result { +pub fn locate(input: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_where(&mut temp as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -331,15 +314,13 @@ pub fn locate(input: &Array) -> Result { /// /// Sorted Array. #[allow(unused_mut)] -pub fn sort(input: &Array, dim: u32, ascending: bool) -> Result { +pub fn sort(input: &Array, dim: u32, ascending: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_sort(&mut temp as MutAfArray, input.get() as AfArray, - dim as c_uint, ascending as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + dim as c_uint, ascending as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -359,17 +340,15 @@ pub fn sort(input: &Array, dim: u32, ascending: bool) -> Result /// /// The second Array contains the original indices of the sorted values. #[allow(unused_mut)] -pub fn sort_index(input: &Array, dim: u32, ascending: bool) -> Result<(Array, Array), AfError> { +pub fn sort_index(input: &Array, dim: u32, ascending: bool) -> (Array, Array) { unsafe { let mut temp: i64 = 0; let mut idx: i64 = 0; let err_val = af_sort_index(&mut temp as MutAfArray, &mut idx as MutAfArray, input.get() as AfArray, dim as c_uint, ascending as c_int); - match err_val { - 0 => Ok((Array::from(temp), Array::from(idx))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(temp), Array::from(idx)) } } @@ -393,17 +372,15 @@ pub fn sort_index(input: &Array, dim: u32, ascending: bool) -> Result<(Array, Ar /// The second Array contains the sorted values. #[allow(unused_mut)] pub fn sort_by_key(keys: &Array, vals: &Array, dim: u32, - ascending: bool) -> Result<(Array, Array), AfError> { + ascending: bool) -> (Array, Array) { unsafe { let mut temp: i64 = 0; let mut temp2: i64 = 0; let err_val = af_sort_by_key(&mut temp as MutAfArray, &mut temp2 as MutAfArray, keys.get() as AfArray, vals.get() as AfArray, dim as c_uint, ascending as c_int); - match err_val { - 0 => Ok((Array::from(temp), Array::from(temp2))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(temp), Array::from(temp2)) } } @@ -418,15 +395,13 @@ pub fn sort_by_key(keys: &Array, vals: &Array, dim: u32, /// /// An Array of unique values from the input Array. #[allow(unused_mut)] -pub fn set_unique(input: &Array, is_sorted: bool) -> Result { +pub fn set_unique(input: &Array, is_sorted: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_set_unique(&mut temp as MutAfArray, input.get() as AfArray, is_sorted as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -442,15 +417,13 @@ pub fn set_unique(input: &Array, is_sorted: bool) -> Result { /// /// An Array with union of the input sets #[allow(unused_mut)] -pub fn set_union(first: &Array, second: &Array, is_unique: bool) -> Result { +pub fn set_union(first: &Array, second: &Array, is_unique: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_set_union(&mut temp as MutAfArray, first.get() as AfArray, - second.get() as AfArray, is_unique as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + second.get() as AfArray, is_unique as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -466,14 +439,12 @@ pub fn set_union(first: &Array, second: &Array, is_unique: bool) -> Result Result { +pub fn set_intersect(first: &Array, second: &Array, is_unique: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_set_intersect(&mut temp as MutAfArray, first.get() as AfArray, - second.get() as AfArray, is_unique as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + second.get() as AfArray, is_unique as c_int); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } -} +} \ No newline at end of file diff --git a/src/arith/mod.rs b/src/arith/mod.rs index 982597255..95d710cdd 100644 --- a/src/arith/mod.rs +++ b/src/arith/mod.rs @@ -4,6 +4,7 @@ extern crate num; use dim4::Dim4; use array::Array; use defines::AfError; +use error::HANDLE_ERROR; use self::libc::{c_int}; use data::{constant, tile}; use self::num::Complex; @@ -102,10 +103,9 @@ impl<'f> Not for &'f Array { fn not(self) -> Array { unsafe { let mut temp: i64 = 0; - match af_not(&mut temp as MutAfArray, self.get() as AfArray) { - 0 => Array::from(temp), - _ => panic!("Negation of Array failed, please check input"), - } + let err_val = af_not(&mut temp as MutAfArray, self.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } @@ -113,14 +113,12 @@ impl<'f> Not for &'f Array { macro_rules! unary_func { ($fn_name: ident, $ffi_fn: ident) => ( #[allow(unused_mut)] - pub fn $fn_name(input: &Array) -> Result { + pub fn $fn_name(input: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_fn(&mut temp as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -171,16 +169,14 @@ unary_func!(isnan, af_isnan); macro_rules! binary_func { ($fn_name: ident, $ffi_fn: ident) => ( #[allow(unused_mut)] - pub fn $fn_name(lhs: &Array, rhs: &Array) -> Result { + pub fn $fn_name(lhs: &Array, rhs: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_fn(&mut temp as MutAfArray, lhs.get() as AfArray, rhs.get() as AfArray, 0); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -204,7 +200,7 @@ macro_rules! convertable_type_def { ($rust_type: ty) => ( impl Convertable for $rust_type { fn convert(&self) -> Array { - constant(*self, Dim4::new(&[1,1,1,1])).unwrap() + constant(*self, Dim4::new(&[1,1,1,1])) } } ) @@ -226,29 +222,27 @@ impl Convertable for Array { macro_rules! overloaded_binary_func { ($fn_name: ident, $help_name: ident, $ffi_name: ident) => ( - fn $help_name(lhs: &Array, rhs: &Array, batch: bool) -> Result { + fn $help_name(lhs: &Array, rhs: &Array, batch: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, lhs.get() as AfArray, rhs.get() as AfArray, batch as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } - pub fn $fn_name (arg1: &T, arg2: &U, batch: bool) -> Result where T: Convertable, U: Convertable { + pub fn $fn_name (arg1: &T, arg2: &U, batch: bool) -> Array where T: Convertable, U: Convertable { let lhs = arg1.convert(); let rhs = arg2.convert(); - match (lhs.is_scalar().unwrap(), rhs.is_scalar().unwrap()) { + match (lhs.is_scalar(), rhs.is_scalar()) { ( true, false) => { - let l = tile(&lhs, rhs.dims().unwrap()).unwrap(); + let l = tile(&lhs, rhs.dims()); $help_name(&l, &rhs, batch) }, (false, true) => { - let r = tile(&rhs, lhs.dims().unwrap()).unwrap(); + let r = tile(&rhs, lhs.dims()); $help_name(&lhs, &r, batch) }, _ => $help_name(&lhs, &rhs, batch), @@ -283,14 +277,13 @@ macro_rules! arith_scalar_func { type Output = Array; fn $fn_name(self, rhs: $rust_type) -> Array { - let cnst_arr = constant(rhs, self.dims().unwrap()).unwrap(); + let cnst_arr = constant(rhs, self.dims()); unsafe { let mut temp: i64 = 0; - match $ffi_fn(&mut temp as MutAfArray, self.get() as AfArray, - cnst_arr.get() as AfArray, 0) { - 0 => Array::from(temp), - _ => panic!("Arithmetic operator on Array failed"), - } + let err_val = $ffi_fn(&mut temp as MutAfArray, self.get() as AfArray, + cnst_arr.get() as AfArray, 0); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } @@ -318,18 +311,16 @@ arith_scalar_spec!(u8); macro_rules! arith_func { ($op_name:ident, $fn_name:ident, $ffi_fn: ident) => ( - impl<'f> $op_name<&'f Array> for &'f Array { + impl $op_name for Array { type Output = Array; - fn $fn_name(self, rhs:&'f Array) -> Array { + fn $fn_name(self, rhs: Array) -> Array { unsafe { let mut temp: i64 = 0; - match $ffi_fn(&mut temp as MutAfArray, - self.get() as AfArray, rhs.get() as AfArray, - 0) { - 0 => Array::from(temp), - _ => panic!("Failed to perform arithmetic operation"), - } + let err_val = $ffi_fn(&mut temp as MutAfArray, + self.get() as AfArray, rhs.get() as AfArray, 0); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } @@ -346,3 +337,62 @@ arith_func!(BitOr, bitor, af_bitor); arith_func!(BitXor, bitxor, af_bitxor); arith_func!(Shl, shl, af_bitshiftl); arith_func!(Shr, shr, af_bitshiftr); + +#[cfg(op_assign)] +mod op_assign { + +use array::Array; +use super::*; +use index::{Indexer, assign_gen}; +use seq::Seq; +use std::mem; +use std::ops::{AddAssign, SubAssign, DivAssign, MulAssign, RemAssign}; +use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; + + +macro_rules! arith_assign_func { + ($op_name:ident, $fn_name:ident, $func: ident) => ( + impl $op_name for Array { + + #[allow(unused_variables)] + fn $fn_name(&mut self, rhs: Array) { + let mut idxrs = Indexer::new(); + idxrs.set_index(&Seq::::default(), 0, Some(false)); + idxrs.set_index(&Seq::::default(), 1, Some(false)); + let tmp = assign_gen(self as &Array, &idxrs, + & $func(self as &Array, &rhs, false)); + mem::replace(self, tmp); + } + } + ) +} + +arith_assign_func!(AddAssign, add_assign, add); +arith_assign_func!(SubAssign, sub_assign, sub); +arith_assign_func!(MulAssign, mul_assign, mul); +arith_assign_func!(DivAssign, div_assign, div); +arith_assign_func!(RemAssign, rem_assign, rem); +arith_assign_func!(ShlAssign, shl_assign, shiftl); +arith_assign_func!(ShrAssign, shr_assign, shiftr); + +macro_rules! bit_assign_func { + ($op_name:ident, $fn_name:ident, $func: ident) => ( + impl $op_name for Array { + + #[allow(unused_variables)] + fn $fn_name(&mut self, rhs: Array) { + let mut idxrs = Indexer::new(); + idxrs.set_index(&Seq::::default(), 0, Some(false)); + idxrs.set_index(&Seq::::default(), 1, Some(false)); + let tmp = assign_gen(self as &Array, &idxrs, & $func(self as &Array, &rhs)); + mem::replace(self, tmp); + } + } + ) +} + +bit_assign_func!(BitAndAssign, bitand_assign, bitand); +bit_assign_func!(BitOrAssign, bitor_assign, bitor); +bit_assign_func!(BitXorAssign, bitxor_assign, bitxor); + +} diff --git a/src/array.rs b/src/array.rs index 77d1a1294..a47851d29 100644 --- a/src/array.rs +++ b/src/array.rs @@ -1,7 +1,9 @@ extern crate libc; use dim4::Dim4; -use defines::{AfError, Aftype, Backend}; +use defines::{AfError, DType, Backend}; +use error::HANDLE_ERROR; +use util::HasAfEnum; use self::libc::{uint8_t, c_void, c_int, c_uint, c_longlong}; type MutAfArray = *mut self::libc::c_longlong; @@ -24,7 +26,7 @@ extern { fn af_get_elements(out: MutAfArray, arr: AfArray) -> c_int; - fn af_get_type(out: *mut uint8_t, arr: AfArray) -> c_int; + fn af_get_type(out: *mut c_int, 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; @@ -72,6 +74,21 @@ extern { fn af_cast(out: MutAfArray, arr: AfArray, aftype: uint8_t) -> c_int; fn af_get_backend_id(backend: *mut c_int, 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: uint8_t) -> 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; } /// A multidimensional data container @@ -84,14 +101,12 @@ pub struct Array { macro_rules! is_func { ($fn_name: ident, $ffi_fn: ident) => ( /// Checks if the Array is of specific format/data type. - pub fn $fn_name(&self) -> Result { + 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); - match err_val { - 0 => Ok(ret_val>0), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + ret_val>0 } } ) @@ -103,22 +118,44 @@ impl Array { /// # Examples /// /// ``` - /// let values: &[f32] = &[1.0, 2.0, 3.0]; - /// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); + /// use arrayfire::{Array, Dim4, print}; + /// let values: [f32; 3] = [1.0, 2.0, 3.0]; + /// let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); + /// print(&indices); /// ``` #[allow(unused_mut)] - pub fn new(dims: Dim4, slice: &[T], aftype: Aftype) -> Result { + pub fn new(slice: &[T], dims: Dim4) -> Array { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; 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 uint8_t); - match err_val { - 0 => Ok(Array {handle: temp}), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } + } + + /// Constructs a new Array object from strided data + /// + /// The data pointed by the slice passed to this function can possibily be offseted using an additional `offset` parameter. + #[allow(unused_mut)] + pub fn new_strided(slice: &[T], offset: i64, + dims: Dim4, strides: Dim4) -> Array { + unsafe { + let aftype = T::get_af_dtype(); + let mut temp: i64 = 0; + 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 uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -131,66 +168,98 @@ impl Array { pub fn get_backend(&self) -> Backend { unsafe { let mut ret_val: i32 = 0; - af_get_backend_id(&mut ret_val as *mut c_int, self.handle as AfArray); - match ret_val { - 1 => Backend::AF_BACKEND_CPU, - 2 => Backend::AF_BACKEND_CUDA, - 3 => Backend::AF_BACKEND_OPENCL, - _ => Backend::AF_BACKEND_DEFAULT, + let err_val = af_get_backend_id(&mut ret_val as *mut c_int, 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, } } } + /// Returns the device identifier(integer) on which the Array was created + /// + /// # Return Values + /// + /// Return the device id on which Array was created. + 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 + } + } + /// Returns the number of elements in the Array - pub fn elements(&self) -> Result { + pub fn elements(&self) -> i64 { unsafe { let mut ret_val: i64 = 0; let err_val = af_get_elements(&mut ret_val as MutAfArray, self.handle as AfArray); - match err_val { - 0 => Ok(ret_val), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + ret_val } } /// Returns the Array data type - pub fn get_type(&self) -> Result { + pub fn get_type(&self) -> DType { unsafe { - let mut ret_val: u8 = 0; - let err_val = af_get_type(&mut ret_val as *mut uint8_t, self.handle as AfArray); - match err_val { - 0 => Ok(Aftype::from(ret_val)), - _ => Err(AfError::from(err_val)), - } + let mut ret_val: i32 = 0; + let err_val = af_get_type(&mut ret_val as *mut c_int, self.handle as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + DType::from(ret_val) } } /// Returns the dimensions of the Array - pub fn dims(&self) -> Result { + 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 c_longlong, &mut ret1 as *mut c_longlong, - &mut ret2 as *mut c_longlong, &mut ret3 as *mut c_longlong, + 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); - match err_val { - 0 => Ok(Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64])), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Dim4::new(&[ret0 as u64, ret1 as u64, ret2 as u64, ret3 as u64]) + } + } + + /// Returns the strides of the Array + 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]) } } /// Returns the number of dimensions of the Array - pub fn numdims(&self) -> Result { + 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); - match err_val { - 0 => Ok(ret_val), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + ret_val + } + } + + /// Returns the offset to the pointer from where data begins + 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 } } @@ -200,38 +269,30 @@ impl Array { } /// Copies the data from the Array to the mutable slice `data` - pub fn host(&self, data: &mut [T]) -> Result<(), AfError> { + pub fn host(&self, data: &mut [T]) { unsafe { - let ret_val = af_get_data_ptr(data.as_mut_ptr() as *mut c_void, self.handle as AfArray); - match ret_val { - 0 => Ok(()), - _ => Err(AfError::from(ret_val)), - } + 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)); } } /// Evaluates any pending lazy expressions that represent the data in the Array object - pub fn eval(&self) -> Result<(), AfError> { + pub fn eval(&self) { unsafe { - let ret_val = af_eval(self.handle as AfArray); - match ret_val { - 0 => Ok(()), - _ => Err(AfError::from(ret_val)), - } + let err_val = af_eval(self.handle as AfArray); + HANDLE_ERROR(AfError::from(err_val)); } } /// Makes an copy of the Array /// /// Internally, this is handled by reference counting - pub fn copy(&self) -> Result { + pub fn copy(&self) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_copy_array(&mut temp as MutAfArray, self.handle as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -247,16 +308,17 @@ impl Array { is_func!(is_floating, af_is_floating); is_func!(is_integer, af_is_integer); is_func!(is_bool, af_is_bool); + is_func!(is_linear, af_is_linear); + is_func!(is_owner, af_is_owner); /// Cast the Array data type to `target_type` - pub fn cast(&self, target_type: Aftype) -> Result { + pub fn cast(&self) -> Array { unsafe { + let trgt_type = T::get_af_dtype(); let mut temp: i64 = 0; - let err_val = af_cast(&mut temp as MutAfArray, self.handle as AfArray, target_type as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + let err_val = af_cast(&mut temp as MutAfArray, self.handle as AfArray, trgt_type as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } @@ -299,31 +361,27 @@ impl Drop for Array { /// /// # Examples /// -/// ``` +/// ``` +/// use arrayfire::{Dim4, print, randu}; /// println!("Create a 5-by-3 matrix of random floats on the GPU"); -/// let a = match randu(dims, Aftype::F32) { -/// Ok(value) => value, -/// Err(error) => panic!("{}", error), -/// }; +/// let dims = Dim4::new(&[3, 1, 1, 1]); +/// let a = randu::(dims); /// print(&a); -/// ``` +/// ``` /// -/// The sample output will look like below: +/// The sample output will look like below: /// -/// ``` -/// [5 3 1 1] -/// 0.7402 0.4464 0.7762 -/// 0.9210 0.6673 0.2948 -/// 0.0390 0.1099 0.7140 -/// 0.9690 0.4702 0.3585 -/// 0.9251 0.5132 0.6814 -/// ``` -pub fn print(input: &Array) -> Result<(), AfError> { +/// ```bash +/// [5 3 1 1] +/// 0.7402 0.4464 0.7762 +/// 0.9210 0.6673 0.2948 +/// 0.0390 0.1099 0.7140 +/// 0.9690 0.4702 0.3585 +/// 0.9251 0.5132 0.6814 +/// ``` +pub fn print(input: &Array) { unsafe { - let ret_val = af_print_array(input.get() as AfArray); - match ret_val { - 0 => Ok(()), - _ => Err(AfError::from(ret_val)), - } + let err_val = af_print_array(input.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); } } diff --git a/src/backend.rs b/src/backend.rs index 0070cfd80..26d5b2ba0 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1,12 +1,14 @@ extern crate libc; use defines::{AfError, Backend}; +use error::HANDLE_ERROR; use self::libc::{c_int, c_uint, uint8_t}; extern { fn af_set_backend(bknd: uint8_t) -> c_int; fn af_get_backend_count(num_backends: *mut c_uint) -> c_int; fn af_get_available_backends(backends: *mut c_int) -> c_int; + fn af_get_active_backend(backend: *mut c_int) -> c_int; } /// Toggle backends between cuda, opencl or cpu @@ -14,45 +16,55 @@ extern { /// # Parameters /// /// - `backend` to which to switch to -pub fn set_backend(backend: Backend) -> Result<(), AfError> { +pub fn set_backend(backend: Backend) { unsafe { let err_val = af_set_backend(backend as uint8_t); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } /// Get the available backend count #[allow(unused_mut)] -pub fn get_backend_count() -> Result { +pub fn get_backend_count() -> u32 { unsafe { let mut temp: u32 = 0; let err_val = af_get_backend_count(&mut temp as *mut c_uint); - match err_val { - 0 => Ok(temp), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp } } /// Get the available backends #[allow(unused_mut)] -pub fn get_available_backends() -> Result, AfError> { +pub fn get_available_backends() -> Vec { unsafe { let mut temp: i32 = 0; let err_val = af_get_available_backends(&mut temp as *mut c_int); - match err_val { - 0 => { - let mut b = Vec::new(); - if temp & 0b0100 == 0b0100 { b.push(Backend::AF_BACKEND_OPENCL); } - if temp & 0b0010 == 0b0010 { b.push(Backend::AF_BACKEND_CUDA); } - if temp & 0b0001 == 0b0001 { b.push(Backend::AF_BACKEND_CPU); } - Ok(b) - }, - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + + let mut b = Vec::new(); + if temp & 0b0100 == 0b0100 { b.push(Backend::OPENCL); } + if temp & 0b0010 == 0b0010 { b.push(Backend::CUDA); } + if temp & 0b0001 == 0b0001 { b.push(Backend::CPU); } + + b } } + +/// Get current active backend +#[allow(unused_mut)] +pub fn get_active_backend() -> Backend { + unsafe { + let mut temp: i32 = 0; + let err_val = af_get_active_backend(&mut temp as *mut c_int); + HANDLE_ERROR(AfError::from(err_val)); + match (err_val, temp) { + (0, 0) => Backend::DEFAULT, + (0, 1) => Backend::CPU, + (0, 2) => Backend::CUDA, + (0, 4) => Backend::OPENCL, + _ => panic!("Invalid backend retrieved, undefined behavior."), + } + } +} \ No newline at end of file diff --git a/src/blas/mod.rs b/src/blas/mod.rs index 30c2163fe..49bad1c69 100644 --- a/src/blas/mod.rs +++ b/src/blas/mod.rs @@ -3,6 +3,7 @@ extern crate libc; use array::Array; use defines::AfError; use defines::MatProp; +use error::HANDLE_ERROR; use self::libc::{c_uint, c_int}; use util::to_u32; @@ -35,16 +36,14 @@ extern { /// The result Array of matrix multiplication #[allow(unused_mut)] pub fn matmul(lhs: &Array, rhs: &Array, - optlhs: MatProp, optrhs: MatProp) -> Result { + optlhs: MatProp, optrhs: MatProp) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_matmul(&mut temp as MutAfArray, lhs.get() as AfArray, rhs.get() as AfArray, to_u32(optlhs) as c_uint, to_u32(optrhs) as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -64,16 +63,14 @@ pub fn matmul(lhs: &Array, rhs: &Array, /// The result of dot product. #[allow(unused_mut)] pub fn dot(lhs: &Array, rhs: &Array, - optlhs: MatProp, optrhs: MatProp) -> Result { + optlhs: MatProp, optrhs: MatProp) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_dot(&mut temp as MutAfArray, lhs.get() as AfArray, rhs.get() as AfArray, to_u32(optlhs) as c_uint, to_u32(optrhs) as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -89,15 +86,13 @@ pub fn dot(lhs: &Array, rhs: &Array, /// /// Transposed Array. #[allow(unused_mut)] -pub fn transpose(arr: &Array, conjugate: bool) -> Result { +pub fn transpose(arr: &Array, conjugate: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_transpose(&mut temp as MutAfArray, arr.get() as AfArray, conjugate as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -109,12 +104,9 @@ pub fn transpose(arr: &Array, conjugate: bool) -> Result { /// - `conjugate` is a boolean that indicates if the transpose operation needs to be a conjugate /// transpose #[allow(unused_mut)] -pub fn transpose_inplace(arr: &mut Array, conjugate: bool) -> Result<(), AfError> { +pub fn transpose_inplace(arr: &mut Array, conjugate: bool) { unsafe { let err_val = af_transpose_inplace(arr.get() as AfArray, conjugate as c_int); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } diff --git a/src/data/mod.rs b/src/data/mod.rs index 1b611d844..6c8b6509b 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -4,10 +4,10 @@ extern crate num; use array::Array; use dim4::Dim4; use defines::AfError; -use defines::Aftype; +use error::HANDLE_ERROR; use self::libc::{uint8_t, c_int, c_uint, c_double}; use self::num::Complex; - +use util::HasAfEnum; use std::vec::Vec; type MutAfArray = *mut self::libc::c_longlong; @@ -69,87 +69,77 @@ extern { } pub trait ConstGenerator { - fn generate(&self, dims: Dim4) -> Result; + fn generate(&self, dims: Dim4) -> Array; } #[allow(unused_mut)] impl ConstGenerator for i64 { - fn generate(&self, dims: Dim4) -> Result { + fn generate(&self, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_constant_long(&mut temp as MutAfArray, *self as Intl, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } #[allow(unused_mut)] impl ConstGenerator for u64 { - fn generate(&self, dims: Dim4) -> Result { + fn generate(&self, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_constant_ulong(&mut temp as MutAfArray, *self as Uintl, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } #[allow(unused_mut)] impl ConstGenerator for Complex { - fn generate(&self, dims: Dim4) -> Result { + fn generate(&self, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_constant_complex(&mut temp as MutAfArray, (*self).re as c_double, (*self).im as c_double, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, 1); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } #[allow(unused_mut)] impl ConstGenerator for Complex { - fn generate(&self, dims: Dim4) -> Result { + fn generate(&self, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_constant_complex(&mut temp as MutAfArray, (*self).re as c_double, (*self).im as c_double, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, 3); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } #[allow(unused_mut)] impl ConstGenerator for bool { - fn generate(&self, dims: Dim4) -> Result { + fn generate(&self, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_constant(&mut temp as MutAfArray, *self as c_int as c_double, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, 4); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } @@ -158,16 +148,14 @@ macro_rules! cnst { ($rust_type:ty, $ffi_type:expr) => ( #[allow(unused_mut)] impl ConstGenerator for $rust_type { - fn generate(&self, dims: Dim4) -> Result { + fn generate(&self, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_constant(&mut temp as MutAfArray, *self as c_double, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, $ffi_type); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } } @@ -207,7 +195,7 @@ cnst!(u16 , 11); /// # Return Values /// /// An Array of given dimensions with constant value -pub fn constant(cnst: T, dims: Dim4) -> Result { +pub fn constant(cnst: T, dims: Dim4) -> Array { cnst.generate(dims) } @@ -220,21 +208,19 @@ pub fn constant(cnst: T, dims: Dim4) -> Result Result { +pub fn range(dims: Dim4, seq_dim: i32) -> Array { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; - let err_val =af_range(&mut temp as MutAfArray, + let err_val = af_range(&mut temp as MutAfArray, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, seq_dim as c_int, aftype as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -246,63 +232,55 @@ pub fn range(dims: Dim4, seq_dim: i32, aftype: Aftype) -> Result /// /// - `dims` is the dimensions of the sequence to be generated /// - `tdims` is the number of repitions of the unit dimensions -/// - `aftype` is the type of Array to generate /// /// # Return Values /// /// Array #[allow(unused_mut)] -pub fn iota(dims: Dim4, tdims: Dim4, aftype: Aftype) -> Result { +pub fn iota(dims: Dim4, tdims: Dim4) -> Array { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; let err_val =af_iota(&mut temp as MutAfArray, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, tdims.ndims() as c_uint, tdims.get().as_ptr() as *const DimT, aftype as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } /// Set seed for random number generation -pub fn set_seed(seed: u64) -> Result<(), AfError> { +pub fn set_seed(seed: u64) { unsafe { let err_val = af_set_seed(seed as Uintl); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } /// Get the seed of random number generator #[allow(unused_mut)] -pub fn get_seed() -> Result { +pub fn get_seed() -> u64 { unsafe { let mut temp: u64 = 0; let err_val = af_get_seed(&mut temp as *mut Uintl); - match err_val { - 0 => Ok(temp), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp } } macro_rules! data_gen_def { ($fn_name:ident, $ffi_name: ident) => ( #[allow(unused_mut)] - pub fn $fn_name(dims: Dim4, aftype: Aftype) -> Result { + pub fn $fn_name(dims: Dim4) -> Array { unsafe { + let aftype = T::get_af_dtype(); let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT, aftype as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -324,14 +302,12 @@ data_gen_def!(identity, af_identity); /// /// An Array with values as a diagonal Matrix #[allow(unused_mut)] -pub fn diag_create(input: &Array, dim: i32) -> Result { +pub fn diag_create(input: &Array, dim: i32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_diag_create(&mut temp as MutAfArray, input.get() as AfArray, dim as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -346,15 +322,13 @@ pub fn diag_create(input: &Array, dim: i32) -> Result { /// /// An Array with values of the diagonal from input Array #[allow(unused_mut)] -pub fn diag_extract(input: &Array, dim: i32) -> Result { +pub fn diag_extract(input: &Array, dim: i32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_diag_extract(&mut temp as MutAfArray, input.get() as AfArray, dim as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -370,15 +344,13 @@ pub fn diag_extract(input: &Array, dim: i32) -> Result { /// /// Concatenated Array #[allow(unused_mut)] -pub fn join(dim: i32, first: &Array, second: &Array) -> Result { +pub fn join(dim: i32, first: &Array, second: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_join(&mut temp as MutAfArray, dim as c_int, first.get() as AfArray, second.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -393,70 +365,31 @@ pub fn join(dim: i32, first: &Array, second: &Array) -> Result { /// /// Concatenated Array #[allow(unused_mut)] -pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Result { +pub fn join_many(dim: i32, inputs: Vec<&Array>) -> Array { unsafe { + let mut v = Vec::new(); + for i in inputs { + v.push(i.get()); + } let mut temp: i64 = 0; let err_val = af_join_many(&mut temp as MutAfArray, dim as c_int, - inputs.len() as c_uint, inputs.as_ptr() as *const AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + v.len() as c_uint, v.as_ptr() as *const AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } -/// Join multiple Arrays along a given dimension -/// -/// # Examples -/// -/// ``` -/// # #[macro_use] extern crate arrayfire; -/// # fn main() { -/// let a = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); -/// let b = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); -/// let c = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); -/// let d = join_many![2, a, b, c]; -/// # } -/// ``` -/// -/// # Panics -/// -/// Using this macro to create an Array from multiple Arrays doesn't implicitly check for errors -/// during FFI calls. Therefore, make sure your inputs are correct. In case, you do need proper -/// error checking, use the [function version](./fn.join_many.html) of this macro. -// Using macro to implement join many wrapper -#[macro_export] -macro_rules! join_many { - [$dim: expr; $($x:ident),+] => { - { - let mut temp_vec = Vec::new(); - $( - temp_vec.push($x); - )* - let mut temp: i64 = 0; - unsafe { - let mut temp: i64 = 0; - af_join_many(&mut temp as MutAfArray, $dim as c_int, - temp_vec.len() as c_uint, temp_vec.as_ptr() as *const AfArray); - Array::from(temp) - } - } - }; -} - macro_rules! data_func_def { ($fn_name:ident, $ffi_name: ident) => ( #[allow(unused_mut)] - pub fn $fn_name(input: &Array, dims: Dim4) -> Result { + pub fn $fn_name(input: &Array, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, input.get() as AfArray, dims[0] as c_uint, dims[1] as c_uint, dims[2] as c_uint, dims[3] as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -476,28 +409,24 @@ data_func_def!(shift, af_shift); /// # Return Values /// Reshaped Array #[allow(unused_mut)] -pub fn moddims(input: &Array, dims: Dim4) -> Result { +pub fn moddims(input: &Array, dims: Dim4) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_moddims(&mut temp as MutAfArray, input.get() as AfArray, dims.ndims() as c_uint, dims.get().as_ptr() as *const DimT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } /// Flatten the multidimensional Array to an 1D Array #[allow(unused_mut)] -pub fn flat(input: &Array) -> Result { +pub fn flat(input: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_flat(&mut temp as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -512,14 +441,12 @@ pub fn flat(input: &Array) -> Result { /// /// Flipped Array #[allow(unused_mut)] -pub fn flip(input: &Array, dim: u32) -> Result { +pub fn flip(input: &Array, dim: u32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_flip(&mut temp as MutAfArray, input.get() as AfArray, dim as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -533,15 +460,13 @@ pub fn flip(input: &Array, dim: u32) -> Result { /// # Return Values /// Array #[allow(unused_mut)] -pub fn lower(input: &Array, is_unit_diag: bool) -> Result { +pub fn lower(input: &Array, is_unit_diag: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_lower(&mut temp as MutAfArray, input.get() as AfArray, is_unit_diag as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -555,15 +480,13 @@ pub fn lower(input: &Array, is_unit_diag: bool) -> Result { /// # Return Values /// Array #[allow(unused_mut)] -pub fn upper(input: &Array, is_unit_diag: bool) -> Result { +pub fn upper(input: &Array, is_unit_diag: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_upper(&mut temp as MutAfArray, input.get() as AfArray, is_unit_diag as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -572,7 +495,7 @@ pub fn upper(input: &Array, is_unit_diag: bool) -> Result { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ``` +/// ```ignore /// c = cond ? a : b; /// where cond, a & b are all objects of type Array /// ``` /// @@ -588,15 +511,13 @@ pub fn upper(input: &Array, is_unit_diag: bool) -> Result { /// /// An Array #[allow(unused_mut)] -pub fn select(a: &Array, cond: &Array, b: &Array) -> Result { +pub fn select(a: &Array, cond: &Array, b: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_select(&mut temp as MutAfArray, cond.get() as AfArray, - a.get() as AfArray, b.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + a.get() as AfArray, b.get() as AfArray); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -605,7 +526,7 @@ pub fn select(a: &Array, cond: &Array, b: &Array) -> Result { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ``` +/// ```ignore /// c = cond ? a : b; /// where a is a scalar(f64) and b is Array /// ``` /// @@ -621,15 +542,13 @@ pub fn select(a: &Array, cond: &Array, b: &Array) -> Result { /// /// An Array #[allow(unused_mut)] -pub fn selectl(a: f64, cond: &Array, b: &Array) -> Result { +pub fn selectl(a: f64, cond: &Array, b: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_select_scalar_l(&mut temp as MutAfArray, cond.get() as AfArray, a as c_double, b.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -638,7 +557,7 @@ pub fn selectl(a: f64, cond: &Array, b: &Array) -> Result { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ``` +/// ```ignore /// c = cond ? a : b; /// where a is Array and b is a scalar(f64) /// ``` /// @@ -654,15 +573,13 @@ pub fn selectl(a: f64, cond: &Array, b: &Array) -> Result { /// /// An Array #[allow(unused_mut)] -pub fn selectr(a: &Array, cond: &Array, b: f64) -> Result { +pub fn selectr(a: &Array, cond: &Array, b: f64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_select_scalar_r(&mut temp as MutAfArray, cond.get() as AfArray, - a.get() as AfArray, b as c_double); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + a.get() as AfArray, b as c_double); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -671,7 +588,7 @@ pub fn selectr(a: &Array, cond: &Array, b: f64) -> Result { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ``` +/// ```ignore /// a = cond ? a : b; /// where cond, a & b are all objects of type Array /// ``` /// @@ -684,15 +601,12 @@ pub fn selectr(a: &Array, cond: &Array, b: f64) -> Result { /// /// # Return Values /// -/// An Array +/// None #[allow(unused_mut)] -pub fn replace(a: &mut Array, cond: &Array, b: &Array) -> Result<(), AfError> { +pub fn replace(a: &mut Array, cond: &Array, b: &Array) { unsafe { let err_val = af_replace(a.get() as AfArray, cond.get() as AfArray, b.get() as AfArray); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -701,7 +615,7 @@ pub fn replace(a: &mut Array, cond: &Array, b: &Array) -> Result<(), AfError> { /// This function does the C-equivalent of the following statement, except that the operation /// happens on a GPU for all elements simultaneously. /// -/// ``` +/// ```ignore /// a = cond ? a : b; /// where cond, a are Arrays and b is scalar(f64) /// ``` /// @@ -714,14 +628,11 @@ pub fn replace(a: &mut Array, cond: &Array, b: &Array) -> Result<(), AfError> { /// /// # Return Values /// -/// An Array +/// None #[allow(unused_mut)] -pub fn replace_scalar(a: &mut Array, cond: &Array, b: f64) -> Result<(), AfError> { +pub fn replace_scalar(a: &mut Array, cond: &Array, b: f64) { unsafe { let err_val = af_replace_scalar(a.get() as AfArray, cond.get() as AfArray, b as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } -} +} \ No newline at end of file diff --git a/src/defines.rs b/src/defines.rs index 8d5597d82..669f2e053 100644 --- a/src/defines.rs +++ b/src/defines.rs @@ -4,7 +4,7 @@ use std::fmt::Error as FmtError; /// Error codes #[repr(C)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum AfError { /// The function returned successfully SUCCESS = 0, @@ -16,7 +16,7 @@ pub enum AfError { /// There was an error with the runtime environment ERR_RUNTIME = 103, // 200-299 Errors in input parameters - /// The input array is not a valid af_array object + /// The input array is not a valid Array object ERR_INVALID_ARRAY = 201, /// One of the function arguments is incorrect ERR_ARG = 202, @@ -28,6 +28,8 @@ pub enum AfError { ERR_DIFF_TYPE = 205, /// Function does not support GFOR / batch mode ERR_BATCH = 207, + /// Input does not belong to the current device + ERR_DEVICE = 208, // 300-399 Errors for missing software features /// The option is not supported ERR_NOT_SUPPORTED = 301, @@ -47,26 +49,27 @@ pub enum AfError { ERR_UNKNOWN = 999 } +/// Compute/Acceleration Backend #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub enum Backend { /// Default backend order: OpenCL -> CUDA -> CPU - AF_BACKEND_DEFAULT = 0, + DEFAULT = 0, /// CPU a.k.a sequential algorithms - AF_BACKEND_CPU = 1, + CPU = 1, /// CUDA Compute Backend - AF_BACKEND_CUDA = 2, + CUDA = 2, /// OpenCL Compute Backend - AF_BACKEND_OPENCL = 4 + OPENCL = 4 } impl Display for Backend { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { let text = match *self { - Backend::AF_BACKEND_OPENCL => "OpenCL", - Backend::AF_BACKEND_CUDA => "Cuda", - Backend::AF_BACKEND_CPU => "CPU", - Backend::AF_BACKEND_DEFAULT => "Default", + Backend::OPENCL => "OpenCL", + Backend::CUDA => "Cuda", + Backend::CPU => "CPU", + Backend::DEFAULT => "Default", }; write!(f, "{}", text) } @@ -81,29 +84,31 @@ impl Display for AfError { impl Error for AfError { fn description(&self) -> &str { match *self { - AfError::SUCCESS => "Function returned successfully", - AfError::ERR_NO_MEM => "The system or device ran out of memory", - AfError::ERR_DRIVER => "Device driver error", - AfError::ERR_RUNTIME => "Error in runtime environment", - AfError::ERR_INVALID_ARRAY => "Input is not a valid Array Object", - AfError::ERR_ARG => "One of the function arguments is incorrect", - AfError::ERR_SIZE => "The size is incorrect", - AfError::ERR_TYPE => "The type is not supported by this function", - AfError::ERR_DIFF_TYPE => "The type of input arrays are not compatible", - AfError::ERR_BATCH => "Function does not support GFOR / batch mode", - AfError::ERR_NOT_SUPPORTED => "The option is not supported", + AfError::SUCCESS => "Function returned successfully", + AfError::ERR_NO_MEM => "System or Device ran out of memory", + AfError::ERR_DRIVER => "Error in the device driver", + AfError::ERR_RUNTIME => "Error with the runtime environment", + AfError::ERR_INVALID_ARRAY => "Iput Array is not a valid object", + AfError::ERR_ARG => "One of the function arguments is incorrect", + AfError::ERR_SIZE => "Size is incorrect", + AfError::ERR_TYPE => "Type is not suppported by this function", + AfError::ERR_DIFF_TYPE => "Type of the input arrays are not compatible", + AfError::ERR_BATCH => "Function does not support GFOR / batch mode", + AfError::ERR_DEVICE => "Input does not belong to the current device", + AfError::ERR_NOT_SUPPORTED => "Unsupported operation/parameter option", AfError::ERR_NOT_CONFIGURED => "This build of ArrayFire does not support this feature", - AfError::ERR_NO_DBL => "This device does not support double", - AfError::ERR_NO_GFX => "This build of ArrayFire was not built with graphics or this device does not support graphics", - AfError::ERR_INTERNAL => "There was an internal error in either ArrayFire or upstream project", - AfError::ERR_UNKNOWN => "Unkown Error", + AfError::ERR_NO_DBL => "This device does not support double", + AfError::ERR_NO_GFX => "This build of ArrayFire has no graphics support", + AfError::ERR_INTERNAL => "Eror either in ArrayFire or in a project upstream", + AfError::ERR_UNKNOWN => "Unknown Error", } } } /// Types of Array data type -#[derive(Copy, Clone)] -pub enum Aftype { +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum DType { /// 32 bit float F32 = 0, /// 32 bit complex float @@ -131,7 +136,8 @@ pub enum Aftype { } /// Dictates the interpolation method to be used by a function -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum InterpType { /// Nearest Neighbor interpolation method NEAREST = 0, @@ -144,7 +150,8 @@ pub enum InterpType { } /// Helps determine how to pad kernels along borders -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum BorderType { /// Pad using zeros ZERO = 0, @@ -153,7 +160,8 @@ pub enum BorderType { } /// Used by `regions` function to identify type of connectivity -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum Connectivity { /// North-East-South-West (N-E-S-W) connectivity from given pixel/point FOUR = 4, @@ -162,7 +170,8 @@ pub enum Connectivity { } /// Helps determine the size of output of convolution -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum ConvMode { /// Default convolution mode where output size is same as input size DEFAULT = 0, @@ -171,7 +180,8 @@ pub enum ConvMode { } /// Helps determine if convolution is in Spatial or Frequency domain -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum ConvDomain { /// ArrayFire chooses whether the convolution will be in spatial domain or frequency domain AUTO = 0, @@ -182,7 +192,8 @@ pub enum ConvDomain { } /// Error metric used by `matchTemplate` function -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum MatchType { /// Sum of Absolute Differences SAD = 0, @@ -205,7 +216,8 @@ pub enum MatchType { } /// Identify the color space of given image(Array) -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum ColorSpace { /// Grayscale color space GRAY = 0, @@ -216,7 +228,8 @@ pub enum ColorSpace { } /// Helps determine the type of a Matrix -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum MatProp { /// Default (no-op) NONE, @@ -244,7 +257,8 @@ pub enum MatProp { /// Norm type #[allow(non_camel_case_types)] -#[derive(Copy, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum NormType { /// Treats input as a vector and return sum of absolute values VECTOR_1 = 0, @@ -266,7 +280,7 @@ pub enum NormType { /// Dictates what color map is used for Image rendering #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum ColorMap { /// Default color map is grayscale range [0-1] DEFAULT = 0, @@ -286,7 +300,7 @@ pub enum ColorMap { /// YCbCr Standards #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum YCCStd { /// ITU-R BT.601 (formerly CCIR 601) standard YCC_601 = 601, @@ -298,10 +312,24 @@ pub enum YCCStd { /// Homography type #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum HomographyType { /// RANdom SAmple Consensus algorithm RANSAC = 0, /// Least Median of Squares LMEDS = 1, } + +/// Plotting markers +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum MarkerType { + NONE = 0, + POINT = 1, + CIRCLE = 2, + SQUARE = 3, + TRIANGLE = 4, + CROSS = 5, + PLUS = 6, + STAR = 7 +} diff --git a/src/device/mod.rs b/src/device/mod.rs index fd17e1fd0..250b2fbb5 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,15 +1,24 @@ extern crate libc; use defines::AfError; -use self::libc::c_int; +use error::HANDLE_ERROR; +use self::libc::{c_int, size_t, c_char}; +use std::ffi::CString; extern { fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int; fn af_info() -> c_int; + fn af_init() -> c_int; fn af_get_device_count(nDevices: *mut c_int) -> c_int; fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int; fn af_set_device(device: c_int) -> c_int; fn af_get_device(device: *mut c_int) -> c_int; + fn af_device_mem_info(alloc_bytes: *mut size_t, alloc_buffers: *mut size_t, + lock_bytes: *mut size_t, lock_buffers: *mut size_t) -> c_int; + fn af_print_mem_info(msg: *const c_char, device_id: c_int) -> c_int; + fn af_set_mem_step_size(step_bytes: size_t) -> c_int; + fn af_get_mem_step_size(step_bytes: *mut size_t) -> c_int; + fn af_device_gc() -> c_int; fn af_sync(device: c_int) -> c_int; } @@ -17,17 +26,15 @@ extern { /// /// # Return Values /// A triplet of integers indicating major, minor & fix release version numbers. -pub fn get_version() -> Result<(i32, i32, i32), AfError> { +pub fn get_version() -> (i32, i32, i32) { unsafe { let mut maj: i32 = 0; let mut min: i32 = 0; let mut pat: i32 = 0; let err_val = af_get_version(&mut maj as *mut c_int, &mut min as *mut c_int, &mut pat as *mut c_int); - match err_val { - 0 => Ok((maj, min, pat)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (maj, min, pat) } } @@ -37,30 +44,36 @@ pub fn get_version() -> Result<(i32, i32, i32), AfError> { /// /// An example output of `af::info` call looks like below /// -/// ``` +/// ```ignore /// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38) /// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000 /// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0 /// ``` -pub fn info() -> Result<(), AfError> { +pub fn info() { unsafe { let err_val = af_info(); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Initialize ArrayFire library +/// +/// 0th device will be the default device unless init call +/// is followed by set_device +pub fn init() { + unsafe { + let err_val = af_init(); + HANDLE_ERROR(AfError::from(err_val)); } } /// Get total number of available devices -pub fn device_count() -> Result { +pub fn device_count() -> i32 { unsafe { let mut temp: i32 = 0; let err_val = af_get_device_count(&mut temp as *mut c_int); - match err_val { - 0 => Ok(temp), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp } } @@ -73,14 +86,12 @@ pub fn device_count() -> Result { /// # Return Values /// /// `True` if `device` device has double support, `False` otherwise. -pub fn is_double_available(device: i32) -> Result { +pub fn is_double_available(device: i32) -> bool { unsafe { let mut temp: i32 = 0; let err_val = af_get_dbl_support(&mut temp as *mut c_int, device as c_int); - match err_val { - 0 => Ok(temp > 0), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp > 0 } } @@ -89,28 +100,120 @@ pub fn is_double_available(device: i32) -> Result { /// # Parameters /// /// - `device` is the value of the device identifier which has to be set as active -pub fn set_device(device: i32) -> Result<(), AfError> { +pub fn set_device(device: i32) { unsafe { let err_val = af_set_device(device as c_int); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } /// Get the current active device id -pub fn get_device() -> Result { +pub fn get_device() -> i32 { unsafe { let mut temp: i32 = 0; let err_val = af_get_device(&mut temp as *mut c_int); - match err_val { - 0 => Ok(temp), - _ => Err(AfError::from(err_val)), + HANDLE_ERROR(AfError::from(err_val)); + temp + } +} + +/// Get memory information from the memory manager for the current active device +/// +/// # Parameters +/// +/// This function doesn't take any input parameters +/// +/// # Return Values +/// +/// A quadruple of values regarding the following information. +/// +/// * Number of bytes allocated +/// * Number of buffers allocated +/// * Number of bytes locked +/// * Number of buffers locked +pub fn device_mem_info() -> (usize, usize, usize, usize) { + unsafe { + let mut o0: usize = 0; + let mut o1: usize = 0; + let mut o2: usize = 0; + let mut o3: usize = 0; + let err_val = af_device_mem_info(&mut o0 as *mut size_t, + &mut o1 as *mut size_t, + &mut o2 as *mut size_t, + &mut o3 as *mut size_t); + HANDLE_ERROR(AfError::from(err_val)); + (o0, o1, o2, o3) + } +} + +/// Print buffer details from the ArrayFire device manager +/// +/// This information is printed in the form of a table. +/// +/// # Parameters +/// +/// - `msg` is a message to print before the table +/// - `device` is the id of the device for which buffer details are to be printed +/// +/// # Return Values +/// +/// None +pub fn print_mem_info(msg: String, device: i32) { + unsafe { + let cmsg = CString::new(msg.as_bytes()); + match cmsg { + Ok(v) => { + let err_val = af_print_mem_info(v.to_bytes_with_nul().as_ptr() as * const c_char, + device as c_int); + HANDLE_ERROR(AfError::from(err_val)); + }, + Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL), } } } +/// Set the minimum memory chunk size +/// +/// # Parameters +/// +/// - `step_bytes` is the size of minimum memory chunk in bytes +/// +/// # Return Values +/// +/// None +pub fn set_mem_step_size(step_bytes: usize) { + unsafe { + let err_val = af_set_mem_step_size(step_bytes as size_t); + HANDLE_ERROR(AfError::from(err_val)); + } +} + +/// Get the minimum memory chunk size +/// +/// # Parameters +/// +/// None +/// +/// # Return Values +/// +/// Returns is the size of minimum memory chunk in bytes +pub fn get_mem_step_size() -> usize { + unsafe { + let mut temp: usize = 0; + let err_val = af_get_mem_step_size(&mut temp as *mut size_t); + HANDLE_ERROR(AfError::from(err_val)); + temp + } +} + +/// Call the garbage collection routine +pub fn device_gc() { + unsafe { + let err_val = af_device_gc(); + HANDLE_ERROR(AfError::from(err_val)); + } +} + /// Sync all operations on given device /// /// # Parameters @@ -120,12 +223,9 @@ pub fn get_device() -> Result { /// # Return Values /// /// None -pub fn sync(device: i32) -> Result<(), AfError> { +pub fn sync(device: i32) { unsafe { let err_val = af_sync(device as c_int); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } diff --git a/src/dim4.rs b/src/dim4.rs index 23d2eee33..29eda2375 100644 --- a/src/dim4.rs +++ b/src/dim4.rs @@ -2,7 +2,7 @@ use std::fmt; use std::ops::Index; /// Dim4 is used to store [Array](./struct.Array.html) dimensions -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct Dim4 { dims: [u64; 4], } @@ -19,6 +19,8 @@ impl Default for Dim4 { /// # Examples /// /// ``` +/// use arrayfire::Dim4; +/// /// let dims = Dim4::new(&[4, 4, 2, 1]); /// println!("0th Dimension length is {}", dims[0]); // -> 4 /// println!("1th Dimension length is {}", dims[1]); // -> 4 @@ -38,6 +40,8 @@ impl Index for Dim4 { /// # Examples /// /// ``` +/// use arrayfire::Dim4; +/// /// let dims = Dim4::new(&[4, 4, 2, 1]); /// println!("0th Dimension length is {}", dims[0]); // -> 4 /// ``` @@ -53,6 +57,7 @@ impl Dim4 { /// # Examples /// /// ``` + /// use arrayfire::Dim4; /// let dims = Dim4::new(&[4, 4, 2, 1]); /// ``` pub fn new(dims: &[u64; 4]) -> Dim4 { diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 000000000..0c1b371b3 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,86 @@ +use std::ops::{Deref, DerefMut}; +use defines::AfError; +use std::error::Error; +use std::marker::{Send, Sync}; +use std::sync::RwLock; + + +pub type ErrorCallback = Fn(AfError); + + +/// Wrap ErrorCallback function pointer inside a structure +/// to enable implementing Send, Sync traits on it. +pub struct Callback<'cblifetime> { + pub cb: &'cblifetime ErrorCallback, +} + + +// Implement Send, Sync traits for Callback structure to +// enable the user of Callback function pointer in conjunction +// with threads using a mutex. +unsafe impl<'cblifetime> Send for Callback<'cblifetime> {} +unsafe impl<'cblifetime> Sync for Callback<'cblifetime> {} + + +pub const DEFAULT_HANDLE_ERROR: Callback<'static> = Callback{cb: &handle_error_general}; + + +lazy_static! { + static ref ERROR_HANDLER_LOCK: RwLock< Callback<'static> > = + RwLock::new(DEFAULT_HANDLE_ERROR); +} + + +/// Register user provided error handler +/// +/// # Examples +/// ``` +/// #[macro_use] +/// extern crate arrayfire; +/// +/// use arrayfire::{AfError, Callback, info, register_error_handler}; +/// use std::error::Error; +/// +/// fn handleError(error_code: AfError) { +/// match error_code { +/// AfError::SUCCESS => {}, /* No-op */ +/// _ => panic!("Error message: {}", error_code.description()), +/// } +/// } +/// +/// pub const ERR_HANDLE: Callback<'static> = Callback{ cb: &handleError}; +/// +/// fn main() { +/// register_error_handler(ERR_HANDLE); +/// +/// info(); +/// } +/// ``` +#[allow(unused_must_use)] +pub fn register_error_handler(cb_value: Callback<'static>) { + let mut gaurd = match ERROR_HANDLER_LOCK.write() { + Ok(g) => g, + Err(_)=> panic!("Failed to acquire lock to register error handler"), + }; + + *gaurd.deref_mut() = cb_value; +} + +pub fn handle_error_general(error_code: AfError) { + match error_code { + AfError::SUCCESS => {}, /* No-op */ + _ => panic!("Error message: {}", error_code.description()), + } +} + +#[allow(non_snake_case)] +pub fn HANDLE_ERROR(error_code: AfError) { + let gaurd = match ERROR_HANDLER_LOCK.read() { + Ok(g) => g, + Err(_)=> panic!("Failed to acquire lock while handling FFI return value"), + }; + + let func = gaurd.deref().cb; + + func(error_code); +} diff --git a/src/graphics.rs b/src/graphics.rs index 718da6e71..42a2dbd18 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -2,7 +2,8 @@ extern crate libc; use array::Array; use defines::AfError; -use defines::ColorMap; +use defines::{ColorMap, MarkerType}; +use error::HANDLE_ERROR; use self::libc::{c_int, c_uint, c_double, c_char}; use std::ffi::CString; @@ -17,6 +18,7 @@ extern { fn af_set_position(wnd: WndHandle, x: c_uint, y: c_uint) -> c_int; fn af_set_title(wnd: WndHandle, title: *const c_char) -> c_int; fn af_set_size(wnd: WndHandle, w: c_uint, h: c_uint) -> c_int; + fn af_set_visibility(wnd: WndHandle, is_visible: c_int) -> c_int; fn af_draw_image(wnd: WndHandle, arr: AfArray, props: CellPtr) -> c_int; fn af_draw_plot(wnd: WndHandle, x: AfArray, y: AfArray, props: CellPtr) -> c_int; fn af_draw_plot3(wnd: WndHandle, P: AfArray, props: CellPtr) -> c_int; @@ -24,6 +26,8 @@ extern { minval: c_double, maxval: c_double, props: CellPtr) -> c_int; fn af_draw_surface(wnd: WndHandle, xvals: AfArray, yvals: AfArray, S: AfArray, props: CellPtr) -> c_int; + fn af_draw_scatter(wnd: WndHandle, x: AfArray, y: AfArray, marker: c_int, props: CellPtr) -> c_int; + fn af_draw_scatter3(wnd: WndHandle, P: AfArray, marker: c_int, props: CellPtr) -> c_int; fn af_grid(wnd: WndHandle, rows: c_int, cols: c_int) -> c_int; fn af_show(wnd: WndHandle) -> c_int; fn af_is_window_closed(out: *mut c_int, wnd: WndHandle) -> c_int; @@ -51,26 +55,24 @@ pub struct Cell { /// /// # Examples /// -/// ``` -/// let wnd = Window::new(1280, 720, String::from("Image Histogram")).unwrap(); -/// let img = match load_image("Path to image", true/*If color image, 'false' otherwise*/) { -/// Ok(img) => img, -/// Err(err) => panic!("Image loading failed with error code {}", err), -/// }; -/// let hst = histogram(img, 256, 0, 255).unwrap(); +/// ```no_run +/// use arrayfire::{histogram, load_image, Window}; +/// let mut wnd = Window::new(1280, 720, String::from("Image Histogram")); +/// let img = load_image("Path to image".to_string(), true/*If color image, 'false' otherwise*/); +/// let hst = histogram(&img, 256, 0 as f64, 255 as f64); /// /// loop { /// wnd.grid(2, 1); /// /// wnd.set_view(0, 0); -/// wnd.draw_image(img, Some("Input Image")); +/// wnd.draw_image(&img, Some("Input Image".to_string())); /// /// wnd.set_view(1, 0); -/// wnd.draw_histogram(hst, 0.0, 255.0, Some("Input Image Histogram")); +/// wnd.draw_hist(&hst, 0.0, 255.0, Some("Input Image Histogram".to_string())); /// /// wnd.show(); /// -/// if wnd.is_closed().unwrap() == true { break; } +/// if wnd.is_closed() == true { break; } /// } /// ``` #[derive(Clone)] @@ -103,67 +105,72 @@ impl Drop for Window { impl Window { /// Creates new Window object #[allow(unused_mut)] - pub fn new(width: i32, height: i32, title: String) -> Result { + pub fn new(width: i32, height: i32, title: String) -> Window { unsafe { let mut temp: u64 = 0; let cstr_ret = CString::new(title.as_bytes()); match cstr_ret { Ok(cstr) => { - let err_val = af_create_window(&mut temp as MutWndHandle - , width as c_int, height as c_int - , cstr.to_bytes_with_nul().as_ptr() as *const c_char); - match err_val { - 0 => Ok(Window::from(temp)), - _ => Err(AfError::from(err_val)), - } + let err_val = af_create_window(&mut temp as MutWndHandle, + width as c_int, height as c_int, + cstr.to_bytes_with_nul().as_ptr() as *const c_char); + HANDLE_ERROR(AfError::from(err_val)); + Window::from(temp) }, - Err(_) => Err(AfError::ERR_INTERNAL), + Err(_) => panic!("String creation failed while prepping params for window creation."), } } } /// Set window starting position on the screen - pub fn set_position(&self, x: u32, y: u32) -> Result<(), AfError> { + pub fn set_position(&self, x: u32, y: u32) { unsafe { let err_val = af_set_position(self.handle as WndHandle, x as c_uint, y as c_uint); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } /// Set window title - pub fn set_title(&self, title: String) -> Result<(), AfError> { + pub fn set_title(&self, title: String) { unsafe { let cstr_ret = CString::new(title.as_bytes()); match cstr_ret { Ok(cstr) => { - let err_val = af_set_title(self.handle as WndHandle - , cstr.to_bytes_with_nul().as_ptr() as *const c_char); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + let err_val = af_set_title(self.handle as WndHandle, + cstr.to_bytes_with_nul().as_ptr() as *const c_char); + HANDLE_ERROR(AfError::from(err_val)); }, - Err(_) => Err(AfError::ERR_INTERNAL), + Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL), } } } + /// Set window visibility + /// + /// # Parameters + /// + /// - `is_visible` is a boolean indicating whether window is to be hidden or brought into focus + /// + /// # Return Values + /// + /// None + pub fn set_visibility(&self, is_visible: bool) { + unsafe { + let err_val = af_set_visibility(self.handle as WndHandle, is_visible as c_int); + HANDLE_ERROR(AfError::from(err_val)); + } + } + /// Set window size /// /// # Parameters /// /// - `w` is the target width of window /// - `h` is the target height of window - pub fn set_size(&self, w: u32, h: u32) -> Result<(), AfError> { + pub fn set_size(&self, w: u32, h: u32) { unsafe { let err_val = af_set_size(self.handle as WndHandle, w as c_uint, h as c_uint); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -174,39 +181,31 @@ impl Window { } /// Returns true if the window close is triggered by the user - pub fn is_closed(&self) -> Result { + pub fn is_closed(&self) -> bool { unsafe { let mut temp: i32 = 1; let err_val = af_is_window_closed(&mut temp as *mut c_int, self.handle as WndHandle); - match err_val { - 0 => Ok(temp > 0), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp > 0 } } /// Used to setup display layout in multiview mode - pub fn grid(&self, rows: i32, cols: i32) -> Result<(), AfError> { + pub fn grid(&self, rows: i32, cols: i32) { unsafe { let err_val = af_grid(self.handle as WndHandle, rows as c_int, cols as c_int); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } /// Used in multiview mode to swap back buffer with front buffer to show the recently rendered /// frame - pub fn show(&mut self) -> Result<(), AfError> { + pub fn show(&mut self) { unsafe { let err_val = af_show(self.handle as WndHandle); - if err_val != 0 { - return Err(AfError::from(err_val)); - } + HANDLE_ERROR(AfError::from(err_val)); self.row = -1; self.col = -1; - Ok(()) } } @@ -227,10 +226,7 @@ impl Window { unsafe { let err_val = af_draw_image(self.handle as WndHandle, input.get() as AfArray, cprops as *const Cell as CellPtr); - match err_val { - 0 => (), - _ => panic!("Rendering the image failed: {}", err_val), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -246,10 +242,7 @@ impl Window { x.get() as AfArray, y.get() as AfArray, cprops as *const Cell as CellPtr); - match err_val { - 0 => (), - _ => panic!("Rendering 2d line plot failed: {}", err_val), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -263,10 +256,7 @@ impl Window { unsafe { let err_val = af_draw_plot3(self.handle as WndHandle, points.get() as AfArray, cprops as *const Cell as CellPtr); - match err_val { - 0 => (), - _ => panic!("Rendering 3d line plot failed: {}", err_val), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -281,10 +271,7 @@ impl Window { let err_val = af_draw_hist(self.handle as WndHandle, hst.get() as AfArray, minval as c_double, maxval as c_double, cprops as *const Cell as CellPtr); - match err_val { - 0 => (), - _ => panic!("Rendering histogram failed: {}", err_val), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -301,10 +288,40 @@ impl Window { yvals.get() as AfArray, zvals.get() as AfArray, cprops as *const Cell as CellPtr); - match err_val { - 0 => (), - _ => panic!("Rendering surface failed: {}", err_val), - } + HANDLE_ERROR(AfError::from(err_val)); } } -} + + /// Render give Arrays as 2d scatter plot + pub fn draw_scatter(&self, xvals: &Array, yvals: &Array, marker: MarkerType, title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_scatter(self.handle as WndHandle, + xvals.get() as AfArray, + yvals.get() as AfArray, + marker as c_int, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } + + /// Render give Array as 3d scatter plot + pub fn draw_scatter3(&self, vals: &Array, marker: MarkerType, title: Option) { + let tstr = match title { + Some(s) => s, + None => format!("Cell({},{}))", self.col, self.row) + }; + let cprops = &Cell {row: self.row, col: self.col, title: tstr.clone(), cmap: self.cmap}; + unsafe { + let err_val = af_draw_scatter3(self.handle as WndHandle, + vals.get() as AfArray, + marker as c_int, + cprops as *const Cell as CellPtr); + HANDLE_ERROR(AfError::from(err_val)); + } + } +} \ No newline at end of file diff --git a/src/image/mod.rs b/src/image/mod.rs index 5188b0819..19bbc9639 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -1,13 +1,9 @@ extern crate libc; use array::Array; -use defines::AfError; -use defines::Aftype; -use defines::BorderType; -use defines::ColorSpace; -use defines::Connectivity; -use defines::InterpType; -use defines::YCCStd; +use defines::{AfError, BorderType, ColorSpace, Connectivity, InterpType, YCCStd}; +use error::HANDLE_ERROR; +use util::HasAfEnum; use self::libc::{uint8_t, c_uint, c_int, c_float, c_double}; type MutAfArray = *mut self::libc::c_longlong; @@ -95,6 +91,8 @@ extern { fn af_ycbcr2rgb(out: MutAfArray, input: AfArray, stnd: c_int) -> c_int; fn af_rgb2ycbcr(out: MutAfArray, input: AfArray, stnd: c_int) -> c_int; + fn af_is_image_io_available(out: *mut c_int) -> c_int; + fn af_transform_coordinates(out: MutAfArray, tf: AfArray, d0: c_float, d1: c_float) -> c_int; } /// Calculate the gradients @@ -113,16 +111,14 @@ extern { /// /// The second Array is `dy` which is the gradient along the 2nd dimension. #[allow(unused_mut)] -pub fn gradient(input: &Array) -> Result<(Array, Array), AfError> { +pub fn gradient(input: &Array) -> (Array, Array) { unsafe { let mut dx: i64 = 0; let mut dy: i64 = 0; let err_val = af_gradient(&mut dx as MutAfArray, &mut dy as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok((Array::from(dx), Array::from(dy))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(dx), Array::from(dy)) } } @@ -137,16 +133,14 @@ pub fn gradient(input: &Array) -> Result<(Array, Array), AfError> { /// /// An Array with pixel values loaded from the image #[allow(unused_mut)] -pub fn load_image(filename: String, is_color: bool) -> Result { +pub fn load_image(filename: String, is_color: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_load_image(&mut temp as MutAfArray, filename.clone().as_bytes().as_ptr() as *const u8, is_color as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -169,15 +163,13 @@ pub fn load_image(filename: String, is_color: bool) -> Result { /// /// An Array with pixel values loaded from the image #[allow(unused_mut)] -pub fn load_image_native(filename: String) -> Result { +pub fn load_image_native(filename: String) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_load_image_native(&mut temp as MutAfArray, filename.clone().as_bytes().as_ptr() as *const u8); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -188,14 +180,11 @@ pub fn load_image_native(filename: String) -> Result { /// - `filename` is the abolute path(includes filename) at which input Array is going to be saved /// - `input` is the Array to be stored into the image file #[allow(unused_mut)] -pub fn save_image(filename: String, input: &Array) -> Result<(), AfError> { +pub fn save_image(filename: String, input: &Array) { unsafe { let err_val = af_save_image(filename.clone().as_bytes().as_ptr() as *const u8, input.get() as AfArray); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -216,14 +205,11 @@ pub fn save_image(filename: String, input: &Array) -> Result<(), AfError> { /// - `filename` is name of file to be saved /// - `input` is the Array to be saved. Should be U8 for saving 8-bit image, U16 for 16-bit image, and F32 for 32-bit image. #[allow(unused_mut)] -pub fn save_image_native(filename: String, input: &Array) -> Result<(), AfError> { +pub fn save_image_native(filename: String, input: &Array) { unsafe { let err_val = af_save_image_native(filename.clone().as_bytes().as_ptr() as *const u8, input.get() as AfArray); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -249,15 +235,13 @@ pub fn save_image_native(filename: String, input: &Array) -> Result<(), AfError> /// Resized Array #[allow(unused_mut)] pub fn resize(input: &Array, odim0: i64, odim1: i64, - method: InterpType) -> Result { + method: InterpType) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_resize(&mut temp as MutAfArray, input.get() as AfArray, odim0 as DimT, odim1 as DimT, method as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -292,17 +276,15 @@ pub fn resize(input: &Array, odim0: i64, odim1: i64, /// Resized Array #[allow(unused_mut)] pub fn transform(input: &Array, trans: &Array, odim0: i64, odim1: i64, - method: InterpType, is_inverse: bool) -> Result { + method: InterpType, is_inverse: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_transform(&mut temp as MutAfArray, input.get() as AfArray, trans.get() as AfArray, odim0 as DimT, odim1 as DimT, method as uint8_t, is_inverse as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -337,15 +319,13 @@ pub fn transform(input: &Array, trans: &Array, odim0: i64, odim1: i64, /// Rotated Array #[allow(unused_mut)] pub fn rotate(input: &Array, theta: f64, crop: bool, - method: InterpType) -> Result { + method: InterpType) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_rotate(&mut temp as MutAfArray, input.get() as AfArray, theta as c_float, crop as c_int, method as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -378,7 +358,7 @@ pub fn rotate(input: &Array, theta: f64, crop: bool, /// Translated Image(Array). #[allow(unused_mut)] pub fn translate(input: &Array, trans0: f32, trans1: f32, - odim0: i64, odim1: i64, method: InterpType) -> Result { + odim0: i64, odim1: i64, method: InterpType) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_translate(&mut temp as MutAfArray, @@ -386,10 +366,8 @@ pub fn translate(input: &Array, trans0: f32, trans1: f32, trans0 as c_float, trans1 as c_float, odim0 as DimT, odim1 as DimT, method as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -413,7 +391,7 @@ pub fn translate(input: &Array, trans0: f32, trans1: f32, /// Translated Image(Array). #[allow(unused_mut)] pub fn scale(input: &Array, scale0: f32, scale1: f32, - odim0: i64, odim1: i64, method: InterpType) -> Result { + odim0: i64, odim1: i64, method: InterpType) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_scale(&mut temp as MutAfArray, @@ -421,10 +399,8 @@ pub fn scale(input: &Array, scale0: f32, scale1: f32, scale0 as c_float, scale1 as c_float, odim0 as DimT, odim1 as DimT, method as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -454,17 +430,15 @@ pub fn scale(input: &Array, scale0: f32, scale1: f32, /// Skewed Image #[allow(unused_mut)] pub fn skew(input: &Array, skew0: f32, skew1: f32, odim0: i64, odim1: i64, - method: InterpType, is_inverse: bool) -> Result { + method: InterpType, is_inverse: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_skew(&mut temp as MutAfArray, input.get() as AfArray, skew0 as c_float, skew1 as c_float, odim0 as DimT, odim1 as DimT, method as uint8_t, is_inverse as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -493,15 +467,13 @@ pub fn skew(input: &Array, skew0: f32, skew1: f32, odim0: i64, odim1: i64, /// Histogram of input Array #[allow(unused_mut)] pub fn histogram(input: &Array, nbins: u32, - minval: f64, maxval: f64) -> Result { + minval: f64, maxval: f64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_histogram(&mut temp as MutAfArray, input.get() as AfArray, nbins as c_uint, minval as c_double, maxval as c_double); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -525,15 +497,13 @@ pub fn histogram(input: &Array, nbins: u32, /// /// Dilated Image(Array) #[allow(unused_mut)] -pub fn dilate(input: &Array, mask: &Array) -> Result { +pub fn dilate(input: &Array, mask: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_dilate(&mut temp as MutAfArray, input.get() as AfArray, mask.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -558,15 +528,13 @@ pub fn dilate(input: &Array, mask: &Array) -> Result { /// /// Eroded Image(Array) #[allow(unused_mut)] -pub fn erode(input: &Array, mask: &Array) -> Result { +pub fn erode(input: &Array, mask: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_erode(&mut temp as MutAfArray, input.get() as AfArray, mask.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -584,15 +552,13 @@ pub fn erode(input: &Array, mask: &Array) -> Result { /// /// Dilated Volume(Array) #[allow(unused_mut)] -pub fn dilate3(input: &Array, mask: &Array) -> Result { +pub fn dilate3(input: &Array, mask: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_dilate3(&mut temp as MutAfArray, input.get() as AfArray, mask.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -610,15 +576,13 @@ pub fn dilate3(input: &Array, mask: &Array) -> Result { /// /// Eroded Volume(Array) #[allow(unused_mut)] -pub fn erode3(input: &Array, mask: &Array) -> Result { +pub fn erode3(input: &Array, mask: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_erode3(&mut temp as MutAfArray, input.get() as AfArray, mask.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -643,16 +607,14 @@ pub fn erode3(input: &Array, mask: &Array) -> Result { /// Filtered Image - Array #[allow(unused_mut)] pub fn bilateral(input: &Array, spatial_sigma: f32, chromatic_sigma: f32, - iscolor: bool) -> Result { + iscolor: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_bilateral(&mut temp as MutAfArray, input.get() as AfArray, spatial_sigma as c_float, chromatic_sigma as c_float, iscolor as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -678,16 +640,14 @@ pub fn bilateral(input: &Array, spatial_sigma: f32, chromatic_sigma: f32, /// Filtered Image - Array #[allow(unused_mut)] pub fn mean_shift(input: &Array, spatial_sigma: f32, chromatic_sigma: f32, - iter: u32, iscolor: bool) -> Result { + iter: u32, iscolor: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_mean_shift(&mut temp as MutAfArray, input.get() as AfArray, spatial_sigma as c_float, chromatic_sigma as c_float, iter as c_uint, iscolor as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -695,15 +655,13 @@ macro_rules! filt_func_def { ($fn_name: ident, $ffi_name: ident) => ( #[allow(unused_mut)] pub fn $fn_name(input: &Array, wlen: u64, wwid: u64, - etype: BorderType) -> Result { + etype: BorderType) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, input.get() as AfArray, wlen as DimT, wwid as DimT, etype as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -736,16 +694,14 @@ filt_func_def!(maxfilt, af_maxfilt); /// An Array with gaussian kernel values #[allow(unused_mut)] pub fn gaussian_kernel(rows: i32, cols: i32, - sigma_r: f64, sigma_c: f64) -> Result { + sigma_r: f64, sigma_c: f64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_gaussian_kernel(&mut temp as MutAfArray, rows as c_int, cols as c_int, sigma_r as c_double, sigma_c as c_double); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -785,15 +741,13 @@ pub fn gaussian_kernel(rows: i32, cols: i32, /// An Array with input image values in target color space #[allow(unused_mut)] pub fn color_space(input: &Array, - tospace: ColorSpace, fromspace: ColorSpace) -> Result { + tospace: ColorSpace, fromspace: ColorSpace) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_color_space(&mut temp as MutAfArray, input.get() as AfArray, tospace as uint8_t, fromspace as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -810,21 +764,19 @@ pub fn color_space(input: &Array, /// /// - `input` is the input image /// - `conn` can take one of the values of [Connectivity](./enum.Connectivity.html) -/// - `aftype` can take one of the values of [Aftype](./enum.Aftype.html) /// /// # Return Values /// /// Array with labels indicating different regions #[allow(unused_mut)] -pub fn regions(input: &Array, conn: Connectivity, aftype: Aftype) -> Result { +pub fn regions(input: &Array, conn: Connectivity) -> Array { unsafe { + let otype = OutType::get_af_dtype(); let mut temp: i64 = 0; let err_val = af_regions(&mut temp as MutAfArray, input.get() as AfArray, - conn as uint8_t, aftype as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + conn as uint8_t, otype as uint8_t); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -846,16 +798,14 @@ pub fn regions(input: &Array, conn: Connectivity, aftype: Aftype) -> Result Result<(Array, Array), AfError> { +pub fn sobel(input: &Array, ker_size: u32) -> (Array, Array) { unsafe { let mut dx: i64 = 0; let mut dy: i64 = 0; let err_val = af_sobel_operator(&mut dx as MutAfArray, &mut dy as MutAfArray, input.get() as AfArray, ker_size as c_uint); - match err_val { - 0 => Ok((Array::from(dx), Array::from(dy))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(dx), Array::from(dy)) } } @@ -869,15 +819,13 @@ pub fn sobel(input: &Array, ker_size: u32) -> Result<(Array, Array), AfError> { /// # Return Values /// Equalized Array #[allow(unused_mut)] -pub fn hist_equal(input: &Array, hist: &Array) -> Result { +pub fn hist_equal(input: &Array, hist: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_hist_equal(&mut temp as MutAfArray, input.get() as AfArray, hist.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -891,15 +839,13 @@ macro_rules! grayrgb_func_def { /// - `g` is fraction of green channel to appear in output /// - `b` is fraction of blue channel to appear in output #[allow(unused_mut)] - pub fn $fn_name(input: &Array, r: f32, g: f32, b: f32) -> Result { + pub fn $fn_name(input: &Array, r: f32, g: f32, b: f32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, input.get() as AfArray, r as c_float, g as c_float, b as c_float); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -912,14 +858,12 @@ macro_rules! hsvrgb_func_def { ($fn_name: ident, $ffi_name: ident) => ( /// Color space conversion functions #[allow(unused_mut)] - pub fn $fn_name(input: &Array) -> Result { + pub fn $fn_name(input: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -966,7 +910,7 @@ hsvrgb_func_def!(rgb2hsv, af_rgb2hsv); /// /// # Examples /// -/// ``` +/// ```ignore /// A [5 5 1 1] /// 10 15 20 25 30 /// 11 16 21 26 31 @@ -1002,15 +946,13 @@ pub fn unwrap(input: &Array, wx: i64, wy: i64, sx: i64, sy: i64, px: i64, py: i64, - is_column: bool) -> Result { + is_column: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_unwrap(&mut temp as MutAfArray, input.get() as AfArray, wx, wy, sx, sy, px, py, is_column as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -1040,15 +982,13 @@ pub fn unwrap(input: &Array, pub fn wrap(input: &Array, ox: i64, oy: i64, wx: i64, wy: i64, sx: i64, sy: i64, px: i64, py: i64, - is_column: bool) -> Result { + is_column: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_wrap(&mut temp as MutAfArray, input.get() as AfArray, ox, oy, wx, wy, sx, sy, px, py, is_column as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -1061,14 +1001,12 @@ pub fn wrap(input: &Array, /// # Return Values /// /// Summed area table (a.k.a Integral Image) of the input image. -pub fn sat(input: &Array) -> Result { +pub fn sat(input: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_sat(&mut temp as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -1092,15 +1030,13 @@ pub fn sat(input: &Array) -> Result { /// # Return Values /// /// Image(Array) in YCbCr color space -pub fn rgb2ycbcr(input: &Array, standard: YCCStd) -> Result { +pub fn rgb2ycbcr(input: &Array, standard: YCCStd) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_rgb2ycbcr(&mut temp as MutAfArray, input.get() as AfArray, standard as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -1130,14 +1066,57 @@ pub fn rgb2ycbcr(input: &Array, standard: YCCStd) -> Result { /// # Return Values /// /// Image(Array) in RGB color space -pub fn ycbcr2rgb(input: &Array, standard: YCCStd) -> Result { +pub fn ycbcr2rgb(input: &Array, standard: YCCStd) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_ycbcr2rgb(&mut temp as MutAfArray, input.get() as AfArray, standard as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +/// Function to check if Image I/O is available +/// +/// # Parameters +/// +/// None +/// +/// # Return Values +/// +/// Return a boolean indicating if ArrayFire was compiled with Image I/O support +pub fn is_imageio_available() -> bool { + unsafe { + let mut temp: i32 = 0; + af_is_image_io_available(&mut temp as *mut c_int); + temp > 0 // Return boolean flag } } + +/// Transform input coordinates +/// +/// The transform function uses a perspective transform matrix to transform input coordinates +/// (given as two dimensions) into a coordinates matrix. +/// +/// The output is a 4x2 matrix, indicating the coordinates of the 4 bidimensional transformed +/// points. +/// +/// # Parameters +/// +/// - `tf` is the transformation matrix +/// - `d0` is the first input dimension +/// - `d1` is the second input dimension +/// +/// # Return Values +/// +/// Transformed coordinates +pub fn transform_coords(tf: &Array, d0: f32, d1: f32) -> Array { + unsafe { + let mut temp: i64 = 0; + let err_val = af_transform_coordinates(&mut temp as MutAfArray, + tf.get() as AfArray, + d0 as c_float, d1 as c_float); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} \ No newline at end of file diff --git a/src/index.rs b/src/index.rs index c782b32a2..d45a93b5e 100644 --- a/src/index.rs +++ b/src/index.rs @@ -2,8 +2,9 @@ extern crate libc; use array::Array; use defines::AfError; +use error::HANDLE_ERROR; use seq::Seq; -use self::libc::{c_int, c_uint, c_longlong}; +use self::libc::{c_double, c_int, c_uint}; type MutAfIndex = *mut self::libc::c_longlong; type MutAfArray = *mut self::libc::c_longlong; @@ -15,12 +16,12 @@ type IndexT = self::libc::c_longlong; extern { fn af_create_indexers(indexers: MutAfIndex) -> c_int; fn af_set_array_indexer(indexer: MutAfIndex, idx: AfArray, dim: DimT) -> c_int; - fn af_set_seq_indexer(indexer: MutAfIndex, idx: *const Seq, dim: DimT, is_batch: c_int) -> c_int; + fn af_set_seq_indexer(indexer: MutAfIndex, idx: *const SeqInternal, dim: DimT, is_batch: c_int) -> c_int; fn af_release_indexers(indexers: MutAfIndex) -> c_int; - fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const Seq) -> c_int; + fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const SeqInternal) -> c_int; fn af_lookup(out: MutAfArray, arr: AfArray, indices: AfArray, dim: c_uint) -> c_int; - fn af_assign_seq(out: MutAfArray, lhs: AfArray, ndims: c_uint, indices: *const Seq, rhs: AfArray) -> c_int; + fn af_assign_seq(out: MutAfArray, lhs: AfArray, ndims: c_uint, indices: *const SeqInternal, rhs: AfArray) -> c_int; fn af_index_gen(out: MutAfArray, input: AfArray, ndims: DimT, indices: *const IndexT) -> c_int; fn af_assign_gen(out: MutAfArray, lhs: AfArray, ndims: DimT, indices: *const IndexT, rhs: AfArray) -> c_int; } @@ -36,7 +37,7 @@ pub struct Indexer { // Any object to be able to be passed on to [./struct.Indexer.html#method.set_index] method // should implement this trait with appropriate implementation pub trait Indexable { - fn set(&self, idxr: &Indexer, dim: u32, is_batch: Option) -> Result<(), AfError>; + fn set(&self, idxr: &Indexer, dim: u32, is_batch: Option); } /// Enables [Array](./struct.Array.html) to be used to index another Array @@ -45,15 +46,12 @@ pub trait Indexable { /// [assign_gen](./fn.assign_gen.html) impl Indexable for Array { #[allow(unused_variables)] - fn set(&self, idxr: &Indexer, dim: u32, is_batch: Option) -> Result<(), AfError> { + fn set(&self, idxr: &Indexer, dim: u32, is_batch: Option) { unsafe { let err_val = af_set_array_indexer(idxr.clone().get() as MutAfIndex, self.get() as AfArray, dim as DimT); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } } @@ -62,34 +60,30 @@ impl Indexable for Array { /// /// This is used in functions [index_gen](./fn.index_gen.html) and /// [assign_gen](./fn.assign_gen.html) -impl Indexable for Seq { - fn set(&self, idxr: &Indexer, dim: u32, is_batch: Option) -> Result<(), AfError> { +impl Indexable for Seq where c_double: From { + fn set(&self, idxr: &Indexer, dim: u32, is_batch: Option) { unsafe { - let err_val = af_set_seq_indexer(idxr.clone().get() as MutAfIndex, self as *const Seq, - dim as DimT, is_batch.unwrap() as c_int); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + let err_val = af_set_seq_indexer(idxr.clone().get() as MutAfIndex, + &SeqInternal::from_seq(self) as *const SeqInternal, + dim as DimT, is_batch.unwrap() as c_int); + HANDLE_ERROR(AfError::from(err_val)); } } } impl Indexer { #[allow(unused_mut)] - pub fn new() -> Result { + pub fn new() -> Indexer { unsafe { let mut temp: i64 = 0; let err_val = af_create_indexers(&mut temp as MutAfIndex); - match err_val { - 0 => Ok(Indexer{handle: temp, count: 0}), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Indexer{handle: temp, count: 0} } } /// Set either [Array](./struct.Array.html) or [Seq](./struct.Seq.html) to index an Array along `idx` dimension - pub fn set_index(&mut self, idx: &T, dim: u32, is_batch: Option) -> Result<(), AfError> { + pub fn set_index(&mut self, idx: &T, dim: u32, is_batch: Option) { self.count = self.count + 1; idx.set(self, dim, is_batch) } @@ -124,22 +118,26 @@ impl Drop for Indexer { /// # Examples /// /// ``` -/// let a = randu(dims, Aftype::F32).unwrap(); +/// use arrayfire::{Dim4, Seq, index, randu, print}; +/// let dims = Dim4::new(&[5, 5, 1, 1]); +/// let a = randu::(dims); /// let seqs = &[Seq::new(1.0, 3.0, 1.0), Seq::default()]; -/// let sub = index(&a, seqs).unwrap(); +/// let sub = index(&a, seqs); /// println!("a(seq(1, 3, 1), span)"); /// print(&sub); /// ``` -pub fn index(input: &Array, seqs: &[Seq]) -> Result { +pub fn index(input: &Array, seqs: &[Seq]) -> Array + where c_double: From +{ unsafe { let mut temp: i64 = 0; + // TODO: allocating a whole new array on the heap just for this is BAD + let seqs: Vec = seqs.iter().map(|s| SeqInternal::from_seq(s)).collect(); let err_val = af_index(&mut temp as MutAfArray , input.get() as AfArray, seqs.len() as u32 - , seqs.as_ptr() as *const Seq); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + , seqs.as_ptr() as *const SeqInternal); + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -148,35 +146,37 @@ pub fn index(input: &Array, seqs: &[Seq]) -> Result { /// # Examples /// /// ``` -/// let a = randu(dims, Aftype::F32).unwrap(); +/// use arrayfire::{Dim4, randu, row, print}; +/// let dims = Dim4::new(&[5, 5, 1, 1]); +/// let a = randu::(dims); /// println!("Grab last row of the random matrix"); /// print(&a); -/// print(&row(&a, num_rows - 1).unwrap()); +/// print(&row(&a, 4)); /// ``` #[allow(dead_code)] -pub fn row(input: &Array, row_num: u64) -> Result { - index(input, &[Seq::new(row_num as f64, row_num as f64, 1.0) - , Seq::default()]) +pub fn row(input: &Array, row_num: u64) -> Array { + index(input, &[Seq::new(row_num as f64, row_num as f64, 1.0), + Seq::default()]) } #[allow(dead_code)] /// Set row `row_num` in `input` Array to a new Array `new_row` -pub fn set_row(input: &Array, new_row: &Array, row_num: u64) -> Result { - assign_seq(input, &[Seq::new(row_num as f64, row_num as f64, 1.0), Seq::default()] - , new_row) +pub fn set_row(input: &Array, new_row: &Array, row_num: u64) -> Array { + assign_seq(input, + &[Seq::new(row_num as f64, row_num as f64, 1.0), Seq::default()], + new_row) } #[allow(dead_code)] /// Get all rows from `first` to `last` in the `input` Array -pub fn rows(input: &Array, first: u64, last: u64) -> Result { +pub fn rows(input: &Array, first: u64, last: u64) -> Array { index(input, &[Seq::new(first as f64, last as f64, 1.0), Seq::default()]) } #[allow(dead_code)] /// Set rows from `first` to `last` in `input` Array with rows from Array `new_rows` -pub fn set_rows(input: &Array, new_rows: &Array, first: u64, last: u64) -> Result { - assign_seq(input, &[Seq::new(first as f64, last as f64, 1.0), Seq::default()] - , new_rows) +pub fn set_rows(input: &Array, new_rows: &Array, first: u64, last: u64) -> Array { + assign_seq(input, &[Seq::new(first as f64, last as f64, 1.0), Seq::default()], new_rows) } /// Extract `col_num` col from `input` Array @@ -184,94 +184,87 @@ pub fn set_rows(input: &Array, new_rows: &Array, first: u64, last: u64) -> Resul /// # Examples /// /// ``` -/// let a = randu(dims, Aftype::F32).unwrap(); -/// println!("Grab last col of the random matrix"); +/// use arrayfire::{Dim4, randu, col, print}; +/// let dims = Dim4::new(&[5, 5, 1, 1]); +/// let a = randu::(dims); /// print(&a); -/// print(&row(&a, num_cols - 1).unwrap()); +/// println!("Grab last col of the random matrix"); +/// print(&col(&a, 4)); /// ``` #[allow(dead_code)] -pub fn col(input: &Array, col_num: u64) -> Result { - index(input, &[Seq::default() - , Seq::new(col_num as f64, col_num as f64, 1.0)]) +pub fn col(input: &Array, col_num: u64) -> Array { + index(input, &[Seq::default(), Seq::new(col_num as f64, col_num as f64, 1.0)]) } #[allow(dead_code)] /// Set col `col_num` in `input` Array to a new Array `new_col` -pub fn set_col(input: &Array, new_col: &Array, col_num: u64) -> Result { - assign_seq(input, &[Seq::default(), Seq::new(col_num as f64, col_num as f64, 1.0)] - , new_col) +pub fn set_col(input: &Array, new_col: &Array, col_num: u64) -> Array { + assign_seq(input, + &[Seq::default(), Seq::new(col_num as f64, col_num as f64, 1.0)], + new_col) } #[allow(dead_code)] /// Get all cols from `first` to `last` in the `input` Array -pub fn cols(input: &Array, first: u64, last: u64) -> Result { - index(input, &[Seq::default() - , Seq::new(first as f64, last as f64, 1.0)]) +pub fn cols(input: &Array, first: u64, last: u64) -> Array { + index(input, &[Seq::default(), Seq::new(first as f64, last as f64, 1.0)]) } #[allow(dead_code)] /// Set cols from `first` to `last` in `input` Array with cols from Array `new_cols` -pub fn set_cols(input: &Array, new_cols: &Array, first: u64, last: u64) -> Result { - assign_seq(input, &[Seq::default(), Seq::new(first as f64, last as f64, 1.0)] - , new_cols) +pub fn set_cols(input: &Array, new_cols: &Array, first: u64, last: u64) -> Array { + assign_seq(input, &[Seq::default(), Seq::new(first as f64, last as f64, 1.0)], new_cols) } #[allow(dead_code)] /// Get slice `slice_num` from `input` Array /// /// Slices indicate that the indexing is along 3rd dimension -pub fn slice(input: &Array, slice_num: u64) -> Result { - index(input, &[Seq::default() - , Seq::default() - , Seq::new(slice_num as f64, slice_num as f64, 1.0)]) +pub fn slice(input: &Array, slice_num: u64) -> Array { + index(input, + &[Seq::default(), Seq::default(), Seq::new(slice_num as f64, slice_num as f64, 1.0)]) } #[allow(dead_code)] /// Set slice `slice_num` in `input` Array to a new Array `new_slice` /// /// Slices indicate that the indexing is along 3rd dimension -pub fn set_slice(input: &Array, new_slice: &Array, slice_num: u64) -> Result { - assign_seq(input, &[Seq::default() - , Seq::default() - , Seq::new(slice_num as f64, slice_num as f64, 1.0)] - , new_slice) +pub fn set_slice(input: &Array, new_slice: &Array, slice_num: u64) -> Array { + assign_seq(input, + &[Seq::default(), Seq::default(), Seq::new(slice_num as f64, slice_num as f64, 1.0)], + new_slice) } #[allow(dead_code)] /// Get slices from `first` to `last` in `input` Array /// /// Slices indicate that the indexing is along 3rd dimension -pub fn slices(input: &Array, first: u64, last: u64) -> Result { - index(input, &[Seq::default() - , Seq::default() - , Seq::new(first as f64, last as f64, 1.0)]) +pub fn slices(input: &Array, first: u64, last: u64) -> Array { + index(input, + &[Seq::default(), Seq::default(), Seq::new(first as f64, last as f64, 1.0)]) } #[allow(dead_code)] /// Set `first` to `last` slices of `input` Array to a new Array `new_slices` /// /// Slices indicate that the indexing is along 3rd dimension -pub fn set_slices(input: &Array, new_slices: &Array, first: u64, last: u64) -> Result { - assign_seq(input, &[Seq::default() - , Seq::default() - , Seq::new(first as f64, last as f64, 1.0)] - , new_slices) +pub fn set_slices(input: &Array, new_slices: &Array, first: u64, last: u64) -> Array { + assign_seq(input, + &[Seq::default() , Seq::default(), Seq::new(first as f64, last as f64, 1.0)], + new_slices) } - /// Lookup(hash) an Array using another Array /// /// Given a dimension `seq_dim`, `indices` are lookedup in `input` and returned as a new /// Array if found -pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Result { +pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_lookup(&mut temp as MutAfArray, input.get() as AfArray, indices.get() as AfArray, seq_dim as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -282,10 +275,11 @@ pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Result Result Result { +pub fn assign_seq(lhs: &Array, seqs: &[Seq], rhs: &Array) -> Array + where c_double: From +{ unsafe{ let mut temp: i64 = 0; + // TODO: allocating a whole new array on the heap just for this is BAD + let seqs: Vec = seqs.iter().map(|s| SeqInternal::from_seq(s)).collect(); let err_val = af_assign_seq(&mut temp as MutAfArray, lhs.get() as AfArray, - seqs.len() as c_uint, seqs.as_ptr() as *const Seq, + seqs.len() as c_uint, seqs.as_ptr() as *const SeqInternal, rhs.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -318,10 +314,11 @@ pub fn assign_seq(lhs: &Array, seqs: &[Seq], rhs: &Array) -> Result(Dim4::new(&[5, 3, 1, 1])); /// // [5 3 1 1] /// // 0.0000 0.2190 0.3835 /// // 0.1315 0.0470 0.5194 @@ -330,29 +327,24 @@ pub fn assign_seq(lhs: &Array, seqs: &[Seq], rhs: &Array) -> Result v, -/// Err(e) => panic!("{}",e), -/// }; +/// let mut idxrs = Indexer::new(); /// idxrs.set_index(&indices, 0, None); // 2nd parameter is indexing dimension /// idxrs.set_index(&seq4gen, 1, Some(false)); // 3rd parameter indicates batch operation /// -/// let sub2 = index_gen(&a, idxrs).unwrap(); +/// let sub2 = index_gen(&a, idxrs); /// println!("a(indices, seq(0, 2, 1))"); print(&sub2); /// // [3 3 1 1] /// // 0.1315 0.0470 0.5194 /// // 0.7556 0.6789 0.8310 /// // 0.4587 0.6793 0.0346 /// ``` -pub fn index_gen(input: &Array, indices: Indexer) -> Result { +pub fn index_gen(input: &Array, indices: Indexer) -> Array { unsafe{ let mut temp: i64 = 0; let err_val = af_index_gen(&mut temp as MutAfArray, input.get() as AfArray, indices.len() as DimT, indices.get() as *const IndexT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -361,10 +353,11 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Result { /// # Examples /// /// ``` -/// let values: &[f32] = &[1.0, 2.0, 3.0]; -/// let indices = Array::new(Dim4::new(&[3, 1, 1, 1]), values, Aftype::F32).unwrap(); +/// use arrayfire::{Array, Dim4, Seq, print, randu, constant, Indexer, assign_gen}; +/// let values: [f32; 3] = [1.0, 2.0, 3.0]; +/// let indices = Array::new(&values, Dim4::new(&[3, 1, 1, 1])); /// let seq4gen = Seq::new(0.0, 2.0, 1.0); -/// let a = randu(Dim4::new(&[5, 3, 1, 1]), Aftype::F32).unwrap(); +/// let a = randu::(Dim4::new(&[5, 3, 1, 1])); /// // [5 3 1 1] /// // 0.0000 0.2190 0.3835 /// // 0.1315 0.0470 0.5194 @@ -372,16 +365,13 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Result { /// // 0.4587 0.6793 0.0346 /// // 0.5328 0.9347 0.0535 /// -/// let b = constant(2.0 as f32, Dim4::new(&[3, 3, 1, 1])).unwrap(); +/// let b = constant(2.0 as f32, Dim4::new(&[3, 3, 1, 1])); /// -/// let mut idxrs = match Indexer::new() { -/// Ok(v) => v, -/// Err(e) => panic!("{}",e), -/// }; +/// let mut idxrs = Indexer::new(); /// idxrs.set_index(&indices, 0, None); // 2nd parameter is indexing dimension /// idxrs.set_index(&seq4gen, 1, Some(false)); // 3rd parameter indicates batch operation /// -/// let sub2 = assign_gen(&a, idxrs, &b).unwrap(); +/// let sub2 = assign_gen(&a, &idxrs, &b); /// println!("a(indices, seq(0, 2, 1))"); print(&sub2); /// // [5 3 1 1] /// // 0.0000 0.2190 0.3835 @@ -390,15 +380,30 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Result { /// // 2.0000 2.0000 2.0000 /// // 0.5328 0.9347 0.0535 /// ``` -pub fn assign_gen(lhs: &Array, indices: &Indexer, rhs: &Array) -> Result { +pub fn assign_gen(lhs: &Array, indices: &Indexer, rhs: &Array) -> Array { unsafe{ let mut temp: i64 = 0; let err_val = af_assign_gen(&mut temp as MutAfArray, lhs.get() as AfArray, indices.len() as DimT, indices.get() as *const IndexT, rhs.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) + } +} + +#[repr(C)] +struct SeqInternal { + begin: c_double, + end: c_double, + step: c_double, +} + +impl SeqInternal { + fn from_seq(s: &Seq) -> Self where c_double: From { + SeqInternal { + begin: From::from(s.begin()), + end: From::from(s.end()), + step: From::from(s.step()), } } } diff --git a/src/lapack/mod.rs b/src/lapack/mod.rs index ca02805db..3afec476e 100644 --- a/src/lapack/mod.rs +++ b/src/lapack/mod.rs @@ -1,8 +1,8 @@ extern crate libc; use array::Array; -use defines::AfError; -use defines::{MatProp, NormType}; +use defines::{AfError, MatProp, NormType}; +use error::HANDLE_ERROR; use util::to_u32; use self::libc::{uint8_t, c_int, c_uint, c_double}; @@ -26,6 +26,7 @@ extern { fn af_rank(rank: *mut c_uint, input: AfArray, tol: c_double) -> c_int; fn af_det(det_real: MutDouble, det_imag: MutDouble, input: AfArray) -> c_int; fn af_norm(out: MutDouble, input: AfArray, ntype: uint8_t, p: c_double, q: c_double) -> c_int; + fn af_is_lapack_available(out: *mut c_int) -> c_int; } /// Perform Singular Value Decomposition @@ -52,17 +53,15 @@ extern { /// /// The third Array is the output array containing V ^ H #[allow(unused_mut)] -pub fn svd(input: &Array) -> Result<(Array, Array, Array), AfError> { +pub fn svd(input: &Array) -> (Array, Array, Array) { unsafe { let mut u: i64 = 0; let mut s: i64 = 0; let mut vt: i64 = 0; let err_val = af_svd(&mut u as MutAfArray, &mut s as MutAfArray, &mut vt as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok((Array::from(u), Array::from(s), Array::from(vt))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(u), Array::from(s), Array::from(vt)) } } @@ -91,17 +90,15 @@ pub fn svd(input: &Array) -> Result<(Array, Array, Array), AfError> { /// /// The third Array is the output array containing V ^ H #[allow(unused_mut)] -pub fn svd_inplace(input: &mut Array) -> Result<(Array, Array, Array), AfError> { +pub fn svd_inplace(input: &mut Array) -> (Array, Array, Array) { unsafe { let mut u: i64 = 0; let mut s: i64 = 0; let mut vt: i64 = 0; let err_val = af_svd_inplace(&mut u as MutAfArray, &mut s as MutAfArray, &mut vt as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok((Array::from(u), Array::from(s), Array::from(vt))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(u), Array::from(s), Array::from(vt)) } } @@ -121,17 +118,15 @@ pub fn svd_inplace(input: &mut Array) -> Result<(Array, Array, Array), AfError> /// /// The third Array will contain the permutation indices to map the input to the decomposition. #[allow(unused_mut)] -pub fn lu(input: &Array) -> Result<(Array, Array, Array), AfError> { +pub fn lu(input: &Array) -> (Array, Array, Array) { unsafe { let mut lower: i64 = 0; let mut upper: i64 = 0; let mut pivot: i64 = 0; let err_val = af_lu(&mut lower as MutAfArray, &mut upper as MutAfArray, &mut pivot as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok((Array::from(lower), Array::from(upper), Array::from(pivot))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(lower), Array::from(upper), Array::from(pivot)) } } @@ -147,15 +142,13 @@ pub fn lu(input: &Array) -> Result<(Array, Array, Array), AfError> { /// An Array with permutation indices to map the input to the decomposition. Since, the input /// matrix is modified in place, only pivot values are returned. #[allow(unused_mut)] -pub fn lu_inplace(input: &mut Array, is_lapack_piv: bool) -> Result { +pub fn lu_inplace(input: &mut Array, is_lapack_piv: bool) -> Array { unsafe { let mut pivot: i64 = 0; let err_val = af_lu_inplace(&mut pivot as MutAfArray, input.get() as AfArray, is_lapack_piv as c_int); - match err_val { - 0 => Ok(Array::from(pivot)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(pivot) } } @@ -176,17 +169,15 @@ pub fn lu_inplace(input: &mut Array, is_lapack_piv: bool) -> Result Result<(Array, Array, Array), AfError> { +pub fn qr(input: &Array) -> (Array, Array, Array) { unsafe { let mut q: i64 = 0; let mut r: i64 = 0; let mut tau: i64 = 0; let err_val = af_qr(&mut q as MutAfArray, &mut r as MutAfArray, &mut tau as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok((Array::from(q), Array::from(r), Array::from(tau))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(q), Array::from(r), Array::from(tau)) } } @@ -200,14 +191,12 @@ pub fn qr(input: &Array) -> Result<(Array, Array, Array), AfError> { /// /// An Array with additional information needed for unpacking the data. #[allow(unused_mut)] -pub fn qr_inplace(input: &mut Array) -> Result { +pub fn qr_inplace(input: &mut Array) -> Array { unsafe { let mut tau: i64 = 0; let err_val = af_qr_inplace(&mut tau as MutAfArray, input.get() as AfArray); - match err_val { - 0 => Ok(Array::from(tau)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(tau) } } @@ -227,16 +216,14 @@ pub fn qr_inplace(input: &mut Array) -> Result { /// If the integer is 0, it means the cholesky decomposition passed. Otherwise, it will contain the rank at /// which the decomposition failed. #[allow(unused_mut)] -pub fn cholesky(input: &Array, is_upper: bool) -> Result<(Array, i32), AfError> { +pub fn cholesky(input: &Array, is_upper: bool) -> (Array, i32) { unsafe { let mut temp: i64 = 0; let mut info: i32 = 0; let err_val = af_cholesky(&mut temp as MutAfArray, &mut info as *mut c_int, input.get() as AfArray, is_upper as c_int); - match err_val { - 0 => Ok((Array::from(temp), info)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(temp), info) } } @@ -252,15 +239,13 @@ pub fn cholesky(input: &Array, is_upper: bool) -> Result<(Array, i32), AfError> /// A signed 32-bit integer. If the integer is 0, it means the cholesky decomposition passed. Otherwise, /// it will contain the rank at which the decomposition failed. #[allow(unused_mut)] -pub fn cholesky_inplace(input: &mut Array, is_upper: bool) -> Result { +pub fn cholesky_inplace(input: &mut Array, is_upper: bool) -> i32 { unsafe { let mut info: i32 = 0; let err_val = af_cholesky_inplace(&mut info as *mut c_int, input.get() as AfArray, is_upper as c_int); - match err_val { - 0 => Ok(info), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + info } } @@ -278,15 +263,13 @@ pub fn cholesky_inplace(input: &mut Array, is_upper: bool) -> Result Result { +pub fn solve(a: &Array, b: &Array, options: MatProp) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_solve(&mut temp as MutAfArray, a.get() as AfArray, b.get() as AfArray, to_u32(options) as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -306,15 +289,13 @@ pub fn solve(a: &Array, b: &Array, options: MatProp) -> Result { /// An Array which is the matrix of unknown variables #[allow(unused_mut)] pub fn solve_lu(a: &Array, piv: &Array, b: &Array, - options: MatProp) -> Result { + options: MatProp) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_solve_lu(&mut temp as MutAfArray, a.get() as AfArray, piv.get() as AfArray, b.get() as AfArray, to_u32(options) as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -331,14 +312,12 @@ pub fn solve_lu(a: &Array, piv: &Array, b: &Array, /// /// An Array with values of the inverse of input matrix. #[allow(unused_mut)] -pub fn inverse(input: &Array, options: MatProp) -> Result { +pub fn inverse(input: &Array, options: MatProp) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_inverse(&mut temp as MutAfArray, input.get() as AfArray, to_u32(options) as c_uint); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -353,14 +332,12 @@ pub fn inverse(input: &Array, options: MatProp) -> Result { /// /// An unsigned 32-bit integer which is the rank of the input matrix. #[allow(unused_mut)] -pub fn rank(input: &Array, tol: f64) -> Result { +pub fn rank(input: &Array, tol: f64) -> u32 { unsafe { let mut temp: u32 = 0; let err_val = af_rank(&mut temp as *mut c_uint, input.get() as AfArray, tol as c_double); - match err_val { - 0 => Ok(temp), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp } } @@ -376,15 +353,13 @@ pub fn rank(input: &Array, tol: f64) -> Result { /// /// If the input matrix is non-complex type, only first values of tuple contains the result. #[allow(unused_mut)] -pub fn det(input: &Array) -> Result<(f64, f64), AfError> { +pub fn det(input: &Array) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = af_det(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } @@ -403,14 +378,29 @@ pub fn det(input: &Array) -> Result<(f64, f64), AfError> { /// /// A 64-bit floating point value that contains the norm of input matrix. #[allow(unused_mut)] -pub fn norm(input: &Array, ntype: NormType, p: f64, q: f64) -> Result { +pub fn norm(input: &Array, ntype: NormType, p: f64, q: f64) -> f64 { unsafe { let mut out: f64 = 0.0; let err_val = af_norm(&mut out as MutDouble, input.get() as AfArray, ntype as uint8_t, p as c_double, q as c_double); - match err_val { - 0 => Ok(out), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + out } } + +/// Function to check if lapack support is available +/// +/// # Parameters +/// +/// None +/// +/// # Return Values +/// +/// Return a boolean indicating if ArrayFire was compiled with lapack support +pub fn is_lapack_available() -> bool { + unsafe { + let mut temp: i32 = 0; + af_is_lapack_available(&mut temp as *mut c_int); + temp > 0 // Return boolean fla + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index a09af0e1c..18c0ce186 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,9 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://arrayfire.com/docs/rust")] +#[macro_use] +extern crate lazy_static; + pub use array::Array; pub use array::{print}; mod array; @@ -23,7 +26,7 @@ pub use arith::{sqrt, log, log1p, log10, log2, pow2, exp, expm1, erf, erfc, root pub use arith::{cbrt, factorial, tgamma, lgamma, iszero, isinf, isnan}; mod arith; -pub use backend::{set_backend, get_backend_count, get_available_backends}; +pub use backend::{set_backend, get_backend_count, get_available_backends, get_active_backend}; mod backend; pub use blas::{matmul, dot, transpose, transpose_inplace}; @@ -37,17 +40,22 @@ pub use data::{reorder, shift, moddims, flat, flip}; pub use data::{select, selectl, selectr, replace, replace_scalar}; mod data; -pub use device::{get_version, info, device_count, is_double_available, set_device, get_device, sync}; +pub use device::{get_version, info, init, device_count, is_double_available, set_device, get_device}; +pub use device::{device_mem_info, print_mem_info, set_mem_step_size, get_mem_step_size, device_gc, sync}; mod device; -pub use defines::{Aftype, AfError, Backend, ColorMap, YCCStd, HomographyType}; +pub use defines::{DType, AfError, Backend, ColorMap, YCCStd, HomographyType}; pub use defines::{InterpType, BorderType, MatchType, NormType}; pub use defines::{Connectivity, ConvMode, ConvDomain, ColorSpace, MatProp}; +pub use defines::{MarkerType}; mod defines; pub use dim4::Dim4; mod dim4; +pub use error::{Callback, ErrorCallback, register_error_handler, handle_error_general}; +mod error; + pub use index::{Indexer, index, row, rows, col, cols, slice, slices, set_row, set_rows, set_col, set_cols, set_slice, set_slices, lookup, assign_seq, index_gen, assign_gen}; @@ -65,12 +73,14 @@ pub use image::{dilate, dilate3, erode, erode3, minfilt, maxfilt}; pub use image::{gradient, histogram, hist_equal, regions}; pub use image::{gray2rgb, rgb2gray, hsv2rgb, rgb2hsv, color_space}; pub use image::{bilateral, mean_shift, medfilt, sobel}; -pub use image::{unwrap, wrap, sat, rgb2ycbcr, ycbcr2rgb}; +pub use image::{unwrap, wrap, sat, rgb2ycbcr, ycbcr2rgb, is_imageio_available, transform_coords}; mod image; pub use lapack::{svd, lu, qr, cholesky, solve, solve_lu, inverse, det, rank, norm}; -pub use lapack::{svd_inplace, lu_inplace, qr_inplace, cholesky_inplace}; +pub use lapack::{svd_inplace, lu_inplace, qr_inplace, cholesky_inplace, is_lapack_available}; mod lapack; +mod macros; +mod num; pub use signal::{approx1, approx2}; pub use signal::{fft, fft2, fft3, ifft, ifft2, ifft3}; @@ -88,6 +98,7 @@ pub use statistics::{var_all, mean_all, stdev_all, median_all}; pub use statistics::{mean_all_weighted, var_all_weighted}; mod statistics; +pub use util::{HasAfEnum}; mod util; pub use vision::Features; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 000000000..bc509379a --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,130 @@ +/// Macro to print the current stats of ArrayFire's memory manager. +/// +/// `mem_info!` print 4 values: +/// +/// Name | Description +/// -------------------------|------------------------- +/// Allocated Bytes | Total number of bytes allocated by the memory manager +/// Allocated Buffers | Total number of buffers allocated +/// Locked (In Use) Bytes | Number of bytes that are in use by active arrays +/// Locked (In Use) Buffers | Number of buffers that are in use by active arrays +/// +/// The `Allocated Bytes` is always a multiple of the memory step size. The +/// default step size is 1024 bytes. This means when a buffer is to be +/// allocated, the size is always rounded up to a multiple of the step size. +/// You can use [get_mem_step_size](./fn.get_mem_step_size.html) to check the +/// current step size and [set_mem_step_size](./fn.set_mem_step_size.html) to +/// set a custom resolution size. +/// +/// The `Allocated Buffers` is the number of buffers that use up the allocated +/// bytes. This includes buffers currently in scope, as well as buffers marked +/// as free, ie, from arrays gone out of scope. The free buffers are available +/// for use by new arrays that might be created. +/// +/// The `Locked Bytes` is the number of bytes in use that cannot be +/// reallocated at the moment. The difference of Allocated Bytes and Locked +/// Bytes is the total bytes available for reallocation. +/// +/// The `Locked Buffers` is the number of buffer in use that cannot be +/// reallocated at the moment. The difference of Allocated Buffers and Locked +/// Buffers is the number of buffers available for reallocation. +/// +/// # Parameters +/// +/// - `msg` is the message that is printed to screen before printing stats +/// +/// # Examples +/// +/// ``` +/// # #[macro_use(mem_info)] extern crate arrayfire; +/// # fn main() { +/// use arrayfire::{Dim4, device_mem_info, print, randu}; +/// +/// let dims = Dim4::new(&[5, 5, 1, 1]); +/// let a = randu::(dims); +/// print(&a); +/// mem_info!("Hello!"); +/// # } +/// ``` +/// +/// Sample Output: +/// +/// ```ignore +/// AF Memory: Here +/// Allocated [ Bytes | Buffers ] = [ 4096 | 4 ] +/// In Use [ Bytes | Buffers ] = [ 2048 | 2 ] +/// ``` +#[macro_export] +macro_rules! mem_info { + [$msg: expr] => { + { + let (abytes, abuffs, lbytes, lbuffs) = device_mem_info(); + println!("AF Memory: {:?}", $msg); + println!("Allocated [Bytes | Buffers] = [ {} | {} ]", abytes, abuffs); + println!("In Use [Bytes | Buffers] = [ {} | {} ]", lbytes, lbuffs); + } + }; +} + +/// Join multiple Arrays along a given dimension +/// +/// All the Arrays provided to this macro should be of type `&Array` +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate arrayfire; +/// +/// # fn main() { +/// use arrayfire::{Dim4, join_many, print, randu}; +/// +/// let a = &randu::(Dim4::new(&[5, 3, 1, 1])); +/// let b = &randu::(Dim4::new(&[5, 3, 1, 1])); +/// let c = &randu::(Dim4::new(&[5, 3, 1, 1])); +/// let d = join_many![2; a, b, c]; +/// print(&d); +/// # } +/// ``` +/// +/// # Panics +/// +/// This macro just calls [join_many](./fn.join_many.html) function after collecting all +/// the input arrays into a vector. +// Using macro to implement join many wrapper +#[macro_export] +macro_rules! join_many { + [$dim: expr; $($x:ident),+] => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push($x); + )* + join_many($dim, temp_vec) + } + }; +} + +/// Print given message before printing out the Array to standard output +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate arrayfire; +/// +/// # fn main() { +/// use arrayfire::{Dim4, print, randu}; +/// let dims = Dim4::new(&[3, 1, 1, 1]); +/// let a = randu::(dims); +/// af_print!("Create a 5-by-3 matrix of random floats on the GPU", a); +/// # } +/// ``` +/// +#[macro_export] +macro_rules! af_print { + [$msg: expr, $x: ident] => { + { + println!("{}", $msg); + print(&$x); + } + }; +} diff --git a/src/num.rs b/src/num.rs new file mode 100644 index 000000000..d5858d486 --- /dev/null +++ b/src/num.rs @@ -0,0 +1,46 @@ +pub trait Zero { + fn zero() -> Self; +} + +pub trait One { + fn one() -> Self; +} + +macro_rules! zero_impl { + ( $t:ident, $z:expr ) => ( + impl Zero for $t { fn zero() -> Self { $z } } + ) +} + +zero_impl!(u8, 0); +zero_impl!(u16, 0); +zero_impl!(u32, 0); +zero_impl!(u64, 0); +zero_impl!(usize, 0); +zero_impl!(i8, 0); +zero_impl!(i16, 0); +zero_impl!(i32, 0); +zero_impl!(i64, 0); +zero_impl!(isize, 0); +zero_impl!(f32, 0.0); +zero_impl!(f64, 0.0); + + +macro_rules! one_impl { + ( $t:ident, $o:expr ) => ( + impl One for $t { fn one() -> Self { $o } } + ) +} + +one_impl!(u8, 1); +one_impl!(u16, 1); +one_impl!(u32, 1); +one_impl!(u64, 1); +one_impl!(usize, 1); +one_impl!(i8, 1); +one_impl!(i16, 1); +one_impl!(i32, 1); +one_impl!(i64, 1); +one_impl!(isize, 1); +one_impl!(f32, 1.0); +one_impl!(f64, 1.0); diff --git a/src/seq.rs b/src/seq.rs index ae0a43b96..a56410362 100644 --- a/src/seq.rs +++ b/src/seq.rs @@ -2,49 +2,50 @@ extern crate libc; use std::fmt; use std::default::Default; -use self::libc::{c_double}; + +use num::{One, Zero}; /// Sequences are used for indexing Arrays #[derive(Copy, Clone)] #[repr(C)] -pub struct Seq { - begin: c_double, - end: c_double, - step: c_double, +pub struct Seq { + begin: T, + end: T, + step: T, } /// Default `Seq` spans all the elements along a dimension -impl Default for Seq { - fn default() -> Seq { - Seq { begin: 1.0, end: 1.0, step: 0.0, } +impl Default for Seq { + fn default() -> Self { + Seq { begin: One::one(), end: One::one(), step: Zero::zero() } } } /// Enables use of `Seq` with `{}` format in print statements -impl fmt::Display for Seq { +impl fmt::Display for Seq { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[begin: {}, end: {}, step: {}]", self.begin, self.end, self.step) } } -impl Seq { +impl Seq { /// Create a `Seq` that goes from `begin` to `end` at a step size of `step` - pub fn new(begin: f64, end: f64, step: f64) -> Seq { + pub fn new(begin: T, end: T, step: T) -> Self { Seq { begin: begin, end: end, step: step, } } /// Get begin index of Seq - pub fn begin(&self) -> f64 { - self.begin as f64 + pub fn begin(&self) -> T { + self.begin } /// Get begin index of Seq - pub fn end(&self) -> f64 { - self.end as f64 + pub fn end(&self) -> T { + self.end } /// Get step size of Seq - pub fn step(&self) -> f64 { - self.step as f64 + pub fn step(&self) -> T { + self.step } } diff --git a/src/signal/mod.rs b/src/signal/mod.rs index 10e566a81..ac1c385c9 100644 --- a/src/signal/mod.rs +++ b/src/signal/mod.rs @@ -1,10 +1,8 @@ extern crate libc; use array::Array; -use defines::AfError; -use defines::InterpType; -use defines::ConvMode; -use defines::ConvDomain; +use defines::{AfError, ConvDomain, ConvMode, InterpType}; +use error::HANDLE_ERROR; use self::libc::{uint8_t, c_int, c_float, c_double, c_longlong}; type MutAfArray = *mut self::libc::c_longlong; @@ -80,15 +78,13 @@ extern { /// An Array with interpolated values #[allow(unused_mut)] pub fn approx1(input: &Array, pos: &Array, - method: InterpType, off_grid: f32) -> Result { + method: InterpType, off_grid: f32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_approx1(&mut temp as MutAfArray, input.get() as AfArray, pos.get() as AfArray, method as c_int, off_grid as c_float); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -108,16 +104,14 @@ pub fn approx1(input: &Array, pos: &Array, /// /// An Array with interpolated values pub fn approx2(input: &Array, pos0: &Array, pos1: &Array, - method: InterpType, off_grid: f32) -> Result { + method: InterpType, off_grid: f32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_approx2(&mut temp as MutAfArray, input.get() as AfArray, pos0.get() as AfArray, pos1.get() as AfArray, method as c_int, off_grid as c_float); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -135,16 +129,14 @@ pub fn approx2(input: &Array, pos0: &Array, pos1: &Array, /// /// Transformed Array #[allow(unused_mut)] -pub fn fft(input: &Array, norm_factor: f64, odim0: i64) -> Result { +pub fn fft(input: &Array, norm_factor: f64, odim0: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, odim0 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -162,16 +154,14 @@ pub fn fft(input: &Array, norm_factor: f64, odim0: i64) -> Result Result { +pub fn fft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft2(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -191,16 +181,14 @@ pub fn fft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Result Result { + odim0: i64, odim1: i64, odim2: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft3(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong, odim2 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -218,16 +206,14 @@ pub fn fft3(input: &Array, norm_factor: f64, /// /// Transformed Array #[allow(unused_mut)] -pub fn ifft(input: &Array, norm_factor: f64, odim0: i64) -> Result { +pub fn ifft(input: &Array, norm_factor: f64, odim0: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_ifft(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, odim0 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -245,16 +231,14 @@ pub fn ifft(input: &Array, norm_factor: f64, odim0: i64) -> Result Result { +pub fn ifft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_ifft2(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -274,16 +258,14 @@ pub fn ifft2(input: &Array, norm_factor: f64, odim0: i64, odim1: i64) -> Result< /// Transformed Array #[allow(unused_mut)] pub fn ifft3(input: &Array, norm_factor: f64, - odim0: i64, odim1: i64, odim2: i64) -> Result { + odim0: i64, odim1: i64, odim2: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_ifft3(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, odim0 as c_longlong, odim1 as c_longlong, odim2 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -312,16 +294,14 @@ macro_rules! conv_func_def { /// The convolved Array #[allow(unused_mut)] pub fn $fn_name(signal: &Array, filter: &Array, - mode: ConvMode, domain: ConvDomain) -> Result { + mode: ConvMode, domain: ConvDomain) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, signal.get() as AfArray, filter.get() as AfArray, mode as uint8_t, domain as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -345,16 +325,14 @@ conv_func_def!(convolve3, af_convolve3); /// The convolved Array #[allow(unused_mut)] pub fn convolve2_sep(cfilt: &Array, rfilt: &Array, signal: &Array, - mode: ConvMode) -> Result { + mode: ConvMode) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_convolve2_sep(&mut temp as MutAfArray, cfilt.get() as AfArray, rfilt.get() as AfArray, signal.get() as AfArray, mode as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -381,15 +359,13 @@ macro_rules! fft_conv_func_def { /// The convolved Array #[allow(unused_mut)] pub fn $fn_name(signal: &Array, filter: &Array, - mode: ConvMode) -> Result { + mode: ConvMode) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, signal.get() as AfArray, filter.get() as AfArray, mode as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -410,14 +386,12 @@ fft_conv_func_def!(fft_convolve3, af_fft_convolve3); /// /// Filtered Array #[allow(unused_mut)] -pub fn fir(b: &Array, x: &Array) -> Result { +pub fn fir(b: &Array, x: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fir(&mut temp as MutAfArray, b.get() as AfArray, x.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -433,15 +407,13 @@ pub fn fir(b: &Array, x: &Array) -> Result { /// /// Filtered Array #[allow(unused_mut)] -pub fn iir(b: &Array, a: &Array, x: &Array) -> Result { +pub fn iir(b: &Array, a: &Array, x: &Array) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_iir(&mut temp as MutAfArray, b.get() as AfArray, a.get() as AfArray, x.get() as AfArray); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -451,13 +423,10 @@ pub fn iir(b: &Array, a: &Array, x: &Array) -> Result { /// /// - `input` is the input Array /// - `norm_factor` is the normalization factor -pub fn fft_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { +pub fn fft_inplace(input: &Array, norm_factor: f64) { unsafe { let err_val = af_fft_inplace(input.get() as AfArray, norm_factor as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -467,13 +436,10 @@ pub fn fft_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { /// /// - `input` is the input Array /// - `norm_factor` is the normalization factor -pub fn fft2_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { +pub fn fft2_inplace(input: &Array, norm_factor: f64) { unsafe { let err_val = af_fft2_inplace(input.get() as AfArray, norm_factor as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -483,13 +449,10 @@ pub fn fft2_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { /// /// - `input` is the input Array /// - `norm_factor` is the normalization factor -pub fn fft3_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { +pub fn fft3_inplace(input: &Array, norm_factor: f64) { unsafe { let err_val = af_fft3_inplace(input.get() as AfArray, norm_factor as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -499,13 +462,10 @@ pub fn fft3_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { /// /// - `input` is the input Array /// - `norm_factor` is the normalization factor -pub fn ifft_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { +pub fn ifft_inplace(input: &Array, norm_factor: f64) { unsafe { let err_val = af_ifft_inplace(input.get() as AfArray, norm_factor as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -515,13 +475,10 @@ pub fn ifft_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { /// /// - `input` is the input Array /// - `norm_factor` is the normalization factor -pub fn ifft2_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { +pub fn ifft2_inplace(input: &Array, norm_factor: f64) { unsafe { let err_val = af_ifft2_inplace(input.get() as AfArray, norm_factor as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -531,13 +488,10 @@ pub fn ifft2_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { /// /// - `input` is the input Array /// - `norm_factor` is the normalization factor -pub fn ifft3_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { +pub fn ifft3_inplace(input: &Array, norm_factor: f64) { unsafe { let err_val = af_ifft3_inplace(input.get() as AfArray, norm_factor as c_double); - match err_val { - 0 => Ok(()), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); } } @@ -552,15 +506,13 @@ pub fn ifft3_inplace(input: &Array, norm_factor: f64) -> Result<(), AfError> { /// # Return Values /// /// Complex Array -pub fn fft_r2c(input: &Array, norm_factor: f64, pad0: i64) -> Result { +pub fn fft_r2c(input: &Array, norm_factor: f64, pad0: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft_r2c(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, pad0 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -576,15 +528,13 @@ pub fn fft_r2c(input: &Array, norm_factor: f64, pad0: i64) -> Result Result { +pub fn fft2_r2c(input: &Array, norm_factor: f64, pad0: i64, pad1: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft2_r2c(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, pad0 as c_longlong, pad1 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -601,16 +551,14 @@ pub fn fft2_r2c(input: &Array, norm_factor: f64, pad0: i64, pad1: i64) -> Result /// # Return Values /// /// Complex Array -pub fn fft3_r2c(input: &Array, norm_factor: f64, pad0: i64, pad1: i64, pad2: i64) -> Result { +pub fn fft3_r2c(input: &Array, norm_factor: f64, pad0: i64, pad1: i64, pad2: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft3_r2c(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, pad0 as c_longlong, pad1 as c_longlong, pad2 as c_longlong); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -625,15 +573,13 @@ pub fn fft3_r2c(input: &Array, norm_factor: f64, pad0: i64, pad1: i64, pad2: i64 /// # Return Values /// /// Complex Array -pub fn fft_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Result { +pub fn fft_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft_c2r(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, is_odd as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -648,15 +594,13 @@ pub fn fft_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Result Result { +pub fn fft2_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft2_c2r(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, is_odd as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -671,14 +615,12 @@ pub fn fft2_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Result Result { +pub fn fft3_c2r(input: &Array, norm_factor: f64, is_odd: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_fft3_c2r(&mut temp as MutAfArray, input.get() as AfArray, norm_factor as c_double, is_odd as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } -} +} \ No newline at end of file diff --git a/src/statistics/mod.rs b/src/statistics/mod.rs index b01327006..12ccea02f 100644 --- a/src/statistics/mod.rs +++ b/src/statistics/mod.rs @@ -2,6 +2,7 @@ extern crate libc; use array::Array; use defines::AfError; +use error::HANDLE_ERROR; use self::libc::{c_int}; type MutAfArray = *mut self::libc::c_longlong; @@ -46,14 +47,12 @@ macro_rules! stat_func_def { /// An Array whose size is equal to input except along the dimension which the stat /// operation is performed. Array size along `dim` will be reduced to one. #[allow(unused_mut)] - pub fn $fn_name(input: &Array, dim: i64) -> Result { + pub fn $fn_name(input: &Array, dim: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_fn(&mut temp as MutAfArray, input.get() as AfArray, dim as DimT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -78,15 +77,13 @@ macro_rules! stat_wtd_func_def { /// An Array whose size is equal to input except along the dimension which the stat /// operation is performed. Array size along `dim` will be reduced to one. #[allow(unused_mut)] - pub fn $fn_name(input: &Array, weights: &Array, dim: i64) -> Result { + pub fn $fn_name(input: &Array, weights: &Array, dim: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_fn(&mut temp as MutAfArray, input.get() as AfArray, weights.get() as AfArray, dim as DimT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } ) @@ -107,15 +104,13 @@ stat_wtd_func_def!(var_weighted, af_var_weighted); /// /// Array with variance of input Array `arr` along dimension `dim`. #[allow(unused_mut)] -pub fn var(arr: &Array, isbiased: bool, dim: i64) -> Result { +pub fn var(arr: &Array, isbiased: bool, dim: i64) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_var(&mut temp as MutAfArray, arr.get() as AfArray, isbiased as c_int, dim as DimT); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -131,15 +126,13 @@ pub fn var(arr: &Array, isbiased: bool, dim: i64) -> Result { /// /// An Array with Covariance values #[allow(unused_mut)] -pub fn cov(x: &Array, y: &Array, isbiased: bool) -> Result { +pub fn cov(x: &Array, y: &Array, isbiased: bool) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_cov(&mut temp as MutAfArray, x.get() as AfArray, y.get() as AfArray, isbiased as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -154,16 +147,14 @@ pub fn cov(x: &Array, y: &Array, isbiased: bool) -> Result { /// /// A tuple of 64-bit floating point values that has the variance of `input` Array. #[allow(unused_mut)] -pub fn var_all(input: &Array, isbiased: bool) -> Result<(f64, f64), AfError> { +pub fn var_all(input: &Array, isbiased: bool) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = af_var_all(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray, isbiased as c_int); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } @@ -179,16 +170,14 @@ macro_rules! stat_all_func_def { /// /// A tuple of 64-bit floating point values with the stat values. #[allow(unused_mut)] - pub fn $fn_name(input: &Array) -> Result<(f64, f64), AfError> { + pub fn $fn_name(input: &Array) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = $ffi_fn(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } ) @@ -211,16 +200,14 @@ macro_rules! stat_wtd_all_func_def { /// /// A tuple of 64-bit floating point values with the stat values. #[allow(unused_mut)] - pub fn $fn_name(input: &Array, weights: &Array) -> Result<(f64, f64), AfError> { + pub fn $fn_name(input: &Array, weights: &Array) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = $ffi_fn(&mut real as MutDouble, &mut imag as MutDouble, input.get() as AfArray, weights.get() as AfArray); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } } ) @@ -239,15 +226,13 @@ stat_wtd_all_func_def!(var_all_weighted, af_var_all_weighted); /// # Return Values /// A tuple of 64-bit floating point values with the coefficients. #[allow(unused_mut)] -pub fn corrcoef(x: &Array, y: &Array) -> Result<(f64, f64), AfError> { +pub fn corrcoef(x: &Array, y: &Array) -> (f64, f64) { unsafe { let mut real: f64 = 0.0; let mut imag: f64 = 0.0; let err_val = af_corrcoef(&mut real as MutDouble, &mut imag as MutDouble, x.get() as AfArray, y.get() as AfArray); - match err_val { - 0 => Ok((real, imag)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (real, imag) } -} +} \ No newline at end of file diff --git a/src/util.rs b/src/util.rs index a26a74c0c..ba1726453 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,12 +1,8 @@ -use defines::AfError; -use defines::Aftype; -use defines::InterpType; -use defines::ConvMode; -use defines::ConvDomain; -use defines::MatProp; -use defines::MatchType; -use defines::ColorMap; +extern crate num; + +use defines::{AfError, ColorMap, ConvDomain, ConvMode, DType, InterpType, MatProp, MatchType}; use std::mem; +use self::num::Complex; impl From for AfError { fn from(t: i32) -> AfError { @@ -15,37 +11,37 @@ impl From for AfError { } } -impl From for Aftype { - fn from(t: u8) -> Aftype { - assert!(Aftype::F32 as u8 <= t && t <= Aftype::U64 as u8); +impl From for DType { + fn from(t: i32) -> DType { + assert!(DType::F32 as i32 <= t && t <= DType::U64 as i32); unsafe { mem::transmute(t) } } } -impl From for InterpType { - fn from(t: u8) -> InterpType { - assert!(InterpType::NEAREST as u8 <= t && t <= InterpType::CUBIC as u8); +impl From for InterpType { + fn from(t: i32) -> InterpType { + assert!(InterpType::NEAREST as i32 <= t && t <= InterpType::CUBIC as i32); unsafe { mem::transmute(t) } } } -impl From for ConvMode { - fn from(t: u8) -> ConvMode { - assert!(ConvMode::DEFAULT as u8 <= t && t <= ConvMode::EXPAND as u8); +impl From for ConvMode { + fn from(t: i32) -> ConvMode { + assert!(ConvMode::DEFAULT as i32 <= t && t <= ConvMode::EXPAND as i32); unsafe { mem::transmute(t) } } } -impl From for ConvDomain { - fn from(t: u8) -> ConvDomain { - assert!(ConvDomain::AUTO as u8 <= t && t <= ConvDomain::FREQUENCY as u8); +impl From for ConvDomain { + fn from(t: i32) -> ConvDomain { + assert!(ConvDomain::AUTO as i32 <= t && t <= ConvDomain::FREQUENCY as i32); unsafe { mem::transmute(t) } } } -impl From for MatchType { - fn from(t: u8) -> MatchType { - assert!(MatchType::SAD as u8 <= t && t <= MatchType::SHD as u8); +impl From for MatchType { + fn from(t: i32) -> MatchType { + assert!(MatchType::SAD as i32 <= t && t <= MatchType::SHD as i32); unsafe { mem::transmute(t) } } } @@ -72,3 +68,52 @@ impl From for ColorMap { unsafe { mem::transmute(t) } } } + +/// Types of the data that can be generated using ArrayFire data generation functions. +/// +/// The trait HasAfEnum has been defined internally for the following types. We strongly suggest +/// not to implement this trait in your program for user defined types because ArrayFire functions +/// will only work for the following data types currently. Any such trait implementation for types +/// other than the ones listed below will result in undefined behavior. +/// +/// - f32 +/// - f64 +/// - num::Complex\ +/// - num::Complex\ +/// - bool +/// - i32 +/// - u32 +/// - u8 +/// - i64 +/// - u64 +/// - i16 +/// - u16 +/// +pub trait HasAfEnum { + fn get_af_dtype() -> DType; +} + +macro_rules! impl_has_af_enum { + ($rust_t: ty, $af_dtype: expr) => ( + impl HasAfEnum for $rust_t { + fn get_af_dtype() -> DType { + $af_dtype + } + } + ) +} + +impl_has_af_enum!(f32, DType::F32); +impl_has_af_enum!(Complex, DType::C32); +impl_has_af_enum!(f64, DType::F64); +impl_has_af_enum!(Complex, DType::C64); +// FIXME: Rust bool may become incompatible in memory layout with C-ABI +// Currently, it is of size 1-byte +impl_has_af_enum!(bool, DType::B8); +impl_has_af_enum!(i32, DType::S32); +impl_has_af_enum!(u32, DType::U32); +impl_has_af_enum!(u8, DType::U8); +impl_has_af_enum!(i64, DType::S64); +impl_has_af_enum!(u64, DType::U64); +impl_has_af_enum!(i16, DType::S16); +impl_has_af_enum!(u16, DType::U16); diff --git a/src/vision/mod.rs b/src/vision/mod.rs index 23ab89e5b..48791a458 100644 --- a/src/vision/mod.rs +++ b/src/vision/mod.rs @@ -1,7 +1,10 @@ extern crate libc; +use std::mem; use array::Array; -use defines::{AfError, HomographyType, Aftype, MatchType}; +use defines::{AfError, HomographyType, MatchType}; +use error::HANDLE_ERROR; +use util::HasAfEnum; use self::libc::{c_void, uint8_t, c_uint, c_int, c_float, c_double, c_longlong}; type MutAfArray = *mut self::libc::c_longlong; @@ -73,14 +76,17 @@ pub struct Features { macro_rules! feat_func_def { ($fn_name: ident, $ffi_name: ident) => ( - pub fn $fn_name(&self) -> Result { + pub fn $fn_name(&self) -> Array { unsafe { let mut temp: i64 = 0; let err_val = $ffi_name(&mut temp as MutAfArray, self.feat as Feat); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + + let temp_array = Array::from(temp); + let retained = temp_array.clone(); + mem::forget(temp_array); + + HANDLE_ERROR(AfError::from(err_val)); + retained } } ) @@ -88,28 +94,24 @@ macro_rules! feat_func_def { impl Features { #[allow(unused_mut)] - pub fn new(n: u64) -> Result { + pub fn new(n: u64) -> Features { unsafe { let mut temp: i64 = 0; let err_val = af_create_features(&mut temp as *mut c_longlong as MutFeat, n as DimT); - match err_val { - 0 => Ok(Features {feat: temp}), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Features {feat: temp} } } /// Get total number of features found - pub fn num_features(&self) -> Result { + pub fn num_features(&self) -> i64 { unsafe { let mut temp: i64 = 0; let err_val = af_get_features_num(&mut temp as *mut DimT, self.feat as *const c_longlong as Feat); - match err_val { - 0 => Ok(temp), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + temp } } @@ -130,10 +132,8 @@ impl Clone for Features { let mut temp: i64 = 0; let ret_val = af_retain_features(&mut temp as *mut c_longlong as MutFeat, self.feat as *const c_longlong as Feat); - match ret_val { - 0 => Features {feat: temp}, - _ => panic!("Weak copy of Features failed with error code: {}", ret_val), - } + HANDLE_ERROR(AfError::from(ret_val)); + Features {feat: temp} } } } @@ -142,10 +142,7 @@ impl Drop for Features { fn drop(&mut self) { unsafe { let ret_val = af_release_features(self.feat as *mut c_longlong as *mut c_void); - match ret_val { - 0 => (), - _ => panic!("Weak copy of Features failed with error code: {}", ret_val), - } + HANDLE_ERROR(AfError::from(ret_val)); } } } @@ -180,16 +177,14 @@ impl Drop for Features { /// compute orientation. Size is set to 1 as FAST does not compute multiple scales. #[allow(unused_mut)] pub fn fast(input: &Array, thr: f32, arc_len: u32, - non_max: bool, feat_ratio: f32, edge: u32) -> Result { + non_max: bool, feat_ratio: f32, edge: u32) -> Features { unsafe { let mut temp: i64 = 0; let err_val = af_fast(&mut temp as *mut c_longlong as MutFeat, input.get() as AfArray, thr as c_float, arc_len as c_uint, non_max as c_int, feat_ratio as c_float, edge as c_uint); - match err_val { - 0 => Ok(Features {feat: temp}), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Features {feat: temp} } } @@ -215,17 +210,15 @@ pub fn fast(input: &Array, thr: f32, arc_len: u32, /// for x and y coordinates and score, while array oreientation & size are set to 0 & 1, /// respectively, since harris doesn't compute that information #[allow(unused_mut)] -pub fn harris(input: &Array, max_corners: u32, min_response: f32, sigma: f32, block_size: u32, k_thr: f32) -> Result { +pub fn harris(input: &Array, max_corners: u32, min_response: f32, sigma: f32, block_size: u32, k_thr: f32) -> Features { unsafe { let mut temp: i64 = 0; let err_val = af_harris(&mut temp as *mut c_longlong as MutFeat, input.get() as AfArray, max_corners as c_uint, min_response as c_float, sigma as c_float, block_size as c_uint, k_thr as c_float); - match err_val { - 0 => Ok(Features {feat: temp}), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Features {feat: temp} } } @@ -253,17 +246,15 @@ pub fn harris(input: &Array, max_corners: u32, min_response: f32, sigma: f32, bl /// This function returns a tuple of [`Features`](./struct.Features.html) and [`Array`](./struct.Array.html). The features objects composed of Arrays for x and y coordinates, score, orientation and size of selected features. The Array object is a two dimensional Array of size Nx8 where N is number of selected features. #[allow(unused_mut)] pub fn orb(input: &Array, fast_thr: f32, max_feat: u32, - scl_fctr: f32, levels: u32, blur_img: bool) -> Result<(Features, Array), AfError> { + scl_fctr: f32, levels: u32, blur_img: bool) -> (Features, Array) { unsafe { let mut f: i64 = 0; let mut d: i64 = 0; let err_val = af_orb(&mut f as *mut c_longlong as MutFeat, &mut d as MutAfArray, input.get() as AfArray, fast_thr as c_float, max_feat as c_uint, scl_fctr as c_float, levels as c_uint, blur_img as c_int); - match err_val { - 0 => Ok((Features {feat: f}, Array::from(d))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Features {feat: f}, Array::from(d)) } } @@ -301,17 +292,15 @@ pub fn orb(input: &Array, fast_thr: f32, max_feat: u32, /// distance to the Ith query value in the train data array. #[allow(unused_mut)] pub fn hamming_matcher(query: &Array, train: &Array, - dist_dims: i64, n_dist: u32) -> Result<(Array, Array), AfError> { + dist_dims: i64, n_dist: u32) -> (Array, Array) { unsafe { let mut idx: i64 = 0; let mut dist:i64 = 0; let err_val = af_hamming_matcher(&mut idx as MutAfArray, &mut dist as MutAfArray, query.get() as AfArray, train.get() as AfArray, dist_dims as DimT, n_dist as c_uint); - match err_val { - 0 => Ok((Array::from(idx), Array::from(dist))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(idx), Array::from(dist)) } } @@ -348,17 +337,15 @@ pub fn hamming_matcher(query: &Array, train: &Array, /// and N is equal to `n_dist`. The value at position IxJ indicates the distance of the Jth smallest /// distance to the Ith query value in the train data array based on the `dist_type` chosen. #[allow(unused_mut)] -pub fn nearest_neighbour(query: &Array, train: &Array, dist_dim: i64, n_dist: u32, dist_type: MatchType) -> Result<(Array, Array), AfError> { +pub fn nearest_neighbour(query: &Array, train: &Array, dist_dim: i64, n_dist: u32, dist_type: MatchType) -> (Array, Array) { unsafe { let mut idx: i64 = 0; let mut dist: i64 = 0; let err_val = af_nearest_neighbour(&mut idx as MutAfArray, &mut dist as MutAfArray, query.get() as AfArray, train.get() as AfArray, dist_dim as DimT, n_dist as c_uint, dist_type as c_int); - match err_val { - 0 => Ok((Array::from(idx), Array::from(dist))), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(idx), Array::from(dist)) } } @@ -378,16 +365,14 @@ pub fn nearest_neighbour(query: &Array, train: &Array, dist_dim: i64, n_dist: u3 /// This function returns an Array with disparity values for the window starting at corresponding pixel position. #[allow(unused_mut)] pub fn match_template(search_img: &Array, template_img: &Array, - mtype: MatchType) -> Result { + mtype: MatchType) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_match_template(&mut temp as MutAfArray, search_img.get() as AfArray, template_img.get() as AfArray, mtype as uint8_t); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -431,17 +416,15 @@ pub fn match_template(search_img: &Array, template_img: &Array, /// # Return Values /// An object of type [Features](./struct.Features.html) composed of arrays for x and y coordinates, score, orientation and size of selected features. #[allow(unused_mut)] -pub fn susan(input: &Array, radius: u32, diff_thr: f32, geom_thr: f32, feature_ratio: f32, edge: u32) -> Result { +pub fn susan(input: &Array, radius: u32, diff_thr: f32, geom_thr: f32, feature_ratio: f32, edge: u32) -> Features { unsafe { let mut temp: i64 = 0; let err_val = af_susan(&mut temp as *mut c_longlong as MutFeat, input.get() as AfArray, radius as c_uint, diff_thr as c_float, geom_thr as c_float, feature_ratio as c_float, edge as c_uint); - match err_val { - 0 => Ok(Features {feat: temp}), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Features {feat: temp} } } @@ -460,15 +443,13 @@ pub fn susan(input: &Array, radius: u32, diff_thr: f32, geom_thr: f32, feature_r /// /// Difference of smoothed inputs - An Array. #[allow(unused_mut)] -pub fn dog(input: &Array, radius1: i32, radius2: i32) -> Result { +pub fn dog(input: &Array, radius1: i32, radius2: i32) -> Array { unsafe { let mut temp: i64 = 0; let err_val = af_dog(&mut temp as MutAfArray, input.get() as AfArray, radius1 as c_int, radius2 as c_int); - match err_val { - 0 => Ok(Array::from(temp)), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + Array::from(temp) } } @@ -503,11 +484,12 @@ pub fn dog(input: &Array, radius1: i32, radius2: i32) -> Result /// /// - `H` is a 3x3 array containing the estimated homography. /// - `inliers` is the number of inliers that the homography was estimated to comprise, in the case that htype is AF_HOMOGRAPHY_RANSAC, a higher inlier_thr value will increase the estimated inliers. Note that if the number of inliers is too low, it is likely that a bad homography will be returned. -pub fn homography(x_src: &Array, y_src: &Array, - x_dst: &Array, y_dst: &Array, - htype: HomographyType, inlier_thr: f32, - iterations: u32, otype: Aftype) -> Result<(Array, i32), AfError> { +pub fn homography(x_src: &Array, y_src: &Array, + x_dst: &Array, y_dst: &Array, + htype: HomographyType, inlier_thr: f32, + iterations: u32) -> (Array, i32) { unsafe { + let otype = OutType::get_af_dtype(); let mut inliers: i32 = 0; let mut temp: i64 = 0; let err_val = af_homography(&mut temp as MutAfArray, &mut inliers as *mut c_int, @@ -515,9 +497,7 @@ pub fn homography(x_src: &Array, y_src: &Array, x_dst.get() as AfArray, y_dst.get() as AfArray, htype as c_int, inlier_thr as c_float, iterations as c_uint, otype as c_int); - match err_val { - 0 => Ok( (Array::from(temp), inliers) ), - _ => Err(AfError::from(err_val)), - } + HANDLE_ERROR(AfError::from(err_val)); + (Array::from(temp), inliers) } -} +} \ No newline at end of file diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 000000000..fa0ce65f2 --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,53 @@ +#[macro_use] +extern crate arrayfire as af; + +use std::error::Error; +use std::thread; +use std::time::Duration; +use af::*; + +macro_rules! implement_handler { + ($fn_name:ident, $msg: expr) => ( + + pub fn $fn_name(error_code: AfError) { + println!("{:?}", $msg); + match error_code { + AfError::SUCCESS => {}, /* No-op */ + _ => panic!("Error message: {}", error_code.description()), + } + } + + ) +} + +implement_handler!(handler_sample1, "Error Handler Sample1"); +implement_handler!(handler_sample2, "Error Handler Sample2"); +implement_handler!(handler_sample3, "Error Handler Sample3"); +implement_handler!(handler_sample4, "Error Handler Sample4"); + +pub const HANDLE1: Callback<'static> = Callback{ cb: &handler_sample1}; +pub const HANDLE2: Callback<'static> = Callback{ cb: &handler_sample2}; +pub const HANDLE3: Callback<'static> = Callback{ cb: &handler_sample3}; +pub const HANDLE4: Callback<'static> = Callback{ cb: &handler_sample4}; + +#[allow(unused_must_use)] +#[test] +fn check_error_handler_mutation() { + + for i in 0..4 { + thread::Builder::new().name(format!("child {}",i+1).to_string()).spawn(move || { + println!("{:?}", thread::current()); + match i { + 0 => register_error_handler(HANDLE1), + 1 => register_error_handler(HANDLE2), + 2 => register_error_handler(HANDLE3), + 3 => register_error_handler(HANDLE4), + _ => panic!("Impossible scenario"), + } + }); + } + + af::info(); + thread::sleep(Duration::from_millis(50)); + +}