tabled/features/
rotate.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! This module contains a [`Rotate`] primitive which can be used in order to rotate [`Table`].
//!
//! It's also possible to transpose the table at the point of construction.
//! See [`Builder::index`].
//!
//! # Example
//!
//! ```
//! use tabled::{Rotate, TableIteratorExt};
//!
//! let data = [[1, 2, 3], [4, 5, 6]];
//!
//! let table = data.table().with(Rotate::Left).to_string();
//!
//! assert_eq!(
//!     table,
//!     concat!(
//!         "+---+---+---+\n",
//!         "| 2 | 3 | 6 |\n",
//!         "+---+---+---+\n",
//!         "| 1 | 2 | 5 |\n",
//!         "+---+---+---+\n",
//!         "| 0 | 1 | 4 |\n",
//!         "+---+---+---+",
//!     )
//! );
//! ```
//!
//! [`Table`]: crate::Table
//! [`Builder::index`]: crate::builder::Builder::index

use papergrid::records::{Records, Resizable};

use crate::{Table, TableOption};

/// Rotate can be used to rotate a table by 90 degrees.
#[derive(Debug)]
pub enum Rotate {
    /// Rotate [`Table`] to the left.
    ///
    /// [`Table`]: crate::Table
    Left,
    /// Rotate [`Table`] to the right.
    ///
    /// [`Table`]: crate::Table
    Right,
    /// Rotate [`Table`] to the top.
    ///
    /// So the top becames the bottom.
    ///
    /// [`Table`]: crate::Table
    Top,
    /// Rotate [`Table`] to the bottom.
    ///
    /// So the top becames the bottom.
    ///
    /// [`Table`]: crate::Table
    Bottom,
}

impl<R> TableOption<R> for Rotate
where
    R: Records + Resizable,
{
    fn change(&mut self, table: &mut Table<R>) {
        let (count_rows, count_cols) = table.shape();
        let records = table.get_records_mut();
        match self {
            Self::Left => {
                {
                    let n = std::cmp::max(count_rows, count_cols);
                    for _ in count_rows..n {
                        records.push_row();
                    }

                    for _ in count_cols..n {
                        records.push_column();
                    }
                }

                for col in 0..count_cols {
                    for row in col..count_rows {
                        records.swap((col, row), (row, col));
                    }
                }

                for row in 0..count_cols / 2 {
                    records.swap_row(row, count_cols - row - 1);
                }

                {
                    let n = std::cmp::max(count_rows, count_cols);
                    for (shift, row) in (count_rows..n).enumerate() {
                        let row = row - shift;
                        records.remove_column(row);
                    }

                    for (shift, col) in (count_cols..n).enumerate() {
                        let col = col - shift;
                        records.remove_row(col);
                    }
                }
            }
            Self::Right => {
                {
                    let n = std::cmp::max(count_rows, count_cols);
                    for _ in count_rows..n {
                        records.push_row();
                    }

                    for _ in count_cols..n {
                        records.push_column();
                    }
                }

                for col in 0..count_cols {
                    for row in col..count_rows {
                        records.swap((col, row), (row, col));
                    }
                }

                for col in 0..count_rows / 2 {
                    records.swap_column(col, count_rows - col - 1);
                }

                {
                    let n = std::cmp::max(count_rows, count_cols);
                    for (shift, row) in (count_rows..n).enumerate() {
                        let row = row - shift;
                        records.remove_column(row);
                    }

                    for (shift, col) in (count_cols..n).enumerate() {
                        let col = col - shift;
                        records.remove_row(col);
                    }
                }
            }
            Self::Bottom => {
                for row in 0..count_rows / 2 {
                    for col in 0..count_cols {
                        let last_row = count_rows - row - 1;
                        records.swap((last_row, col), (row, col));
                    }
                }
            }
            Self::Top => Self::Bottom.change(table),
        }
    }
}