1use crate::{grid::records::vec_records::CellInfo, Table};
2
3use super::Builder;
4
5/// [`IndexBuilder`] helps to add an index to the table.
6///
7/// Index is a column on the left of the table.
8///
9/// It also can be used to transpose the table.
10///
11/// Creates a new [`IndexBuilder`] instance.
12///
13/// It creates a default index a range from 0 to N. (N - count rows)
14/// It also sets a default columns to the range 0 .. N (N - count columns).
15///nfo<'a>
16/// # Example
17///
18/// ```
19/// use tabled::builder::Builder;
20///
21/// let mut builder = Builder::default();
22/// builder.push_record(["i", "col-1", "col-2"]);
23/// builder.push_record(["0", "value-1", "value-2"]);
24///
25/// let table = builder.index().build().to_string();
26///
27/// assert_eq!(
28/// table,
29/// "+---+---+---------+---------+\n\
30/// | | i | col-1 | col-2 |\n\
31/// +---+---+---------+---------+\n\
32/// | 0 | 0 | value-1 | value-2 |\n\
33/// +---+---+---------+---------+"
34/// )
35/// ```
36///
37/// # Example
38///
39/// ```
40/// use tabled::builder::Builder;
41///
42/// let table = Builder::default()
43/// .index()
44/// .build();
45/// ```
46#[derive(Debug, Clone)]
47pub struct IndexBuilder {
48 /// Index is an index data.
49 /// It's always set.
50 index: Vec<CellInfo<String>>,
51 /// Name of an index
52 name: Option<CellInfo<String>>,
53 /// A flag which checks if we need to actually use index.
54 ///
55 /// It might happen when it's only necessary to [`Self::transpose`] table.
56 print_index: bool,
57 /// A flag which checks if table was transposed.
58 transposed: bool,
59 /// Data originated in [`Builder`].
60 data: Vec<Vec<CellInfo<String>>>,
61 /// A size of columns
62 count_columns: usize,
63}
64
65impl IndexBuilder {
66 /// No flag makes builder to not use an index.
67 ///
68 /// It may be useful when only [`Self::transpose`] need to be used.
69 ///
70 /// ```
71 /// use tabled::builder::Builder;
72 ///
73 /// let mut builder = Builder::default();
74 /// builder.push_record(["i", "col-1", "col-2"]);
75 /// builder.push_record(["0", "value-1", "value-2"]);
76 /// builder.push_record(["2", "value-3", "value-4"]);
77 ///
78 /// let table = builder.index().hide().build().to_string();
79 ///
80 /// assert_eq!(
81 /// table,
82 /// "+---+---------+---------+\n\
83 /// | i | col-1 | col-2 |\n\
84 /// +---+---------+---------+\n\
85 /// | 0 | value-1 | value-2 |\n\
86 /// +---+---------+---------+\n\
87 /// | 2 | value-3 | value-4 |\n\
88 /// +---+---------+---------+"
89 /// )
90 /// ```
91 pub fn hide(mut self) -> Self {
92 self.print_index = false;
93 self
94 }
95
96 /// Set an index name.
97 ///
98 /// When [`None`] the name won't be used.
99 ///
100 /// # Example
101 ///
102 /// ```
103 /// use tabled::builder::Builder;
104 ///
105 /// let mut builder = Builder::default();
106 /// builder.push_record(["i", "column1", "column2"]);
107 /// builder.push_record(["0", "value1", "value2"]);
108 ///
109 /// let table = builder.index()
110 /// .column(1)
111 /// .name(Some(String::from("index")))
112 /// .build();
113 ///
114 /// assert_eq!(
115 /// table.to_string(),
116 /// "+--------+---+---------+\n\
117 /// | | i | column2 |\n\
118 /// +--------+---+---------+\n\
119 /// | index | | |\n\
120 /// +--------+---+---------+\n\
121 /// | value1 | 0 | value2 |\n\
122 /// +--------+---+---------+"
123 /// )
124 /// ```
125 pub fn name(mut self, name: Option<String>) -> Self {
126 self.name = name.map(CellInfo::new);
127 self
128 }
129
130 /// Sets a index to the chosen column.
131 ///
132 /// Also sets a name of the index to the column name.
133 ///
134 /// # Example
135 ///
136 /// ```
137 /// use tabled::builder::Builder;
138 ///
139 /// let mut builder = Builder::default();
140 /// builder.push_record(["i", "column1", "column2"]);
141 /// builder.push_record(["0", "value1", "value2"]);
142 ///
143 /// let table = builder.index().column(1).build();
144 ///
145 /// assert_eq!(
146 /// table.to_string(),
147 /// "+---------+---+---------+\n\
148 /// | | i | column2 |\n\
149 /// +---------+---+---------+\n\
150 /// | column1 | | |\n\
151 /// +---------+---+---------+\n\
152 /// | value1 | 0 | value2 |\n\
153 /// +---------+---+---------+"
154 /// )
155 /// ```
156 pub fn column(mut self, column: usize) -> Self {
157 if column >= self.count_columns {
158 return self;
159 }
160
161 self.index = get_column(&mut self.data, column);
162
163 let name = self.index.remove(0);
164 self.name = Some(name);
165
166 self
167 }
168
169 /// Transpose index and columns.
170 ///
171 /// # Example
172 ///
173 /// ```
174 /// use tabled::builder::Builder;
175 ///
176 /// let mut builder = Builder::default();
177 /// builder.push_record(["i", "column-1", "column-2", "column-3"]);
178 /// builder.push_record(["0", "value-1", "value-2", "value-3"]);
179 /// builder.push_record(["1", "value-4", "value-5", "value-6"]);
180 /// builder.push_record(["2", "value-7", "value-8", "value-9"]);
181 ///
182 /// let table = builder.index().column(1).transpose().build();
183 ///
184 /// assert_eq!(
185 /// table.to_string(),
186 /// "+----------+---------+---------+---------+\n\
187 /// | column-1 | value-1 | value-4 | value-7 |\n\
188 /// +----------+---------+---------+---------+\n\
189 /// | i | 0 | 1 | 2 |\n\
190 /// +----------+---------+---------+---------+\n\
191 /// | column-2 | value-2 | value-5 | value-8 |\n\
192 /// +----------+---------+---------+---------+\n\
193 /// | column-3 | value-3 | value-6 | value-9 |\n\
194 /// +----------+---------+---------+---------+"
195 /// )
196 /// ```
197 pub fn transpose(mut self) -> Self {
198 if self.data.is_empty() {
199 return self;
200 }
201
202 let mut columns = self.data.remove(0);
203 std::mem::swap(&mut self.index, &mut columns);
204
205 let count_columns = columns.len();
206 make_rows_columns(&mut self.data, self.index.len());
207
208 self.data.insert(0, columns);
209
210 self.transposed = !self.transposed;
211 self.count_columns = count_columns;
212
213 self
214 }
215
216 /// Builds a table.
217 pub fn build(self) -> Table {
218 let builder: Builder = self.into();
219 builder.build()
220 }
221}
222
223impl From<Builder> for IndexBuilder {
224 fn from(builder: Builder) -> Self {
225 let count_columns: usize = builder.count_columns();
226 let data: Vec<Vec<_>> = builder.into();
227
228 let mut index: Vec> = Vec::new();
229 if !data.is_empty() {
230 // we exclude first row which contains a header
231 let count_rows: usize = data.len() - 1;
232 index = build_range_index(count_rows);
233 }
234
235 Self {
236 index,
237 data,
238 count_columns,
239 name: None,
240 print_index: true,
241 transposed: false,
242 }
243 }
244}
245
246impl From<IndexBuilder> for Builder {
247 fn from(b: IndexBuilder) -> Self {
248 build_index(b)
249 }
250}
251
252fn build_index(mut b: IndexBuilder) -> Builder {
253 // we can skip the conversion if this builder has neither data rows nor header row
254 if b.index.is_empty() && b.count_columns == 0 {
255 return Builder::default();
256 }
257
258 // add index column
259 if b.print_index {
260 b.index.insert(0, CellInfo::default());
261 insert_column(&mut b.data, b.index, 0);
262 }
263
264 if let Some(name) = b.name {
265 if b.transposed && b.print_index {
266 b.data[0][0] = name;
267 } else {
268 let count_columns = b.data[0].len();
269 let mut name_row = vec![CellInfo::default(); count_columns];
270 name_row[0] = name;
271
272 b.data.insert(1, name_row);
273 }
274 }
275
276 Builder::from_vec(b.data)
277}
278
279fn build_range_index(n: usize) -> Vec<CellInfo<String>> {
280 (0..n).map(|i: usize| i.to_string()).map(CellInfo::new).collect()
281}
282
283fn get_column<T>(v: &mut [Vec<T>], col: usize) -> Vec<T>
284where
285 T: Default,
286{
287 let mut column: Vec = Vec::with_capacity(v.len());
288 for row: &mut Vec in v.iter_mut() {
289 let value: T = row.remove(index:col);
290 column.push(value);
291 }
292
293 column
294}
295
296// todo: Seems like can be hugely simplified.
297fn make_rows_columns<T>(v: &mut Vec<Vec<T>>, count_columns: usize)
298where
299 T: Default,
300{
301 let mut columns: Vec> = Vec::with_capacity(count_columns);
302 for _ in 0..count_columns {
303 let column: Vec = get_column(v, col:0);
304 columns.push(column);
305 }
306
307 v.clear();
308
309 for column: Vec in columns {
310 v.push(column);
311 }
312}
313
314fn insert_column<T: Default>(v: &mut [Vec<T>], mut column: Vec<T>, col: usize) {
315 for row: &mut Vec in v.iter_mut() {
316 let value: T = column.remove(index:col);
317 row.insert(index:col, element:value);
318 }
319}
320