Skip to content

Commit 1c19542

Browse files
committed
Enforce Indexable objects to use lifetime of Indexer object
Currently, only Seq and Array implement the Indexable trait. Earlier to this change, there was no proper lifetime specification for Indexer struct and Indexer::set_index method to enfore borrow checking. This should be fixed now.
1 parent dbac16c commit 1c19542

File tree

2 files changed

+83
-17
lines changed

2 files changed

+83
-17
lines changed

src/arith/mod.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,15 @@ macro_rules! arith_assign_func {
460460

461461
#[allow(unused_variables)]
462462
fn $fn_name(&mut self, rhs: Array) {
463+
let tmp_seq = Seq::<f32>::default();
463464
let mut idxrs = Indexer::new();
464-
for n in 0..self.numdims() {
465-
idxrs.set_index(&Seq::<f32>::default(), n, Some(false));
466-
}
465+
idxrs.set_index(&tmp_seq, 0, Some(false));
466+
idxrs.set_index(&tmp_seq, 1, Some(false));
467+
idxrs.set_index(&tmp_seq, 2, Some(false));
468+
idxrs.set_index(&tmp_seq, 3, Some(false));
467469
let tmp = assign_gen(self as &Array, &idxrs,
468470
& $func(self as &Array, &rhs, false));
469-
mem::replace(self, tmp);
471+
let old = mem::replace(self, tmp);
470472
}
471473
}
472474
)
@@ -486,11 +488,14 @@ macro_rules! bit_assign_func {
486488

487489
#[allow(unused_variables)]
488490
fn $fn_name(&mut self, rhs: Array) {
491+
let tmp_seq = Seq::<f32>::default();
489492
let mut idxrs = Indexer::new();
490-
idxrs.set_index(&Seq::<f32>::default(), 0, Some(false));
491-
idxrs.set_index(&Seq::<f32>::default(), 1, Some(false));
493+
idxrs.set_index(&tmp_seq, 0, Some(false));
494+
idxrs.set_index(&tmp_seq, 1, Some(false));
495+
idxrs.set_index(&tmp_seq, 2, Some(false));
496+
idxrs.set_index(&tmp_seq, 3, Some(false));
492497
let tmp = assign_gen(self as &Array, &idxrs, & $func(self as &Array, &rhs, false));
493-
mem::replace(self, tmp);
498+
let old = mem::replace(self, tmp);
494499
}
495500
}
496501
)

src/index.rs

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use seq::Seq;
77
use self::libc::{c_double, c_int, c_uint};
88
use util::{AfArray, AfIndex, DimT, MutAfArray, MutAfIndex};
99

