tabled/settings/reverse/
mod.rs

1use crate::{
2    grid::config::Offset,
3    grid::records::{ExactRecords, Records, Resizable},
4    settings::TableOption,
5};
6
7// TOOD: simplify
8
9/// Reverse data on the table.
10#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
11pub struct Reverse {
12    columns: bool,
13    start: usize,
14    limit: Offset,
15}
16
17impl Reverse {
18    /// Reverse columns starting from given index.
19    pub const fn columns(start: usize) -> Self {
20        Self::new(true, start, Offset::End(0))
21    }
22
23    /// Reverse rows starting from given index.
24    pub const fn rows(start: usize) -> Self {
25        Self::new(false, start, Offset::End(0))
26    }
27
28    /// Reverse rows starting from given index.
29    pub const fn limit(self, limit: Offset) -> Self {
30        Self::new(self.columns, self.start, limit)
31    }
32
33    const fn new(columns: bool, start: usize, limit: Offset) -> Self {
34        Self {
35            columns,
36            start,
37            limit,
38        }
39    }
40}
41
42impl<R, D, C> TableOption<R, C, D> for Reverse
43where
44    R: Resizable + Records + ExactRecords,
45{
46    fn change(self, records: &mut R, _: &mut C, _: &mut D) {
47        let count_rows = records.count_rows();
48        let count_columns = records.count_columns();
49
50        let start = self.start;
51
52        if self.columns {
53            let end = match self.limit {
54                Offset::Start(limit) => start + limit,
55                Offset::End(limit) => count_columns - limit,
56            };
57
58            if start >= end || end > count_columns {
59                return;
60            }
61
62            reverse_columns(records, start, end);
63        } else {
64            let end = match self.limit {
65                Offset::Start(limit) => start + limit,
66                Offset::End(limit) => count_rows - limit,
67            };
68
69            if start >= end || end > count_rows {
70                return;
71            }
72
73            reverse_rows(records, start, end);
74        }
75    }
76}
77
78fn reverse_rows<R>(data: &mut R, start: usize, end: usize)
79where
80    R: Resizable + ExactRecords,
81{
82    let count_rows = end - start;
83    if count_rows < 2 {
84        return;
85    }
86
87    let mut i = start;
88    let mut j = end - 1;
89
90    while i < j {
91        data.swap_row(i, j);
92        i += 1;
93        j -= 1;
94    }
95}
96
97fn reverse_columns<R>(data: &mut R, start: usize, end: usize)
98where
99    R: Resizable + Records,
100{
101    let count_columns = end - start;
102    if count_columns < 2 {
103        return;
104    }
105
106    let mut i = start;
107    let mut j = end - 1;
108
109    while i < j {
110        data.swap_column(i, j);
111        i += 1;
112        j -= 1;
113    }
114}
115
116#[cfg(test)]
117#[cfg(feature = "std")]
118mod tests {
119    use crate::grid::records::{vec_records::VecRecords, Records};
120
121    use super::{reverse_columns, reverse_rows};
122
123    #[test]
124    fn test_reverse_rows() {
125        assert_eq!(
126            rev_rows(vec![vec![0, 1, 2], vec![3, 4, 5], vec![6, 7, 8]]),
127            vec![vec![6, 7, 8], vec![3, 4, 5], vec![0, 1, 2]]
128        )
129    }
130
131    #[test]
132    fn test_reverse_columns() {
133        assert_eq!(
134            rev_cols(vec![vec![0, 1, 2], vec![3, 4, 5], vec![6, 7, 8]]),
135            vec![vec![2, 1, 0], vec![5, 4, 3], vec![8, 7, 6]]
136        )
137    }
138
139    fn rev_rows(mut data: Vec<Vec<usize>>) -> Vec<Vec<usize>> {
140        let end = data.len();
141        reverse_rows(&mut data, 0, end);
142        data
143    }
144
145    fn rev_cols(data: Vec<Vec<usize>>) -> Vec<Vec<usize>> {
146        let mut records = VecRecords::new(data);
147        let end = records.count_columns();
148        reverse_columns(&mut records, 0, end);
149
150        records.into()
151    }
152}