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 | #![cfg_attr (feature = "std" , doc = "```" )] |
9 | #![cfg_attr (not(feature = "std" ), doc = "```ignore" )] |
10 | //! use tabled::{Table, settings::Rotate}; |
11 | //! |
12 | //! let data = [[1, 2, 3], [4, 5, 6]]; |
13 | //! |
14 | //! let table = Table::new(data).with(Rotate::Left).to_string(); |
15 | //! |
16 | //! assert_eq!( |
17 | //! table, |
18 | //! concat!( |
19 | //! "+---+---+---+ \n" , |
20 | //! "| 2 | 3 | 6 | \n" , |
21 | //! "+---+---+---+ \n" , |
22 | //! "| 1 | 2 | 5 | \n" , |
23 | //! "+---+---+---+ \n" , |
24 | //! "| 0 | 1 | 4 | \n" , |
25 | //! "+---+---+---+" , |
26 | //! ) |
27 | //! ); |
28 | //! ``` |
29 | //! |
30 | //! [`Table`]: crate::Table |
31 | //! [`Builder::index`]: crate::builder::Builder::index |
32 | |
33 | // use core::cmp::max; |
34 | use core::cmp::max; |
35 | |
36 | use crate::{ |
37 | grid::records::{ExactRecords, Records, Resizable}, |
38 | settings::TableOption, |
39 | }; |
40 | |
41 | /// Rotate can be used to rotate a table by 90 degrees. |
42 | #[derive (Debug)] |
43 | pub enum Rotate { |
44 | /// Rotate [`Table`] to the left. |
45 | /// |
46 | /// [`Table`]: crate::Table |
47 | Left, |
48 | /// Rotate [`Table`] to the right. |
49 | /// |
50 | /// [`Table`]: crate::Table |
51 | Right, |
52 | /// Rotate [`Table`] to the top. |
53 | /// |
54 | /// So the top becomes the bottom. |
55 | /// |
56 | /// [`Table`]: crate::Table |
57 | Top, |
58 | /// Rotate [`Table`] to the bottom. |
59 | /// |
60 | /// So the top becomes the bottom. |
61 | /// |
62 | /// [`Table`]: crate::Table |
63 | Bottom, |
64 | } |
65 | |
66 | impl<R, D, C> TableOption<R, C, D> for Rotate |
67 | where |
68 | R: Records + ExactRecords + Resizable, |
69 | { |
70 | fn change(self, records: &mut R, _: &mut C, _: &mut D) { |
71 | match self { |
72 | Self::Left => rotate_left(records), |
73 | Self::Right => rotate_right(records), |
74 | Self::Bottom | Self::Top => rotate_horizontal(records), |
75 | } |
76 | } |
77 | } |
78 | |
79 | fn rotate_horizontal<R>(records: &mut R) |
80 | where |
81 | R: Records + ExactRecords + Resizable, |
82 | { |
83 | let count_rows: usize = records.count_rows(); |
84 | let count_cols: usize = records.count_columns(); |
85 | |
86 | for row: usize in 0..count_rows / 2 { |
87 | for col: usize in 0..count_cols { |
88 | let last_row: usize = count_rows - row - 1; |
89 | records.swap((last_row, col), (row, col)); |
90 | } |
91 | } |
92 | } |
93 | |
94 | fn rotate_left<R>(records: &mut R) |
95 | where |
96 | R: Records + ExactRecords + Resizable, |
97 | { |
98 | let count_rows = records.count_rows(); |
99 | let count_cols = records.count_columns(); |
100 | let size = max(count_rows, count_cols); |
101 | |
102 | { |
103 | for _ in count_rows..size { |
104 | records.push_row(); |
105 | } |
106 | |
107 | for _ in count_cols..size { |
108 | records.push_column(); |
109 | } |
110 | } |
111 | |
112 | for col in 0..size { |
113 | for row in col..size { |
114 | records.swap((col, row), (row, col)); |
115 | } |
116 | } |
117 | |
118 | for row in 0..count_cols / 2 { |
119 | records.swap_row(row, count_cols - row - 1); |
120 | } |
121 | |
122 | { |
123 | for (shift, row) in (count_rows..size).enumerate() { |
124 | let row = row - shift; |
125 | records.remove_column(row); |
126 | } |
127 | |
128 | for (shift, col) in (count_cols..size).enumerate() { |
129 | let col = col - shift; |
130 | records.remove_row(col); |
131 | } |
132 | } |
133 | } |
134 | |
135 | fn rotate_right<R>(records: &mut R) |
136 | where |
137 | R: Records + ExactRecords + Resizable, |
138 | { |
139 | let count_rows = records.count_rows(); |
140 | let count_cols = records.count_columns(); |
141 | let size = max(count_rows, count_cols); |
142 | |
143 | { |
144 | for _ in count_rows..size { |
145 | records.push_row(); |
146 | } |
147 | |
148 | for _ in count_cols..size { |
149 | records.push_column(); |
150 | } |
151 | } |
152 | |
153 | for col in 0..size { |
154 | for row in col..size { |
155 | records.swap((col, row), (row, col)); |
156 | } |
157 | } |
158 | |
159 | for col in 0..count_rows / 2 { |
160 | records.swap_column(col, count_rows - col - 1); |
161 | } |
162 | |
163 | { |
164 | for (shift, row) in (count_rows..size).enumerate() { |
165 | let row = row - shift; |
166 | records.remove_column(row); |
167 | } |
168 | |
169 | for (shift, col) in (count_cols..size).enumerate() { |
170 | let col = col - shift; |
171 | records.remove_row(col); |
172 | } |
173 | } |
174 | } |
175 | |