| 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 | |