tabled/builder.rs
1//! Builder module provides a [`Builder`] type which helps building
2//! a [`Table`] dynamically.
3//!
4//! It also contains [`IndexBuilder`] which can help to build a table with index.
5//!
6//! # Examples
7//!
8//! Here's an example of [`IndexBuilder`] usage
9//!
10#![cfg_attr(feature = "derive", doc = "```")]
11#![cfg_attr(not(feature = "derive"), doc = "```ignore")]
12//! use tabled::{Table, Tabled, Style};
13//!
14//! #[derive(Tabled)]
15//! struct Mission {
16//! name: &'static str,
17//! #[tabled(inline)]
18//! status: Status,
19//! }
20//!
21//! #[derive(Tabled)]
22//! enum Status {
23//! Complete,
24//! Started,
25//! Ready,
26//! Unknown,
27//! }
28//!
29//! let data = [
30//! Mission { name: "Algebra", status: Status::Unknown },
31//! Mission { name: "Apolo", status: Status::Complete },
32//! ];
33//!
34//! let mut builder = Table::builder(&data).index();
35//! builder
36//! .set_index(0)
37//! .set_name(None)
38//! .transpose();
39//!
40//! let mut table = builder.build();
41//! table.with(Style::modern());
42//!
43//! println!("{}", table);
44//!
45//! assert_eq!(
46//! table.to_string(),
47//! concat!(
48//! "┌──────────┬─────────┬───────┐\n",
49//! "│ │ Algebra │ Apolo │\n",
50//! "├──────────┼─────────┼───────┤\n",
51//! "│ Complete │ │ + │\n",
52//! "├──────────┼─────────┼───────┤\n",
53//! "│ Started │ │ │\n",
54//! "├──────────┼─────────┼───────┤\n",
55//! "│ Ready │ │ │\n",
56//! "├──────────┼─────────┼───────┤\n",
57//! "│ Unknown │ + │ │\n",
58//! "└──────────┴─────────┴───────┘",
59//! ),
60//! )
61//! ```
62//!
63//! Example when we don't want to show empty data of enum where not all variants are used.
64//!
65#![cfg_attr(feature = "derive", doc = "```")]
66#![cfg_attr(not(feature = "derive"), doc = "```ignore")]
67//! use tabled::{Table, Tabled, Style};
68//!
69//! #[derive(Tabled)]
70//! enum Status {
71//! #[tabled(inline)]
72//! Complete {
73//! started_timestamp: usize,
74//! finihsed_timestamp: usize,
75//! },
76//! #[tabled(inline)]
77//! Started {
78//! timestamp: usize,
79//! },
80//! Ready,
81//! Unknown,
82//! }
83//!
84//! let data = [
85//! Status::Unknown,
86//! Status::Complete { started_timestamp: 123, finihsed_timestamp: 234 },
87//! ];
88//!
89//! let mut builder = Table::builder(&data);
90//! builder.clean();
91//!
92//! let table = builder.build()
93//! .with(Style::modern())
94//! .to_string();
95//!
96//! println!("{}", table);
97//!
98//! assert_eq!(
99//! table,
100//! concat!(
101//! "┌───────────────────┬────────────────────┬─────────┐\n",
102//! "│ started_timestamp │ finihsed_timestamp │ Unknown │\n",
103//! "├───────────────────┼────────────────────┼─────────┤\n",
104//! "│ │ │ + │\n",
105//! "├───────────────────┼────────────────────┼─────────┤\n",
106//! "│ 123 │ 234 │ │\n",
107//! "└───────────────────┴────────────────────┴─────────┘",
108//! ),
109//! )
110//! ```
111
112use std::{borrow::Cow, iter::FromIterator};
113
114use papergrid::{
115 records::{
116 cell_info::CellInfo,
117 vec_records::{CellMut, VecRecords},
118 Records,
119 },
120 width::{CfgWidthFunction, WidthFunc},
121 AlignmentHorizontal, Entity, Formatting, GridConfig, Indent, Padding,
122};
123
124use crate::{Style, Table};
125
126/// Builder creates a [`Table`] from dynamic data set.
127///
128/// It useful when the amount of columns or rows is not known statically.
129///
130/// ```rust
131/// use tabled::builder::Builder;
132///
133/// let mut builder = Builder::default();
134/// builder.set_columns(["index", "measure", "value"]);
135/// builder.add_record(["0", "weight", "0.443"]);
136///
137/// let table = builder.build();
138///
139/// println!("{}", table);
140/// ```
141///
142/// It may be useful to use [`FromIterator`] for building.
143///
144/// ```rust
145/// use tabled::builder::Builder;
146/// use std::iter::FromIterator;
147///
148/// let data = vec![
149/// ["column1", "column2"],
150/// ["data1", "data2"],
151/// ["data3", "data4"],
152/// ];
153///
154/// let table = Builder::from_iter(data).build();
155///
156/// println!("{}", table);
157/// ```
158#[derive(Debug, Default, Clone)]
159pub struct Builder<'a> {
160 /// A list of rows.
161 records: Vec<Vec<CellInfo<'a>>>,
162 /// A columns row.
163 columns: Option<Vec<CellInfo<'a>>>,
164 /// A number of columns.
165 size: usize,
166 different_column_sizes_used: bool,
167 /// A content of cells which are created in case rows has different length.
168 empty_cell_text: Option<String>,
169}
170
171impl<'a> Builder<'a> {
172 /// Creates a [`Builder`] instance.
173 pub fn new() -> Self {
174 Self::default()
175 }
176
177 /// Set a column size.
178 ///
179 /// If it make it lower then it was originally it is considered NOP.
180 pub fn hint_column_size(&mut self, size: usize) {
181 self.size = size;
182 }
183
184 /// Sets a [`Table`] header.
185 ///
186 /// ```rust
187 /// use tabled::builder::Builder;
188 ///
189 /// let mut builder = Builder::default();
190 /// builder
191 /// .set_columns((0..3).map(|i| i.to_string()))
192 /// .add_record(["i", "surname", "lastname"]);
193 /// ```
194 pub fn set_columns<H, T>(&mut self, columns: H) -> &mut Self
195 where
196 H: IntoIterator<Item = T>,
197 T: Into<Cow<'a, str>>,
198 {
199 let ctrl = CfgWidthFunction::new(4);
200 let list = create_row(columns, self.size, &ctrl);
201
202 self.update_size(list.len());
203 self.columns = Some(list);
204
205 self
206 }
207
208 /// Sets off a [`Table`] header.
209 ///
210 /// If not set its a nop.
211 ///
212 /// ```rust
213 /// use tabled::Table;
214 ///
215 /// let data = [("Hello", 1u8, false), ("World", 21u8, true)];
216 ///
217 /// let table = Table::builder(data).build().to_string();
218 ///
219 /// assert_eq!(
220 /// table,
221 /// "+-------+----+-------+\n\
222 /// | &str | u8 | bool |\n\
223 /// +-------+----+-------+\n\
224 /// | Hello | 1 | false |\n\
225 /// +-------+----+-------+\n\
226 /// | World | 21 | true |\n\
227 /// +-------+----+-------+"
228 /// );
229 ///
230 ///
231 /// let mut builder = Table::builder(data);
232 /// builder.remove_columns();
233 /// let table = builder.build().to_string();
234 ///
235 /// assert_eq!(
236 /// table,
237 /// "+-------+----+-------+\n\
238 /// | Hello | 1 | false |\n\
239 /// +-------+----+-------+\n\
240 /// | World | 21 | true |\n\
241 /// +-------+----+-------+"
242 /// );
243 ///
244 /// ```
245 pub fn remove_columns(&mut self) -> &mut Self {
246 self.columns = None;
247 let size = self.get_size();
248 self.size = size;
249
250 self
251 }
252
253 /// Adds a row to a [`Table`].
254 ///
255 /// If [`Self::set_columns`] is not set the first row will be considered a header.
256 ///
257 /// ```rust
258 /// use tabled::builder::Builder;
259 ///
260 /// let mut builder = Builder::default();
261 /// builder.add_record((0..3).map(|i| i.to_string()));
262 /// builder.add_record(["i", "surname", "lastname"]);
263 /// ```
264 pub fn add_record<R, T>(&mut self, row: R) -> &mut Self
265 where
266 R: IntoIterator<Item = T>,
267 T: Into<Cow<'a, str>>,
268 {
269 let ctrl = CfgWidthFunction::new(4);
270 let list = create_row(row, self.size, &ctrl);
271
272 self.update_size(list.len());
273 self.records.push(list);
274
275 self
276 }
277
278 /// Sets a content of cells which are created in case rows has different length.
279 ///
280 ///
281 /// ```rust
282 /// use tabled::builder::Builder;
283 ///
284 /// let mut builder = Builder::default();
285 /// builder.set_default_text("undefined");
286 /// builder.set_columns((0..3).map(|i| i.to_string()));
287 /// builder.add_record(["i"]);
288 /// ```
289 pub fn set_default_text<T>(&mut self, text: T) -> &mut Self
290 where
291 T: Into<String>,
292 {
293 self.empty_cell_text = Some(text.into());
294 self
295 }
296
297 /// Build creates a [`Table`] instance.
298 ///
299 /// ```rust
300 /// use tabled::builder::Builder;
301 ///
302 /// let mut builder = Builder::default();
303 /// builder.set_columns(["i", "column1", "column2"]);
304 /// builder.add_record(["0", "value1", "value2"]);
305 /// ```
306 pub fn build(mut self) -> Table<VecRecords<CellInfo<'a>>> {
307 if self.different_column_sizes_used {
308 self.fix_rows();
309 }
310
311 let has_columns = self.columns.is_some();
312 let records = build_grid(self.records, self.columns, self.size);
313 build_table(records, has_columns)
314 }
315
316 /// Add an index to the [`Table`].
317 ///
318 /// Default index is a range 0-N where N is amount of records.
319 ///
320 /// # Example
321 ///
322 /// ```
323 /// use tabled::Table;
324 ///
325 /// let table = Table::builder(&["Hello", "World", "!"]).index().build();
326 ///
327 /// assert_eq!(
328 /// table.to_string(),
329 /// "+---+-------+\n\
330 /// | | &str |\n\
331 /// +---+-------+\n\
332 /// | 0 | Hello |\n\
333 /// +---+-------+\n\
334 /// | 1 | World |\n\
335 /// +---+-------+\n\
336 /// | 2 | ! |\n\
337 /// +---+-------+"
338 /// )
339 /// ```
340 pub fn index(self) -> IndexBuilder<'a> {
341 IndexBuilder::new(self)
342 }
343
344 /// Clean removes empty columns and rows.
345 ///
346 /// # Example
347 ///
348 /// ```
349 /// use tabled::Table;
350 ///
351 /// let mut builder = Table::builder(&["Hello", "World", ""]);
352 /// builder.clean();
353 ///
354 /// let table = builder.build();
355 ///
356 /// assert_eq!(
357 /// table.to_string(),
358 /// "+-------+\n\
359 /// | &str |\n\
360 /// +-------+\n\
361 /// | Hello |\n\
362 /// +-------+\n\
363 /// | World |\n\
364 /// +-------+"
365 /// )
366 /// ```
367 pub fn clean(&mut self) -> &mut Self {
368 self.clean_columns();
369 self.clean_rows();
370 self
371 }
372
373 /// Creates a Builder from a built [`Records`]
374 ///
375 /// [`Records`]: papergrid::records::Records
376 pub fn custom<R>(records: R) -> CustomRecords<R> {
377 CustomRecords::new(records)
378 }
379
380 fn clean_columns(&mut self) {
381 let mut i = 0;
382 for col in 0..self.size {
383 let col = col - i;
384
385 let mut is_empty = true;
386 for row in 0..self.records.len() {
387 if !self.records[row][col].is_empty() {
388 is_empty = false;
389 break;
390 }
391 }
392
393 if is_empty {
394 for row in 0..self.records.len() {
395 self.records[row].remove(col);
396 }
397
398 if let Some(columns) = self.columns.as_mut() {
399 if columns.len() > col {
400 columns.remove(col);
401 }
402 }
403
404 i += 1;
405 }
406 }
407
408 self.size -= i;
409 }
410
411 fn clean_rows(&mut self) {
412 for row in (0..self.records.len()).rev() {
413 let mut is_empty = true;
414 for col in 0..self.size {
415 if !self.records[row][col].is_empty() {
416 is_empty = false;
417 break;
418 }
419 }
420
421 if is_empty {
422 self.records.remove(row);
423 }
424
425 if row == 0 {
426 break;
427 }
428 }
429 }
430
431 fn update_size(&mut self, size: usize) {
432 match size.cmp(&self.size) {
433 std::cmp::Ordering::Less => {
434 if !self.records.is_empty() {
435 self.different_column_sizes_used = true;
436 }
437 }
438 std::cmp::Ordering::Greater => {
439 self.size = size;
440
441 if !self.records.is_empty() || self.columns.is_some() {
442 self.different_column_sizes_used = true;
443 }
444 }
445 std::cmp::Ordering::Equal => (),
446 }
447 }
448
449 fn get_size(&mut self) -> usize {
450 let mut max = self.columns.as_ref().map_or(0, Vec::len);
451
452 let max_records = self.records.iter().map(Vec::len).max().unwrap_or(0);
453
454 max = std::cmp::max(max_records, max);
455
456 max
457 }
458
459 fn fix_rows(&mut self) {
460 let ctrl = CfgWidthFunction::new(4);
461 let text = self.empty_cell_text.clone().unwrap_or_default();
462 let empty_cell_text = CellInfo::new(text, &ctrl);
463
464 if let Some(header) = self.columns.as_mut() {
465 if self.size > header.len() {
466 append_vec(header, self.size - header.len(), &empty_cell_text);
467 }
468 }
469
470 for row in &mut self.records {
471 if self.size > row.len() {
472 append_vec(row, self.size - row.len(), &empty_cell_text);
473 }
474 }
475 }
476}
477
478impl<'a, R, V> FromIterator<R> for Builder<'a>
479where
480 R: IntoIterator<Item = V>,
481 V: Into<Cow<'a, str>>,
482{
483 fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
484 let mut builder = Self::default();
485 for row in iter {
486 builder.add_record(row);
487 }
488
489 builder
490 }
491}
492
493impl<'a, D> Extend<D> for Builder<'a>
494where
495 D: Into<Cow<'a, str>>,
496{
497 fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
498 self.add_record(iter);
499 }
500}
501
502impl From<Vec<Vec<String>>> for Builder<'_> {
503 fn from(strings: Vec<Vec<String>>) -> Self {
504 let size = strings.iter().map(|r| r.len()).max().unwrap_or(0);
505 if size == 0 {
506 return Self::default();
507 }
508
509 let ctrl = CfgWidthFunction::new(4);
510 let mut records = vec![vec![CellInfo::default(); size]; strings.len()];
511 for (row, list) in strings.into_iter().zip(records.iter_mut()) {
512 create_row_exact(list, row, &ctrl);
513 }
514
515 Self {
516 records,
517 size,
518 ..Default::default()
519 }
520 }
521}
522
523impl<'a> From<Vec<Vec<CellInfo<'a>>>> for Builder<'a> {
524 fn from(records: Vec<Vec<CellInfo<'a>>>) -> Self {
525 Self {
526 records,
527 ..Default::default()
528 }
529 }
530}
531
532/// [`IndexBuilder`] helps to add an index to the table.
533///
534/// Index is a column on the left of the table.
535///
536/// It also can be used to transpose the table.
537///
538/// # Example
539///
540/// ```
541/// use tabled::builder::Builder;
542///
543/// let table = Builder::default()
544/// .index()
545/// .build();
546/// ```
547#[derive(Debug, Clone)]
548pub struct IndexBuilder<'a> {
549 /// Index is an index data.
550 /// It's always set.
551 index: Vec<CellInfo<'a>>,
552 /// Name of an index
553 name: Option<CellInfo<'a>>,
554 /// A flag which checks if we need to actually use index.
555 ///
556 /// It might happen when it's only necessary to [Self::transpose] table.
557 print_index: bool,
558 /// A flag which checks if table was transposed.
559 transposed: bool,
560 /// Original builder instance.
561 b: Builder<'a>,
562}
563
564impl<'a> IndexBuilder<'a> {
565 /// Creates a new [`IndexBuilder`] instance.
566 ///
567 /// It creates a default index a range from 0 to N. (N - count rows)
568 /// It also sets a default columns to the range 0 .. N (N - count columns).
569 ///
570 /// # Example
571 ///
572 /// ```
573 /// use tabled::builder::Builder;
574 ///
575 /// let mut builder = Builder::default();
576 /// builder.set_columns(["i", "col-1", "col-2"]);
577 /// builder.add_record(["0", "value-1", "value-2"]);
578 ///
579 /// let table = builder.index().build();
580 ///
581 /// assert_eq!(
582 /// table.to_string(),
583 /// "+---+---+---------+---------+\n\
584 /// | | i | col-1 | col-2 |\n\
585 /// +---+---+---------+---------+\n\
586 /// | 0 | 0 | value-1 | value-2 |\n\
587 /// +---+---+---------+---------+"
588 /// )
589 /// ```
590 fn new(mut b: Builder<'a>) -> Self {
591 let index = build_range_index(b.records.len());
592
593 if b.columns.is_none() {
594 b.columns = Some(build_range_index(b.size));
595 }
596
597 Self {
598 index,
599 name: None,
600 print_index: true,
601 transposed: false,
602 b,
603 }
604 }
605
606 /// No flag makes builder to not use an index.
607 ///
608 /// It may be useful when only [`Self::transpose`] need to be used.
609 ///
610 /// ```
611 /// use tabled::builder::Builder;
612 ///
613 /// let mut builder = Builder::default();
614 /// builder.set_columns(["i", "col-1", "col-2"]);
615 /// builder.add_record(["0", "value-1", "value-2"]);
616 /// builder.add_record(["2", "value-3", "value-4"]);
617 ///
618 /// let mut builder = builder.index();
619 /// builder.hide_index();
620 ///
621 /// let table = builder.build();
622 ///
623 /// assert_eq!(
624 /// table.to_string(),
625 /// "+---+---------+---------+\n\
626 /// | i | col-1 | col-2 |\n\
627 /// +---+---------+---------+\n\
628 /// | 0 | value-1 | value-2 |\n\
629 /// +---+---------+---------+\n\
630 /// | 2 | value-3 | value-4 |\n\
631 /// +---+---------+---------+"
632 /// )
633 /// ```
634 pub fn hide_index(&mut self) -> &mut Self {
635 self.print_index = false;
636 self
637 }
638
639 /// Set an index name.
640 ///
641 /// When [`None`] the name won't be used.
642 pub fn set_name(&mut self, name: Option<String>) -> &mut Self {
643 self.name = name.map(|s| {
644 let ctrl = CfgWidthFunction::new(4);
645 CellInfo::new(s, ctrl)
646 });
647 self
648 }
649
650 /// Sets a index to the chosen column.
651 ///
652 /// Also sets a name of the index to the column name.
653 ///
654 /// # Example
655 ///
656 /// ```
657 /// use tabled::builder::Builder;
658 ///
659 /// let mut builder = Builder::default();
660 /// builder.set_columns(["i", "column1", "column2"]);
661 /// builder.add_record(["0", "value1", "value2"]);
662 ///
663 /// let mut builder = builder.index();
664 /// builder.set_index(1);
665 ///
666 /// let table = builder.build();
667 ///
668 /// assert_eq!(
669 /// table.to_string(),
670 /// "+---------+---+---------+\n\
671 /// | | i | column2 |\n\
672 /// +---------+---+---------+\n\
673 /// | column1 | | |\n\
674 /// +---------+---+---------+\n\
675 /// | value1 | 0 | value2 |\n\
676 /// +---------+---+---------+"
677 /// )
678 /// ```
679 pub fn set_index(&mut self, column: usize) -> &mut Self {
680 if self.b.columns.is_none() {
681 return self;
682 }
683
684 if column >= self.b.size {
685 return self;
686 }
687
688 let name = self
689 .b
690 .columns
691 .as_mut()
692 .map(|v| remove_or_default(v, column))
693 .unwrap_or_default();
694
695 self.name = Some(name);
696
697 self.index = get_column(&mut self.b.records, column);
698
699 self.b.size -= 1;
700
701 self
702 }
703
704 /// Transpose index and columns.
705 ///
706 /// # Example
707 ///
708 /// ```
709 /// use tabled::builder::Builder;
710 ///
711 /// let mut builder = Builder::default();
712 /// builder.set_columns(["i", "column-1", "column-2", "column-3"]);
713 /// builder.add_record(["0", "value-1", "value-2", "value-3"]);
714 /// builder.add_record(["1", "value-4", "value-5", "value-6"]);
715 /// builder.add_record(["2", "value-7", "value-8", "value-9"]);
716 ///
717 /// let mut builder = builder.index();
718 /// builder.set_index(1).transpose();
719 ///
720 /// let table = builder.build();
721 ///
722 /// assert_eq!(
723 /// table.to_string(),
724 /// "+----------+---------+---------+---------+\n\
725 /// | column-1 | value-1 | value-4 | value-7 |\n\
726 /// +----------+---------+---------+---------+\n\
727 /// | i | 0 | 1 | 2 |\n\
728 /// +----------+---------+---------+---------+\n\
729 /// | column-2 | value-2 | value-5 | value-8 |\n\
730 /// +----------+---------+---------+---------+\n\
731 /// | column-3 | value-3 | value-6 | value-9 |\n\
732 /// +----------+---------+---------+---------+"
733 /// )
734 /// ```
735 pub fn transpose(&mut self) -> &mut Self {
736 let columns = self.b.columns.take().unwrap_or_default();
737
738 let index = std::mem::replace(&mut self.index, columns);
739 self.b.columns = Some(index);
740
741 let new_count_columns = self.b.records.len();
742 make_rows_columns(&mut self.b.records, self.b.size);
743 self.b.size = new_count_columns;
744
745 self.transposed = !self.transposed;
746
747 self
748 }
749
750 /// Builds a table.
751 pub fn build(self) -> Table<VecRecords<CellInfo<'a>>> {
752 Builder::from(self).build()
753 }
754}
755
756impl<'a> From<IndexBuilder<'a>> for Builder<'a> {
757 fn from(index_builder: IndexBuilder<'a>) -> Self {
758 let mut b = build_index(index_builder);
759
760 // fixme: we don't update builder size internally
761 b.fix_rows();
762 b.different_column_sizes_used = false;
763
764 b
765 }
766}
767
768/// A builder which wraps [`Records`] and builds [`Table`] out of it.
769///
770/// [`Records`]: papergrid::records::Records
771#[derive(Debug, Clone)]
772pub struct CustomRecords<R> {
773 records: R,
774 has_header: bool,
775}
776
777impl<R> CustomRecords<R> {
778 fn new(records: R) -> Self {
779 Self {
780 records,
781 has_header: false,
782 }
783 }
784
785 /// Set a flag that custom records has a columns row.
786 pub fn with_header(&mut self) {
787 self.has_header = true;
788 }
789}
790
791impl<R> CustomRecords<R>
792where
793 R: Records,
794{
795 /// Builds a [`Table`] from [`Records`].
796 ///
797 /// [`Records`]: papergrid::records::Records
798 pub fn build(self) -> Table<R> {
799 build_table(self.records, self.has_header)
800 }
801}
802
803fn make_rows_columns(v: &mut Vec<Vec<CellInfo<'_>>>, count_columns: usize) {
804 let mut columns = Vec::with_capacity(count_columns);
805 for _ in 0..count_columns {
806 let column = get_column(v, 0);
807 columns.push(column);
808 }
809
810 v.clear();
811
812 for column in columns {
813 v.push(column);
814 }
815}
816
817fn build_index(mut b: IndexBuilder<'_>) -> Builder<'_> {
818 if b.index.is_empty() {
819 return b.b;
820 }
821
822 let records = &mut b.b.records;
823
824 // it's guaranted to be set
825 let columns = b.b.columns.take().unwrap();
826
827 records.insert(0, columns);
828
829 // add index column
830 if b.print_index {
831 b.b.size += 1;
832 b.index.insert(0, CellInfo::default());
833 insert_column(records, b.index, 0);
834 }
835
836 if let Some(name) = b.name {
837 if b.transposed && b.print_index {
838 records[0][0] = name;
839 } else {
840 records.insert(1, vec![name]);
841 }
842 }
843
844 b.b
845}
846
847fn insert_column<T: Default>(v: &mut [Vec<T>], mut column: Vec<T>, col: usize) {
848 for row in v.iter_mut() {
849 let value = remove_or_default(&mut column, col);
850 row.insert(col, value);
851 }
852}
853
854fn get_column<'a>(v: &mut [Vec<CellInfo<'a>>], col: usize) -> Vec<CellInfo<'a>> {
855 let mut column = Vec::with_capacity(v.len());
856 for row in v.iter_mut() {
857 let value = remove_or_default(row, col);
858 column.push(value);
859 }
860
861 column
862}
863
864fn remove_or_default<T: Default>(v: &mut Vec<T>, i: usize) -> T {
865 if v.len() > i {
866 v.remove(i)
867 } else {
868 T::default()
869 }
870}
871
872fn build_range_index(n: usize) -> Vec<CellInfo<'static>> {
873 let ctrl = CfgWidthFunction::new(4);
874 (0..n)
875 .map(|i| CellInfo::new(i.to_string(), &ctrl))
876 .collect()
877}
878
879fn create_row<'a, R, T, W>(row: R, size: usize, ctrl: &W) -> Vec<CellInfo<'a>>
880where
881 R: IntoIterator<Item = T>,
882 T: Into<Cow<'a, str>>,
883 W: WidthFunc,
884{
885 let mut list = Vec::with_capacity(size);
886 for text in row {
887 list.push(CellInfo::new(text, ctrl))
888 }
889
890 list
891}
892
893fn create_row_exact<'a, R, T, W>(list: &mut [CellInfo<'a>], row: R, ctrl: &W)
894where
895 R: IntoIterator<Item = T>,
896 T: Into<Cow<'a, str>>,
897 W: WidthFunc,
898{
899 for (text, cell) in row.into_iter().zip(list.iter_mut()) {
900 CellMut::set(cell, text, ctrl);
901 }
902}
903
904/// Building [`Table`] from ordinary data.
905fn build_table<R>(records: R, with_header: bool) -> Table<R>
906where
907 R: Records,
908{
909 let mut table = Table::from(records);
910 table.with(Style::ascii());
911
912 configure_grid(table.get_config_mut());
913 table.set_header_flag(with_header);
914
915 table
916}
917
918/// Building [`Grid`] from ordinary data.
919fn build_grid<'a>(
920 mut records: Vec<Vec<CellInfo<'a>>>,
921 columns: Option<Vec<CellInfo<'a>>>,
922 count_columns: usize,
923) -> VecRecords<CellInfo<'a>> {
924 if let Some(columns) = columns {
925 records.insert(0, columns);
926 }
927
928 VecRecords::with_hint(records, count_columns)
929}
930
931fn configure_grid(cfg: &mut GridConfig) {
932 cfg.set_tab_width(4);
933 cfg.set_padding(
934 Entity::Global,
935 Padding {
936 left: Indent::spaced(1),
937 right: Indent::spaced(1),
938 top: Indent::default(),
939 bottom: Indent::default(),
940 },
941 );
942 cfg.set_alignment_horizontal(Entity::Global, AlignmentHorizontal::Left);
943 cfg.set_formatting(
944 Entity::Global,
945 Formatting {
946 horizontal_trim: false,
947 allow_lines_alignement: false,
948 vertical_trim: false,
949 },
950 );
951}
952
953fn append_vec<'a>(v: &mut Vec<CellInfo<'a>>, n: usize, value: &CellInfo<'a>) {
954 v.extend((0..n).map(|_| value.clone()));
955}