tabled/features/rotate.rs
1//! This module contains a [`Rotate`] primitive which can be used in order to rotate [`Table`].
2//!
3//! It's also possible to transpose the table at the point of construction.
4//! See [`Builder::index`].
5//!
6//! # Example
7//!
8//! ```
9//! use tabled::{Rotate, TableIteratorExt};
10//!
11//! let data = [[1, 2, 3], [4, 5, 6]];
12//!
13//! let table = data.table().with(Rotate::Left).to_string();
14//!
15//! assert_eq!(
16//! table,
17//! concat!(
18//! "+---+---+---+\n",
19//! "| 2 | 3 | 6 |\n",
20//! "+---+---+---+\n",
21//! "| 1 | 2 | 5 |\n",
22//! "+---+---+---+\n",
23//! "| 0 | 1 | 4 |\n",
24//! "+---+---+---+",
25//! )
26//! );
27//! ```
28//!
29//! [`Table`]: crate::Table
30//! [`Builder::index`]: crate::builder::Builder::index
31
32use papergrid::records::{Records, Resizable};
33
34use crate::{Table, TableOption};
35
36/// Rotate can be used to rotate a table by 90 degrees.
37#[derive(Debug)]
38pub enum Rotate {
39 /// Rotate [`Table`] to the left.
40 ///
41 /// [`Table`]: crate::Table
42 Left,
43 /// Rotate [`Table`] to the right.
44 ///
45 /// [`Table`]: crate::Table
46 Right,
47 /// Rotate [`Table`] to the top.
48 ///
49 /// So the top becames the bottom.
50 ///
51 /// [`Table`]: crate::Table
52 Top,
53 /// Rotate [`Table`] to the bottom.
54 ///
55 /// So the top becames the bottom.
56 ///
57 /// [`Table`]: crate::Table
58 Bottom,
59}
60
61impl<R> TableOption<R> for Rotate
62where
63 R: Records + Resizable,
64{
65 fn change(&mut self, table: &mut Table<R>) {
66 let (count_rows, count_cols) = table.shape();
67 let records = table.get_records_mut();
68 match self {
69 Self::Left => {
70 {
71 let n = std::cmp::max(count_rows, count_cols);
72 for _ in count_rows..n {
73 records.push_row();
74 }
75
76 for _ in count_cols..n {
77 records.push_column();
78 }
79 }
80
81 for col in 0..count_cols {
82 for row in col..count_rows {
83 records.swap((col, row), (row, col));
84 }
85 }
86
87 for row in 0..count_cols / 2 {
88 records.swap_row(row, count_cols - row - 1);
89 }
90
91 {
92 let n = std::cmp::max(count_rows, count_cols);
93 for (shift, row) in (count_rows..n).enumerate() {
94 let row = row - shift;
95 records.remove_column(row);
96 }
97
98 for (shift, col) in (count_cols..n).enumerate() {
99 let col = col - shift;
100 records.remove_row(col);
101 }
102 }
103 }
104 Self::Right => {
105 {
106 let n = std::cmp::max(count_rows, count_cols);
107 for _ in count_rows..n {
108 records.push_row();
109 }
110
111 for _ in count_cols..n {
112 records.push_column();
113 }
114 }
115
116 for col in 0..count_cols {
117 for row in col..count_rows {
118 records.swap((col, row), (row, col));
119 }
120 }
121
122 for col in 0..count_rows / 2 {
123 records.swap_column(col, count_rows - col - 1);
124 }
125
126 {
127 let n = std::cmp::max(count_rows, count_cols);
128 for (shift, row) in (count_rows..n).enumerate() {
129 let row = row - shift;
130 records.remove_column(row);
131 }
132
133 for (shift, col) in (count_cols..n).enumerate() {
134 let col = col - shift;
135 records.remove_row(col);
136 }
137 }
138 }
139 Self::Bottom => {
140 for row in 0..count_rows / 2 {
141 for col in 0..count_cols {
142 let last_row = count_rows - row - 1;
143 records.swap((last_row, col), (row, col));
144 }
145 }
146 }
147 Self::Top => Self::Bottom.change(table),
148 }
149 }
150}