dynamic_grid/
lib.rs

1#[cfg(test)]
2#[macro_use] extern crate assert_matches;
3
4use std::fmt;
5use std::fmt::Formatter;
6use std::string::ToString;
7use std::slice::{Iter, IterMut};
8
9#[derive(Default, Debug, Clone)]
10/// Dynamic Grid
11pub struct DynamicGrid <T>{
12    data: Vec<T>,
13    line_start_index: Vec<usize>
14}
15
16impl <T> DynamicGrid<T> where T: Clone{
17
18    /// Constructor, Returns a dynamic grid
19    pub fn new () -> Self{
20        DynamicGrid{ data: vec![], line_start_index: vec![] }
21    }
22
23    /// Init a grid of size rows x columns with the given data element
24    ///
25    /// # Arguments
26    /// * `row` - number of rows
27    /// * `col` - number columns
28    /// * `value` - default value
29    pub fn init (row: usize, col: usize, value: T) -> Self{
30        let mut v = vec![0, row];
31        let mut index_row = 0;
32        v.iter_mut().for_each(| value| {
33            *value = index_row;
34            index_row += col;
35        });
36
37        DynamicGrid{
38            data: vec![value; row * col],
39            line_start_index: v
40        }
41    }
42
43    ///Returns a grid from a vector of vector
44    /// # Arguments
45    /// * vec - Vector which represent a grid
46    pub fn from_vec(vec: Vec<Vec<T>>) -> Self{
47        let mut g = DynamicGrid::new();
48        let mut start_index = 0;
49        for row  in vec.iter() {
50            g.line_start_index.push(start_index);
51            for item in row.iter(){
52                g.data.push(item.clone());
53                start_index+=1;
54            }
55        }
56        g
57    }
58
59    /// Returns number of rows of the grid
60    pub fn rows(&self) -> usize {
61        self.line_start_index.len()
62    }
63
64    /// Returns the size of the row indicate by the index
65    /// # Arguments
66    /// * `index` - rows index
67    pub fn row_size(&self, index_row: usize) -> Option<usize> {
68        if index_row < self.rows() {
69            Some(self.row_size_unchecked(index_row))
70        } else {
71            None
72        }
73    }
74
75    /// Returns the size of the row indicate by the index, without bound checking
76    /// # Arguments
77    /// * `index` - rows index
78    pub fn row_size_unchecked(&self, index_row: usize) -> usize{
79        let end = if index_row < self.rows() - 1 {self.line_start_index[index_row + 1]}
80        else {self.data.len()};
81        end - self.line_start_index[index_row]
82    }
83
84    /// push value in the last position of last row
85    /// * `value` - value to push
86    pub fn push(&mut self, value: T) -> (usize, usize){
87        self.data.push(value);
88        (self.rows() - 1, self.row_size_unchecked(self.rows() - 1) - 1 )
89
90    }
91
92    /// push value in the last position at row mentioned
93    /// # Argument
94    /// * index_row - index of row
95    /// * value - value to push
96    pub fn push_at_row(&mut self, index_row: usize, value: T) -> Option<(usize, usize)> {
97        if index_row < self.rows() {
98            let position = (index_row, self.row_size_unchecked(index_row));
99            self.insert(position.0, position.1, value);
100            return Some(position)
101        }
102        return None
103    }
104
105    /// insert value at position
106    /// # Argument
107    /// * index_row - index of row
108    /// * index_col - index of col
109    /// * value - value to insert
110    ///
111    /// # Panics
112    /// Panics if the row and the col index are out of bounds.
113    pub fn insert(&mut self, index_row: usize, index_col:usize, value: T){
114        if index_row < self.rows(){
115            if index_col <= self.row_size_unchecked(index_row){
116                self.data.insert(self.line_start_index[index_row] + index_col, value);
117                if index_row < self.rows() - 1 {self.line_start_index[index_row + 1] += 1}
118            }else {
119                panic!("Out of bounds. Col index must be less than {:?}, your index is {:?}", self.row_size_unchecked(index_row) - 1, index_col)
120
121            }
122        } else {
123            panic!("Out of bounds. Row index must be less than {:?}, your index is {:?}", self.rows() - 1, index_row)
124        }
125    }
126
127    /// swap two element in the grid
128    /// # Argument
129    /// * first_position - position of the first element
130    /// * second_position - position of the second element
131    /// # Panics
132    /// Panics if the row and the col index are out of bounds.
133    pub fn swap(&mut self, first_position: (usize, usize), second_position: (usize, usize)) {
134        if first_position.0 < self.rows() && second_position.0 < self.rows() {
135            if first_position.1 < self.row_size_unchecked(first_position.0)
136                && second_position.1 < self.row_size_unchecked(second_position.0){
137                let first_index = self.line_start_index[first_position.0] + first_position.1;
138                let second_index = self.line_start_index[second_position.0] + second_position.1;
139
140                self.data.swap(first_index, second_index);
141            } else {
142                panic!("Out of bounds");
143            }
144        } else {
145            panic!("Out of bounds");
146        }
147    }
148
149
150    /// push a new empty row
151    pub fn push_new_row(&mut self, value: T) -> (usize, usize){
152        self.line_start_index.push(self.data.len());
153        self.push(value);
154        (self.rows() - 1, self.row_size_unchecked(self.rows() - 1) - 1 )
155    }
156
157    /// remove the last value of the last row
158    pub fn remove(&mut self){
159        if self.data.len() > 0 {
160            self.data.remove(self.data.len() -1 );
161            if *self.line_start_index.last().unwrap() >= self.data.len(){
162                self.remove_row(self.rows() - 1 )
163            }
164        }
165    }
166
167    /// remove the last row
168    pub fn remove_row(&mut self, index_row: usize) {
169        if !self.data.is_empty() && index_row < self.rows(){
170            let start = self.line_start_index[index_row];
171            let end = start + self.row_size_unchecked(index_row);
172
173            self.data = self.data.iter()
174                .enumerate()
175                .filter(|(i, _)| !(start..end).contains(i))
176                .map(|(_, v)| v.clone())
177                .collect();
178
179            self.line_start_index.remove(index_row);
180        }
181    }
182
183    /// Returns a reference to an element, without doing bound checking.
184    /// # Arguments
185    /// `index_row` - index of row
186    /// `index_col` - index of column
187    /// # Example
188    pub unsafe fn get_unchecked(&self, index_row: usize, index_col: usize) -> &T{
189        self.data.get_unchecked(self.line_start_index[index_row] + index_col)
190    }
191
192    /// Return a mutable reference to an element, without doing bound checking.
193    /// # Arguments
194    /// `index_row` - index of row
195    /// `index_col` - index of column
196    /// # Example
197    pub unsafe fn get_unchecked_mut(&mut self, index_row: usize, index_col: usize) -> &mut T{
198        self.data.get_unchecked_mut(self.line_start_index[index_row] + index_col)
199    }
200
201    ///Returns a reference to an element.
202    ///
203    /// # Arguments
204    /// `index_row` - index of row
205    /// `index_col` - index of column
206    /// # Example
207    ///
208    pub fn get (&self, index_row: usize, index_col: usize) -> Option<&T>{
209        if index_row < self.rows() {
210            if index_col < self.row_size_unchecked(index_row) {
211                unsafe{ Some(self.get_unchecked(index_row, index_col))}
212            } else {
213                None
214            }
215        }else {
216            None
217        }
218    }
219
220    ///Returns a reference to an element.
221    ///
222    /// # Arguments
223    /// `index_row` - index of row
224    /// `index_col` - index of column
225    /// # Example
226    ///
227    pub fn get_mut (&mut self, index_row: usize, index_col: usize) -> Option<&mut T>{
228        if index_row < self.rows() {
229            if index_col < self.row_size_unchecked(index_row) {
230                unsafe{ Some(self.get_unchecked_mut(index_row, index_col))}
231            } else {
232                None
233            }
234        }else {
235            None
236        }
237    }
238
239    /// Returns an iterator over the whole grid, starting from the first row and column.
240    pub fn iter(&self) -> Iter<T> {
241        self.data.iter()
242    }
243
244    /// Returns an mutable iterator over the whole grid that allows modifying each value.
245    pub fn iter_mut(&mut self) -> IterMut<T> {
246        self.data.iter_mut()
247    }
248
249    /// Returns a row Iterator
250    ///
251    /// # Panics
252    /// Panics if the row index is out of bounds.
253    pub fn iter_row(&self, index_row: usize) -> Iter<T> {
254        if index_row < self.rows() {
255            let cols = self.row_size_unchecked(index_row);
256            let start = self.line_start_index[index_row];
257            return self.data[start..(start + cols)].iter()
258        } else {
259            panic!("Out of bounds. Row index must be less than {:?}, your index is {:?}", self.rows() - 1, index_row)
260        }
261    }
262
263    /// Returns a mutable row Iterator
264    ///
265    /// # Panics
266    /// Panics if the row index is out of bounds.
267    pub fn iter_row_mut(&mut self, index_row: usize) -> IterMut<T> {
268        if index_row < self.rows() {
269            let cols = self.row_size_unchecked(index_row);
270            let start = self.line_start_index[index_row];
271            return self.data[start..(start + cols)].iter_mut()
272        } else {
273            panic!("Out of bounds. Row index must be less than {:?}, your index is {:?}", self.rows() - 1, index_row)
274        }
275    }
276
277
278}
279
280impl <T> fmt::Display for DynamicGrid<T> where T: Clone + ToString{
281    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
282        let mut s = String::new();
283
284        for row in 0..self.rows(){
285            for data in self.iter_row(row) {
286                s.push_str(data.to_string().as_str());
287                s.push_str(",")
288            }
289            s.push_str("\n");
290        }
291
292        write!(f, "{}", s)
293    }
294}
295
296#[cfg(test)]
297mod tests {
298
299    use crate::DynamicGrid;
300
301    // 10, 5, 4
302    // 3, 9
303    // 1
304    // 7, 6, 2, 8
305    fn init() -> DynamicGrid<usize>{
306        /*let mut g = DynamicGrid::new();
307        g.push_new_row(10);
308        g.push(5);
309        g.push(4);
310
311        g.push_new_row(3);
312        g.push(9);
313
314        g.push_new_row(1);
315
316        g.push_new_row(7);
317        g.push(6);
318        g.push(2);
319        g.push(8);*/
320
321        let g =
322            DynamicGrid::from_vec(
323                vec![
324                        vec![10, 5, 4],
325                        vec![3, 9],
326                        vec![1],
327                        vec![7, 6, 2, 8]
328    ]);
329
330        g
331    }
332
333    #[test]
334    fn test_new() {
335        let g: DynamicGrid<i32> = DynamicGrid::new();
336
337        assert_matches!(g.rows(), 0);
338        assert_matches!(g.row_size(0), None);
339        assert_matches!(g.row_size(10), None);
340    }
341
342    #[test]
343    fn test_init() {
344        let g = init();
345        assert_matches!(g.rows(), 4);
346        assert_matches!(g.row_size(0), Some(3));
347        assert_matches!(g.row_size(1), Some(2));
348        assert_matches!(g.row_size(2), Some(1));
349        assert_matches!(g.row_size(3), Some(4));
350        assert_matches!(g.row_size(10), None);
351    }
352
353    #[test]
354    fn test_push() {
355        let mut g = init();
356
357        let position = g.push(4);
358        assert_matches!(position, (3, 4));
359        assert_matches!(g.row_size(0), Some(3));
360        assert_matches!(g.row_size(3), Some(5));
361    }
362
363    #[test]
364    fn test_push_new_row(){
365        let mut g = init();
366        let position = g.push_new_row(4);
367        assert_matches!(position, (4, 0));
368        assert_matches!(g.row_size(0), Some(3));
369        assert_matches!(g.row_size(4), Some(1));
370    }
371
372    #[test]
373    fn test_push_at_row() {
374        let mut g = init();
375
376        let position = g.push_at_row(2, 4);
377        println!("{}", g);
378        assert_matches!(position, Some((2, 1)));
379        assert_matches!(g.get(2, 1), Some(4));
380        assert_matches!(g.row_size(0), Some(3));
381        assert_matches!(g.row_size(2), Some(2));
382
383    }
384
385    #[test]
386    fn test_swap() {
387        let mut g = init();
388
389        g.swap((0, 1), (3, 2));
390
391        assert_matches!(g.get(0, 1), Some(2));
392        assert_matches!(g.get(3, 2), Some(5));
393
394    }
395
396    #[test]
397    fn test_remove() {
398        let mut g = init();
399        g.remove();
400        assert_matches!(g.row_size(3), Some(3))
401    }
402
403    #[test]
404    fn test_remove_row() {
405        let mut g = init();
406        g.remove_row(0);
407        assert_matches!(g.rows(), 3);
408    }
409
410    #[test]
411    fn test_get() {
412        let mut g = init();
413        assert_matches!(g.get(0,0), Some(10));
414        assert_matches!(g.get(10,0), None);
415        assert_matches!(g.get(1, 1), Some(9));
416        assert_matches!(g.get(3, 3), Some(8));
417        assert_matches!(g.get(3, 4), None);
418
419
420        g.push(11);
421        assert_matches!(g.get(3, 4), Some(11));
422    }
423
424    #[test]
425    fn test_get_mut() {
426        let mut g = init();
427        assert_matches!(g.get_mut(0,0), Some(10));
428        assert_matches!(g.get_mut(10,0), None);
429        assert_matches!(g.get_mut(1, 1), Some(9));
430
431        g.push(3);
432        assert_matches!(g.get_mut(3, 4), Some(3));
433
434        *g.get_mut(3, 4).unwrap() = 5;
435        assert_matches!(g.get(3, 4), Some(5));
436    }
437
438    #[test]
439    fn test_iterator() {
440        let g = init();
441        let mut iter = g.iter();
442        assert_matches!(iter.next(), Some(10));
443        assert_matches!(iter.next(), Some(5));
444        assert_matches!(iter.next(), Some(4));
445        assert_matches!(iter.next(), Some(3));
446        assert_matches!(iter.next(), Some(9));
447        assert_matches!(iter.next(), Some(1));
448        assert_matches!(iter.next(), Some(7));
449        assert_matches!(iter.next(), Some(6));
450        assert_matches!(iter.next(), Some(2));
451        assert_matches!(iter.next(), Some(8));
452        assert_matches!(iter.next(), None);
453    }
454
455    #[test]
456    fn test_row_iterator() {
457        let g = init();
458        let mut iter = g.iter_row(1);
459        assert_matches!(iter.next(), Some(3));
460        assert_matches!(iter.next(), Some(9));
461        assert_matches!(iter.next(), None);
462
463        let mut iter = g.iter_row(2);
464        assert_matches!(iter.next(), Some(1));
465        assert_matches!(iter.next(), None);
466
467        let mut iter = g.iter_row(3);
468        assert_matches!(iter.next(), Some(7));
469        assert_matches!(iter.next(), Some(6));
470        assert_matches!(iter.next(), Some(2));
471        assert_matches!(iter.next(), Some(8));
472        assert_matches!(iter.next(), None);
473
474    }
475
476    #[test]
477    #[should_panic]
478    fn test_row_iterator_should_panic() {
479        let g = init();
480        let mut _iter = g.iter_row(10);
481
482        // Seconde way to assert panic
483        // let should_panic = std::panic::catch_unwind(||{let mut _iter = g.iter_row(10);});
484        // assert!(should_panic.is_err());
485
486    }
487}