1use std::iter::FromIterator;
2
3use crate::{grid::records::vec_records::CellInfo, Table};
4
5use super::IndexBuilder;
6
7/// Builder creates a [`Table`] from dynamic data set.
8///
9/// It useful when the amount of columns or rows is not known statically.
10///
11/// ```rust
12/// use tabled::builder::Builder;
13///
14/// let mut builder = Builder::default();
15/// builder.push_record(["index", "measure", "value"]);
16/// builder.push_record(["0", "weight", "0.443"]);
17///
18/// let table = builder.build();
19///
20/// println!("{}", table);
21/// ```
22///
23/// It may be useful to use [`FromIterator`] for building.
24///
25/// ```rust
26/// use tabled::builder::Builder;
27/// use std::iter::FromIterator;
28///
29/// let data = vec![
30/// ["column1", "column2"],
31/// ["data1", "data2"],
32/// ["data3", "data4"],
33/// ];
34///
35/// let table = Builder::from_iter(data).build();
36///
37/// println!("{}", table);
38/// ```
39#[derive(Debug, Default, Clone)]
40pub struct Builder {
41 /// A list of rows.
42 data: Vec<Vec<CellInfo<String>>>,
43 /// A number of columns.
44 count_columns: usize,
45 /// A content of cells which are created in case rows has different length.
46 empty_text: CellInfo<String>,
47}
48
49impl Builder {
50 /// Creates a [`Builder`] instance.
51 ///
52 /// ```
53 /// use tabled::builder::Builder;
54 ///
55 /// let builder = Builder::new();
56 /// ```
57 pub fn new() -> Self {
58 Self::default()
59 }
60
61 /// Creates a [`Builder`] instance with a given row capacity.
62 ///
63 /// ```
64 /// use tabled::builder::Builder;
65 ///
66 /// let mut builder = Builder::with_capacity(2, 3);
67 /// builder.push_record((0..3).map(|i| i.to_string()));
68 /// builder.push_record(["i", "surname", "lastname"]);
69 /// ```
70 pub fn with_capacity(count_records: usize, count_columns: usize) -> Self {
71 let mut builder = Self::new();
72 builder.data = Vec::with_capacity(count_records);
73 builder.count_columns = count_columns;
74
75 builder
76 }
77
78 /// Creates a [`Builder`] instance.
79 ///
80 /// # Safety
81 ///
82 /// It's marked unsafe to emphasize that you shall make sure that all rows bound to have the same length.
83 ///
84 /// ```
85 /// use tabled::builder::Builder;
86 ///
87 /// let data = vec![];
88 /// let builder = Builder::from_vec(data);
89 /// ```
90 pub fn from_vec(data: Vec<Vec<CellInfo<String>>>) -> Self {
91 let count_columns = if data.is_empty() { 0 } else { data[0].len() };
92
93 Self {
94 data,
95 count_columns,
96 empty_text: CellInfo::default(),
97 }
98 }
99
100 /// Sets a content of cells which are created in case rows has different length.
101 ///
102 ///
103 /// ```rust
104 /// use tabled::builder::Builder;
105 ///
106 /// let mut builder = Builder::default();
107 /// builder.set_empty("undefined");
108 /// builder.push_record((0..3).map(|i| i.to_string()));
109 /// builder.push_record(["i"]);
110 /// ```
111 pub fn set_empty<T>(&mut self, text: T)
112 where
113 T: Into<String>,
114 {
115 self.empty_text = CellInfo::new(text.into());
116 }
117
118 /// Build creates a [`Table`] instance.
119 ///
120 /// ```rust
121 /// use tabled::builder::Builder;
122 ///
123 /// let mut builder = Builder::default();
124 /// builder.push_record(["i", "column1", "column2"]);
125 /// builder.push_record(["0", "value1", "value2"]);
126 /// ```
127 pub fn build(self) -> Table {
128 Table::from(self)
129 }
130
131 /// Add an index to the [`Table`].
132 ///
133 /// Default index is a range 0-N where N is amount of records.
134 ///
135 /// # Example
136 ///
137 /// ```
138 /// use tabled::Table;
139 ///
140 /// let table = Table::builder(&["Hello", "World", "!"]).index().build();
141 ///
142 /// assert_eq!(
143 /// table.to_string(),
144 /// "+---+-------+\n\
145 /// | | &str |\n\
146 /// +---+-------+\n\
147 /// | 0 | Hello |\n\
148 /// +---+-------+\n\
149 /// | 1 | World |\n\
150 /// +---+-------+\n\
151 /// | 2 | ! |\n\
152 /// +---+-------+"
153 /// )
154 /// ```
155 pub fn index(self) -> IndexBuilder {
156 IndexBuilder::from(self)
157 }
158
159 /// Adds a row to a [`Table`].
160 ///
161 /// ```
162 /// use tabled::builder::Builder;
163 ///
164 /// let mut builder = Builder::default();
165 /// builder.push_record((0..3).map(|i| i.to_string()));
166 /// builder.push_record(["i", "surname", "lastname"]);
167 /// ```
168 pub fn push_record<R>(&mut self, record: R)
169 where
170 R: IntoIterator,
171 R::Item: Into<String>,
172 {
173 let list = create_row(record, self.count_columns, &self.empty_text);
174 let list_length = list.len();
175
176 if !is_size_eq(self.count_columns, list_length) {
177 let size = list_length - self.count_columns;
178 resize_rows(&mut self.data, size, &self.empty_text)
179 }
180
181 self.count_columns = list_length;
182 self.data.push(list);
183 }
184
185 /// Insert a row into a specific position.
186 ///
187 /// # Panics
188 ///
189 /// Panics if `index > count_rows`.
190 pub fn insert_record<R>(&mut self, index: usize, record: R)
191 where
192 R: IntoIterator,
193 R::Item: Into<String>,
194 {
195 let list = create_row(record, self.count_columns, &self.empty_text);
196 let list_length = list.len();
197
198 if !is_size_eq(self.count_columns, list_length) {
199 let size = list_length - self.count_columns;
200 resize_rows(&mut self.data, size, &self.empty_text)
201 }
202
203 self.count_columns = list_length;
204 self.data.insert(index, list);
205 }
206
207 /// Clean removes empty columns and rows.
208 ///
209 /// # Example
210 ///
211 /// ```
212 /// use tabled::Table;
213 ///
214 /// let mut builder = Table::builder(&["Hello", "World", ""]);
215 /// builder.clean();
216 ///
217 /// let table = builder.build();
218 ///
219 /// assert_eq!(
220 /// table.to_string(),
221 /// "+-------+\n\
222 /// | &str |\n\
223 /// +-------+\n\
224 /// | Hello |\n\
225 /// +-------+\n\
226 /// | World |\n\
227 /// +-------+"
228 /// )
229 /// ```
230 pub fn clean(&mut self) {
231 self.count_columns -= remove_empty_columns(&mut self.data, self.count_columns);
232 remove_empty_rows(&mut self.data, self.count_columns);
233 }
234
235 /// Removes a row with a specific position.
236 ///
237 /// Index expected to be in range.
238 /// `Builder::count_records() < x >= 0`
239 ///
240 /// # Panics
241 ///
242 /// Panics if `row_index > count_rows`.
243 pub fn remove_record(&mut self, index: usize) {
244 let _ = self.data.remove(index);
245 }
246
247 /// Removes a column with a specific position.
248 ///
249 /// Index expected to be in range.
250 /// `Builder::count_columns() < x >= 0`
251 ///
252 /// # Panics
253 ///
254 /// Panics if `index > count_columns`.
255 pub fn remove_column(&mut self, index: usize) {
256 for row in &mut self.data {
257 let _ = row.remove(index);
258 }
259
260 self.count_columns -= 1;
261 }
262
263 /// Push a column.
264 pub fn push_column<I>(&mut self, column: I)
265 where
266 I: IntoIterator,
267 I::Item: Into<String>,
268 {
269 let mut iter = column.into_iter();
270
271 for row in self.data.iter_mut() {
272 let text = iter
273 .next()
274 .map(Into::into)
275 .map(CellInfo::new)
276 .unwrap_or(self.empty_text.clone());
277
278 row.push(text);
279 }
280
281 for text in iter {
282 let text = CellInfo::new(text.into());
283
284 let mut row = Vec::with_capacity(self.count_columns + 1);
285 for _ in 0..self.count_columns {
286 row.push(self.empty_text.clone());
287 }
288
289 row.push(text);
290 }
291
292 self.count_columns += 1;
293 }
294
295 /// Insert a column with a specific position.
296 ///
297 /// In case a column is bigger then the total amount of rows it will be truncated.
298 ///
299 /// # Panics
300 ///
301 /// Panics if `index > count_columns`.
302 pub fn insert_column<I>(&mut self, index: usize, column: I)
303 where
304 I: IntoIterator,
305 I::Item: Into<String>,
306 {
307 let mut iter = column.into_iter();
308
309 for row in self.data.iter_mut() {
310 let text = iter
311 .next()
312 .map(Into::into)
313 .map(CellInfo::new)
314 .unwrap_or(self.empty_text.clone());
315
316 row.insert(index, text);
317 }
318
319 for text in iter {
320 let text = CellInfo::new(text.into());
321
322 let mut row = Vec::with_capacity(self.count_columns + 1);
323 for _ in 0..index {
324 row.push(self.empty_text.clone());
325 }
326
327 row.push(text);
328
329 for _ in index..self.count_columns {
330 row.push(self.empty_text.clone());
331 }
332 }
333
334 self.count_columns += 1;
335 }
336
337 /// Remove all records.
338 pub fn clear(&mut self) {
339 self.data.clear();
340 self.count_columns = 0;
341 }
342
343 /// Returns an amount of columns which would be present in a built table.
344 pub fn count_columns(&self) -> usize {
345 self.count_columns
346 }
347
348 /// Returns an amount of rows which would be present in a built table.
349 ///
350 /// Notice that it does not include header if present;
351 /// It returns only amount of records.
352 pub fn count_records(&self) -> usize {
353 self.data.len()
354 }
355}
356
357impl From<Builder> for Vec<Vec<String>> {
358 fn from(builder: Builder) -> Self {
359 builderimpl Iterator>
360 .data
361 .into_iter()
362 .map(|row: Vec>| row.into_iter().map(CellInfo::into_inner).collect())
363 .collect()
364 }
365}
366
367impl From<Builder> for Vec<Vec<CellInfo<String>>> {
368 fn from(builder: Builder) -> Self {
369 builder.data
370 }
371}
372
373impl<R> FromIterator<R> for Builder
374where
375 R: IntoIterator,
376 R::Item: Into<String>,
377{
378 fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
379 let mut builder: Builder = Self::new();
380 for row in iter {
381 builder.push_record(row);
382 }
383
384 builder
385 }
386}
387
388impl<D> Extend<D> for Builder
389where
390 D: Into<String>,
391{
392 fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
393 self.push_record(iter);
394 }
395}
396
397impl From<Vec<Vec<String>>> for Builder {
398 fn from(data: Vec<Vec<String>>) -> Self {
399 let mut data: Vec>> = dataimpl Iterator>>
400 .into_iter()
401 .map(|row: Vec| row.into_iter().map(CellInfo::new).collect())
402 .collect();
403
404 let count_columns: usize = equalize_row_length(&mut data);
405
406 Self {
407 data,
408 count_columns,
409 empty_text: CellInfo::default(),
410 }
411 }
412}
413
414impl From<Vec<Vec<CellInfo<String>>>> for Builder {
415 fn from(mut data: Vec<Vec<CellInfo<String>>>) -> Self {
416 let count_columns: usize = equalize_row_length(&mut data);
417
418 Self {
419 data,
420 count_columns,
421 empty_text: CellInfo::default(),
422 }
423 }
424}
425
426fn create_row<R>(row: R, size: usize, default: &CellInfo<String>) -> Vec<CellInfo<String>>
427where
428 R: IntoIterator,
429 R::Item: Into<String>,
430{
431 let mut list: Vec> = Vec::with_capacity(size);
432 for text: impl Into in row {
433 let text: String = text.into();
434 let text: CellInfo = CellInfo::new(text);
435 list.push(text);
436 }
437
438 if list.len() < size {
439 for _ in 0..size - list.len() {
440 let text: CellInfo = default.clone();
441 list.push(text);
442 }
443 }
444
445 list
446}
447
448fn remove_empty_columns(data: &mut [Vec<CellInfo<String>>], count_columns: usize) -> usize {
449 let mut deleted = 0;
450 for col in 0..count_columns {
451 let col = col - deleted;
452
453 let mut is_empty_column = true;
454 for row in data.iter() {
455 let text = &row[col];
456 if !text.as_ref().is_empty() {
457 is_empty_column = false;
458 break;
459 }
460 }
461
462 if is_empty_column {
463 for row in data.iter_mut() {
464 let _ = row.remove(col);
465 }
466
467 deleted += 1;
468 }
469 }
470
471 deleted
472}
473
474fn remove_empty_rows(data: &mut Vec<Vec<CellInfo<String>>>, count_columns: usize) {
475 let mut deleted: usize = 0;
476
477 for row: usize in 0..data.len() {
478 let row: usize = row - deleted;
479
480 let mut is_empty_row: bool = true;
481 for col: usize in 0..count_columns {
482 let cell: &CellInfo = &data[row][col];
483 if !cell.as_ref().is_empty() {
484 is_empty_row = false;
485 break;
486 }
487 }
488
489 if is_empty_row {
490 let _ = data.remove(index:row);
491 deleted += 1;
492 }
493 }
494}
495
496fn resize_rows(data: &mut Vec<Vec<CellInfo<String>>>, size: usize, empty_text: &CellInfo<String>) {
497 for row: &mut Vec> in data {
498 append_vec(v:row, value:empty_text.clone(), n:size);
499 }
500}
501
502fn append_vec<T>(v: &mut Vec<T>, value: T, n: usize)
503where
504 T: Clone,
505{
506 for _ in 0..n {
507 v.push(value.clone());
508 }
509}
510
511fn is_size_eq(expected: usize, new: usize) -> bool {
512 use std::cmp::Ordering;
513
514 match new.cmp(&expected) {
515 Ordering::Less => {
516 unreachable!("must be impossible due to the assumptions/checks we do");
517 }
518 Ordering::Greater => false,
519 Ordering::Equal => true,
520 }
521}
522
523fn equalize_row_length(data: &mut Vec<Vec<CellInfo<String>>>) -> usize {
524 if data.is_empty() {
525 return 0;
526 }
527
528 let first_row_length: usize = data[0].len();
529 let init: (usize, bool) = (first_row_length, true);
530 let (count_columns: usize, is_consistent: bool) = data.iter().fold(init, |mut acc: (usize, bool), cur: &Vec>| {
531 let length: usize = cur.len();
532 acc.1 = acc.1 && acc.0 == length;
533 acc.0 = std::cmp::max(v1:acc.0, v2:length);
534 acc
535 });
536
537 if !is_consistent {
538 let empty_text: CellInfo = CellInfo::default();
539 for row: &mut Vec> in data {
540 let size: usize = count_columns - row.len();
541 append_vec(v:row, value:empty_text.clone(), n:size);
542 }
543 }
544
545 count_columns
546}
547