10+
use std::marker::PhantomData;
11+
1012
#[allow(dead_code)]
1113
extern {
1214
fn af_create_indexers(indexers: MutAfIndex) -> c_int;
@@ -22,8 +24,60 @@ extern {
2224
}
2325

2426
/// Struct to manage an array of resources of type `af_indexer_t`(ArrayFire C struct)
25-
pub struct Indexer {
27+
///
28+
/// # Examples
29+
///
30+
/// Given below are examples illustrating correct and incorrect usage of Indexer struct.
31+
///
32+
/// <h3> Correct Usage </h3>
33+
///
34+
/// ```rust
35+
/// use arrayfire::{Array, Dim4, randu, index_gen, Indexer};
36+
///
37+
/// // Always be aware of the fact that, the `Seq` or `Array` objects
38+
/// // that we intend to use for indexing via `Indexer` have to outlive
39+
/// // the `Indexer` object created in this context.
40+
///
41+
/// let dims = Dim4::new(&[1, 3, 1, 1]);
42+
/// let bools = Array::new(&[1, 0, 1], dims);
43+
/// let values = Array::new(&[2, 5, 6], dims);
44+
///
45+
/// let mut idxr = Indexer::new();
46+
///
47+
/// // `bools` is created much before idxr, thus will
48+
/// // stay in scope at least as long as idxr
49+
/// idxr.set_index(&bools, 0, None);
50+
///
51+
/// index_gen(&values, idxr);
52+
/// ```
53+
///
54+
/// <h3> Incorrect Usage </h3>
55+
///
56+
/// ```rust,ignore
57+
/// // Say, you create an Array on the fly and try
58+
/// // to call set_index, it will throw the given below
59+
/// // error or something similar to that
60+
/// idxr.set_index(&Array::new(&[1, 0, 1], dims), 0, None);
61+
/// ```
62+
///
63+
/// ```text
64+
/// error: borrowed value does not live long enough
65+
/// --> <anon>:16:55
66+
/// |
67+
///16 | idxr.set_index(&Array::new(&[1, 0, 1], dims), 0, None);
68+
/// | ---------------------------- ^ temporary value dropped here while still borrowed
69+
/// | |
70+
/// | temporary value created here
71+
///...
72+
///19 | }
73+
/// | - temporary value needs to live until here
74+
/// |
75+
/// = note: consider using a `let` binding to increase its lifetime
76+
/// ```
77+
pub struct Indexer<'object> {
2678
handle: i64,
79+
count: usize,
80+
marker: PhantomData<&'object ()>,
2781
}
2882

2983
// Trait that indicates that object can be used for indexing
@@ -42,7 +96,7 @@ impl Indexable for Array {
4296
#[allow(unused_variables)]
4397
fn set(&self, idxr: &mut Indexer, dim: u32, is_batch: Option<bool>) {
4498
unsafe {
45-
let err_val = af_set_array_indexer(idxr.get() as AfIndex, self.clone().get() as AfArray,
99+
let err_val = af_set_array_indexer(idxr.get() as AfIndex, self.get() as AfArray,
46100
dim as DimT);
47101
HANDLE_ERROR(AfError::from(err_val));
48102
}
@@ -64,21 +118,28 @@ impl<T: Copy> Indexable for Seq<T> where c_double: From<T> {
64118
}
65119
}
66120

67-
impl Indexer {
121+
impl<'object> Indexer<'object> {
68122
#[allow(unused_mut)]
69123
/// Create a new Indexer object and set the dimension specific index objects later
70-
pub fn new() -> Indexer {
124+
pub fn new() -> Indexer<'object> {
71125
unsafe {
72126
let mut temp: i64 = 0;
73127
let err_val = af_create_indexers(&mut temp as MutAfIndex);
74128
HANDLE_ERROR(AfError::from(err_val));
75-
Indexer{handle: temp}
129+
Indexer{handle: temp, count: 0, marker: PhantomData}
76130
}
77131
}
78132

79133
/// Set either [Array](./struct.Array.html) or [Seq](./struct.Seq.html) to index an Array along `idx` dimension
80-
pub fn set_index<T: Indexable>(&mut self, idx: &T, dim: u32, is_batch: Option<bool>) {
81-
idx.set(self, dim, is_batch)
134+
pub fn set_index<'s, T>(&'s mut self, idx: &'object T, dim: u32, is_batch: Option<bool>)
135+
where T : Indexable + 'object {
136+
idx.set(self, dim, is_batch);
137+
self.count = self.count+1;
138+
}
139+
140+
/// Get number of indexing objects set
141+
pub fn len(&self) -> usize {
142+
self.count
82143
}
83144

84145
/// Get native(ArrayFire) resource handle
@@ -87,7 +148,7 @@ impl Indexer {
87148
}
88149
}
89150

90-
impl Drop for Indexer {
151+
impl<'object> Drop for Indexer<'object> {
91152
fn drop(&mut self) {
92153
unsafe {
93154
let ret_val = af_release_indexers(self.handle as AfIndex);
@@ -328,7 +389,7 @@ pub fn index_gen(input: &Array, indices: Indexer) -> Array {
328389
unsafe{
329390
let mut temp: i64 = 0;
330391
let err_val = af_index_gen(&mut temp as MutAfArray, input.get() as AfArray,
331-
4, indices.get() as AfIndex);
392+
indices.len() as DimT, indices.get() as AfIndex);
332393
HANDLE_ERROR(AfError::from(err_val));
333394
Array::from(temp)
334395
}
@@ -370,7 +431,7 @@ pub fn assign_gen(lhs: &Array, indices: &Indexer, rhs: &Array) -> Array {
370431
unsafe{
371432
let mut temp: i64 = 0;
372433
let err_val = af_assign_gen(&mut temp as MutAfArray, lhs.get() as AfArray,
373-
4, indices.get() as AfIndex,
434+
indices.len() as DimT, indices.get() as AfIndex,
374435
rhs.get() as AfArray);
375436
HANDLE_ERROR(AfError::from(err_val));
376437
Array::from(temp)

0 commit comments

Comments
 (0)