Coverage Report

Created: 2026-03-14 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tabled-0.20.0/src/tables/table.rs
Line
Count
Source
1
//! This module contains a main table representation [`Table`].
2
3
use core::ops::DerefMut;
4
use std::{borrow::Cow, fmt, iter::FromIterator};
5
6
use crate::{
7
    builder::Builder,
8
    grid::{
9
        colors::NoColors,
10
        config::{
11
            AlignmentHorizontal, ColorMap, ColoredConfig, CompactConfig, Entity, Indent, Sides,
12
            SpannedConfig,
13
        },
14
        dimension::{CompleteDimension, Dimension, Estimate, PeekableGridDimension},
15
        records::{
16
            vec_records::{Text, VecRecords},
17
            ExactRecords, Records,
18
        },
19
        PeekableGrid,
20
    },
21
    settings::{object::Object, CellOption, Style, TableOption},
22
    Tabled,
23
};
24
25
/// The structure provides an interface for building a table for types that implements [`Tabled`].
26
///
27
/// To build a string representation of a table you must use a [`std::fmt::Display`].
28
/// Or simply call `.to_string()` method.
29
///
30
/// The default table [`Style`] is [`Style::ascii`],
31
/// with a single left and right [`Padding`].
32
///
33
/// ## Example
34
///
35
/// ### Basic usage
36
///
37
/// ```rust,no_run
38
/// use tabled::Table;
39
///
40
/// let table = Table::new(&["Year", "2021"]);
41
/// ```
42
///
43
/// ### With settings
44
///
45
/// ```rust,no_run
46
/// use tabled::{Table, settings::{Style, Alignment}};
47
///
48
/// let data = vec!["Hello", "2021"];
49
/// let mut table = Table::new(&data);
50
/// table
51
///     .with(Style::psql())
52
///     .with(Alignment::left());
53
/// ```
54
///
55
/// ### With a [`Tabled`] trait.
56
///
57
/// ```rust,no_run
58
/// use tabled::{Table, Tabled};
59
///
60
/// #[derive(Tabled)]
61
/// struct Character {
62
///     good: f32,
63
///     bad: f32,
64
///     encouraging: f32,
65
///     destructive: f32,
66
/// }
67
///
68
/// #[derive(Tabled)]
69
/// struct Person<'a>(
70
///     #[tabled(rename = "name")] &'a str,
71
///     #[tabled(inline)] Character,
72
/// );
73
///
74
/// let data = vec![
75
///     Person("007", Character { good: 0.8, bad: 0.2, encouraging: 0.8, destructive: 0.1}),
76
///     Person("001", Character { good: 0.2, bad: 0.5, encouraging: 0.2, destructive: 0.1}),
77
///     Person("006", Character { good: 0.4, bad: 0.1, encouraging: 0.5, destructive: 0.8}),
78
/// ];
79
///
80
/// let table = Table::new(&data);
81
/// ```
82
///
83
/// [`Padding`]: crate::settings::Padding
84
/// [`Style`]: crate::settings::Style
85
/// [`Style::ascii`]: crate::settings::Style::ascii
86
#[derive(Debug, Clone, PartialEq, Eq)]
87
pub struct Table {
88
    records: VecRecords<Text<String>>,
89
    config: ColoredConfig,
90
    dimension: CompleteDimension,
91
}
92
93
impl Table {
94
    /// Creates a Table instance, from a list of [`Tabled`] values.
95
    ///
96
    /// If you use a reference iterator you'd better use [`FromIterator`] instead.
97
    /// As it has a different lifetime constraints and make less copies therefore.
98
    ///
99
    /// # Examples
100
    ///
101
    /// ```
102
    /// use tabled::{Table, Tabled, assert::assert_table};
103
    ///
104
    /// #[derive(Tabled)]
105
    /// struct Relationship {
106
    ///     love: bool
107
    /// }
108
    ///
109
    /// let list = vec![
110
    ///     Relationship { love: true },
111
    ///     Relationship { love: false },
112
    /// ];
113
    ///
114
    /// let table = Table::new(list);
115
    ///
116
    /// assert_table!(
117
    ///     table,
118
    ///     "+-------+"
119
    ///     "| love  |"
120
    ///     "+-------+"
121
    ///     "| true  |"
122
    ///     "+-------+"
123
    ///     "| false |"
124
    ///     "+-------+"
125
    /// );
126
    /// ```
127
    ///
128
    /// ## Don't hesitate to use iterators.
129
    ///
130
    /// ```
131
    /// use tabled::{Table, Tabled, assert::assert_table};
132
    ///
133
    /// #[derive(Tabled)]
134
    /// struct Relationship {
135
    ///     person: String,
136
    ///     love: bool
137
    /// }
138
    ///
139
    /// let list = vec![
140
    ///     Relationship { person: String::from("Clara"), love: true },
141
    ///     Relationship { person: String::from("Greg"), love: false },
142
    /// ];
143
    ///
144
    /// // Maybe don't love but don't hate :)
145
    /// let iter = list.into_iter()
146
    ///     .map(|mut rel| {
147
    ///         if !rel.love {
148
    ///             rel.love = true;
149
    ///         }
150
    ///
151
    ///         rel
152
    ///     });
153
    ///
154
    /// let table = Table::new(iter);
155
    ///
156
    /// assert_table!(
157
    ///     table,
158
    ///     "+--------+------+"
159
    ///     "| person | love |"
160
    ///     "+--------+------+"
161
    ///     "| Clara  | true |"
162
    ///     "+--------+------+"
163
    ///     "| Greg   | true |"
164
    ///     "+--------+------+"
165
    /// );
166
    /// ```
167
    ///
168
    /// ## Notice that you can pass tuples.
169
    ///
170
    /// ```
171
    /// use tabled::{Table, Tabled, assert::assert_table};
172
    ///
173
    /// #[derive(Tabled)]
174
    /// struct Relationship {
175
    ///     love: bool
176
    /// }
177
    ///
178
    /// let list = vec![
179
    ///     ("Kate", Relationship { love: true }),
180
    ///     ("", Relationship { love: false }),
181
    /// ];
182
    ///
183
    /// let table = Table::new(list);
184
    ///
185
    /// assert_table!(
186
    ///     table,
187
    ///     "+------+-------+"
188
    ///     "| &str | love  |"
189
    ///     "+------+-------+"
190
    ///     "| Kate | true  |"
191
    ///     "+------+-------+"
192
    ///     "|      | false |"
193
    ///     "+------+-------+"
194
    /// );
195
    /// ```
196
    ///
197
    /// ## As a different way to create a [`Table`], you can use [`Table::from_iter`].  
198
    ///
199
    /// ```
200
    /// use std::iter::FromIterator;
201
    /// use tabled::{Table, assert::assert_table};
202
    ///
203
    /// let list = vec![
204
    ///     vec!["Kate", "+", "+", "+", "-"],
205
    ///     vec!["", "-", "-", "-", "-"],
206
    /// ];
207
    ///
208
    /// let table = Table::from_iter(list);
209
    ///
210
    /// assert_table!(
211
    ///     table,
212
    ///     "+------+---+---+---+---+"
213
    ///     "| Kate | + | + | + | - |"
214
    ///     "+------+---+---+---+---+"
215
    ///     "|      | - | - | - | - |"
216
    ///     "+------+---+---+---+---+"
217
    /// );
218
    /// ```
219
0
    pub fn new<I, T>(iter: I) -> Self
220
0
    where
221
0
        I: IntoIterator<Item = T>,
222
0
        T: Tabled,
223
    {
224
0
        let mut header = Vec::with_capacity(T::LENGTH);
225
0
        for text in T::headers() {
226
0
            let text = text.into_owned();
227
0
            let cell = Text::new(text);
228
0
            header.push(cell);
229
0
        }
230
231
0
        let mut records = vec![header];
232
0
        for row in iter.into_iter() {
233
0
            let mut list = Vec::with_capacity(T::LENGTH);
234
0
            for text in row.fields().into_iter() {
235
0
                let text = text.into_owned();
236
0
                let cell = Text::new(text);
237
0
238
0
                list.push(cell);
239
0
            }
240
241
0
            records.push(list);
242
        }
243
244
0
        let records = VecRecords::new(records);
245
0
        let config = ColoredConfig::new(configure_grid());
246
0
        let dimension = CompleteDimension::default();
247
248
0
        Self {
249
0
            records,
250
0
            config,
251
0
            dimension,
252
0
        }
253
0
    }
Unexecuted instantiation: <tabled::tables::table::Table>::new::<alloc::vec::Vec<anise::naif::pretty_print::BpcRow>, anise::naif::pretty_print::BpcRow>
Unexecuted instantiation: <tabled::tables::table::Table>::new::<alloc::vec::Vec<anise::naif::pretty_print::SpkRow>, anise::naif::pretty_print::SpkRow>
Unexecuted instantiation: <tabled::tables::table::Table>::new::<alloc::vec::Vec<anise::almanac::planetary::PlanetaryRow>, anise::almanac::planetary::PlanetaryRow>
Unexecuted instantiation: <tabled::tables::table::Table>::new::<alloc::vec::Vec<anise::structure::spacecraft::SpacecraftRow>, anise::structure::spacecraft::SpacecraftRow>
Unexecuted instantiation: <tabled::tables::table::Table>::new::<alloc::vec::Vec<anise::structure::dataset::pretty_print::LocationRow>, anise::structure::dataset::pretty_print::LocationRow>
Unexecuted instantiation: <tabled::tables::table::Table>::new::<alloc::vec::Vec<anise::structure::dataset::pretty_print::EulerParamRow>, anise::structure::dataset::pretty_print::EulerParamRow>
Unexecuted instantiation: <tabled::tables::table::Table>::new::<_, _>
254
255
    /// Creates a Table instance, from a list of [`Tabled`] values.
256
    ///
257
    /// It's an optimized version of [`Table::new`].
258
    ///
259
    /// ```
260
    /// use tabled::{Table, Tabled, assert::assert_table};
261
    ///
262
    /// #[derive(Tabled)]
263
    /// struct Relationship {
264
    ///     person: String,
265
    ///     love: bool
266
    /// }
267
    ///
268
    /// let list = vec![
269
    ///     Relationship { person: String::from("Clara"), love: true },
270
    ///     Relationship { person: String::from("Greg"), love: false },
271
    /// ];
272
    ///
273
    /// let table = Table::with_capacity(&list, list.len());
274
    ///
275
    /// assert_table!(
276
    ///     table,
277
    ///     "+--------+-------+"
278
    ///     "| person | love  |"
279
    ///     "+--------+-------+"
280
    ///     "| Clara  | true  |"
281
    ///     "+--------+-------+"
282
    ///     "| Greg   | false |"
283
    ///     "+--------+-------+"
284
    /// );
285
    /// ```
286
0
    pub fn with_capacity<I, T>(iter: I, count_rows: usize) -> Self
287
0
    where
288
0
        I: IntoIterator<Item = T>,
289
0
        T: Tabled,
290
    {
291
0
        let mut header = Vec::with_capacity(T::LENGTH);
292
0
        for text in T::headers() {
293
0
            let text = text.into_owned();
294
0
            let cell = Text::new(text);
295
0
            header.push(cell);
296
0
        }
297
298
0
        let mut records = Vec::with_capacity(count_rows + 1);
299
0
        records.push(header);
300
301
0
        for row in iter.into_iter() {
302
0
            let mut list = Vec::with_capacity(T::LENGTH);
303
0
            for text in row.fields().into_iter() {
304
0
                let text = text.into_owned();
305
0
                let cell = Text::new(text);
306
0
307
0
                list.push(cell);
308
0
            }
309
310
0
            records.push(list);
311
        }
312
313
0
        let records = VecRecords::new(records);
314
0
        let config = ColoredConfig::new(configure_grid());
315
0
        let dimension = CompleteDimension::default();
316
317
0
        Self {
318
0
            records,
319
0
            config,
320
0
            dimension,
321
0
        }
322
0
    }
323
324
    /// Creates a Table instance, from a list of [`Tabled`] values.
325
    ///
326
    /// Compared to [`Table::new`] it does not use a "header" (first line).
327
    ///
328
    /// If you use a reference iterator you'd better use [`FromIterator`] instead.
329
    /// As it has a different lifetime constraints and make less copies therefore.
330
    ///
331
    /// # Examples
332
    ///
333
    /// ```
334
    /// use tabled::{Table, Tabled, assert::assert_table};
335
    ///
336
    /// #[derive(Tabled)]
337
    /// struct Relationship {
338
    ///     love: bool
339
    /// }
340
    ///
341
    /// let list = vec![
342
    ///     ("Kate", Relationship { love: true }),
343
    ///     ("", Relationship { love: false }),
344
    /// ];
345
    ///
346
    /// let table = Table::nohead(list);
347
    ///
348
    /// assert_table!(
349
    ///     table,
350
    ///     "+------+-------+"
351
    ///     "| Kate | true  |"
352
    ///     "+------+-------+"
353
    ///     "|      | false |"
354
    ///     "+------+-------+"
355
    /// );
356
    /// ```
357
0
    pub fn nohead<I, T>(iter: I) -> Self
358
0
    where
359
0
        I: IntoIterator<Item = T>,
360
0
        T: Tabled,
361
    {
362
0
        let mut records = vec![];
363
0
        for row in iter.into_iter() {
364
0
            let mut list = Vec::with_capacity(T::LENGTH);
365
0
            for text in row.fields().into_iter() {
366
0
                let text = text.into_owned();
367
0
                let cell = Text::new(text);
368
0
369
0
                list.push(cell);
370
0
            }
371
372
0
            records.push(list);
373
        }
374
375
0
        let records = VecRecords::new(records);
376
0
        let config = ColoredConfig::new(configure_grid());
377
0
        let dimension = CompleteDimension::default();
378
379
0
        Self {
380
0
            records,
381
0
            config,
382
0
            dimension,
383
0
        }
384
0
    }
385
386
    /// Creates a Key-Value [`Table`] instance, from a list of [`Tabled`] values.
387
    ///
388
    /// # Examples
389
    ///
390
    /// ```
391
    /// use tabled::{Table, Tabled, assert::assert_table};
392
    ///
393
    /// #[derive(Tabled)]
394
    /// #[tabled(rename_all = "PascalCase")]
395
    /// struct Swim {
396
    ///     event: String,
397
    ///     time: String,
398
    ///     #[tabled(rename = "Pool Length")]
399
    ///     pool: u8,
400
    /// }
401
    ///
402
    /// const POOL_25: u8 = 25;
403
    /// const POOL_50: u8 = 50;
404
    ///
405
    /// let list = vec![
406
    ///     Swim { event: String::from("Men 100 Freestyle"), time: String::from("47.77"), pool: POOL_25 },
407
    ///     Swim { event: String::from("Men 400 Freestyle"), time: String::from("03:59.16"), pool: POOL_25 },
408
    ///     Swim { event: String::from("Men 800 Freestyle"), time: String::from("08:06.70"), pool: POOL_25 },
409
    ///     Swim { event: String::from("Men 4x100 Medley Relay"), time: String::from("03:27.28"), pool: POOL_50 },
410
    /// ];
411
    ///
412
    /// let table = Table::kv(list);
413
    ///
414
    /// assert_table!(
415
    ///     table,
416
    ///     "+-------------+------------------------+"
417
    ///     "| Event       | Men 100 Freestyle      |"
418
    ///     "+-------------+------------------------+"
419
    ///     "| Time        | 47.77                  |"
420
    ///     "+-------------+------------------------+"
421
    ///     "| Pool Length | 25                     |"
422
    ///     "+-------------+------------------------+"
423
    ///     "| Event       | Men 400 Freestyle      |"
424
    ///     "+-------------+------------------------+"
425
    ///     "| Time        | 03:59.16               |"
426
    ///     "+-------------+------------------------+"
427
    ///     "| Pool Length | 25                     |"
428
    ///     "+-------------+------------------------+"
429
    ///     "| Event       | Men 800 Freestyle      |"
430
    ///     "+-------------+------------------------+"
431
    ///     "| Time        | 08:06.70               |"
432
    ///     "+-------------+------------------------+"
433
    ///     "| Pool Length | 25                     |"
434
    ///     "+-------------+------------------------+"
435
    ///     "| Event       | Men 4x100 Medley Relay |"
436
    ///     "+-------------+------------------------+"
437
    ///     "| Time        | 03:27.28               |"
438
    ///     "+-------------+------------------------+"
439
    ///     "| Pool Length | 50                     |"
440
    ///     "+-------------+------------------------+"
441
    /// );
442
    /// ```
443
    ///
444
    /// Next you'll find a more complex example with a subtle style.
445
    ///
446
    /// ```
447
    /// use tabled::{Table, Tabled, settings::Style};
448
    /// use tabled::settings::{style::HorizontalLine, Theme};
449
    /// use tabled::assert::assert_table;
450
    ///
451
    /// #[derive(Tabled)]
452
    /// #[tabled(rename_all = "PascalCase")]
453
    /// struct Swim {
454
    ///     event: String,
455
    ///     time: String,
456
    ///     #[tabled(rename = "Pool Length")]
457
    ///     pool: u8,
458
    /// }
459
    ///
460
    /// const POOL_25: u8 = 25;
461
    /// const POOL_50: u8 = 50;
462
    ///
463
    /// let list = vec![
464
    ///     Swim { event: String::from("Men 100 Freestyle"), time: String::from("47.77"), pool: POOL_25 },
465
    ///     Swim { event: String::from("Men 400 Freestyle"), time: String::from("03:59.16"), pool: POOL_25 },
466
    ///     Swim { event: String::from("Men 800 Freestyle"), time: String::from("08:06.70"), pool: POOL_25 },
467
    ///     Swim { event: String::from("Men 4x100 Medley Relay"), time: String::from("03:27.28"), pool: POOL_50 },
468
    /// ];
469
    ///
470
    /// let mut table = Table::kv(list);
471
    ///
472
    /// let mut style = Theme::from_style(Style::rounded().remove_horizontals());
473
    /// for entry in 1 .. table.count_rows() / Swim::LENGTH {
474
    ///     style.insert_horizontal_line(entry * Swim::LENGTH, HorizontalLine::inherit(Style::modern()));
475
    /// }
476
    ///
477
    /// table.with(style);
478
    ///
479
    /// assert_table!(
480
    ///     table,
481
    ///     "╭─────────────┬────────────────────────╮"
482
    ///     "│ Event       │ Men 100 Freestyle      │"
483
    ///     "│ Time        │ 47.77                  │"
484
    ///     "│ Pool Length │ 25                     │"
485
    ///     "├─────────────┼────────────────────────┤"
486
    ///     "│ Event       │ Men 400 Freestyle      │"
487
    ///     "│ Time        │ 03:59.16               │"
488
    ///     "│ Pool Length │ 25                     │"
489
    ///     "├─────────────┼────────────────────────┤"
490
    ///     "│ Event       │ Men 800 Freestyle      │"
491
    ///     "│ Time        │ 08:06.70               │"
492
    ///     "│ Pool Length │ 25                     │"
493
    ///     "├─────────────┼────────────────────────┤"
494
    ///     "│ Event       │ Men 4x100 Medley Relay │"
495
    ///     "│ Time        │ 03:27.28               │"
496
    ///     "│ Pool Length │ 50                     │"
497
    ///     "╰─────────────┴────────────────────────╯"
498
    /// );
499
    /// ```
500
0
    pub fn kv<I, T>(iter: I) -> Self
501
0
    where
502
0
        I: IntoIterator<Item = T>,
503
0
        T: Tabled,
504
    {
505
0
        let headers = T::headers();
506
507
0
        let mut records = Vec::new();
508
0
        for row in iter.into_iter() {
509
0
            for (text, name) in row.fields().into_iter().zip(headers.iter()) {
510
0
                let key = Text::new(name.clone().into_owned());
511
0
                let value = Text::new(text.into_owned());
512
0
513
0
                records.push(vec![key, value]);
514
0
            }
515
        }
516
517
0
        let records = VecRecords::new(records);
518
0
        let config = ColoredConfig::new(configure_grid());
519
0
        let dimension = CompleteDimension::default();
520
521
0
        Self {
522
0
            records,
523
0
            config,
524
0
            dimension,
525
0
        }
526
0
    }
527
528
    /// Creates a builder from a data set given.
529
    ///
530
    /// # Example
531
    ///
532
    #[cfg_attr(feature = "derive", doc = "```")]
533
    #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
534
    /// use tabled::{
535
    ///     Table, Tabled,
536
    ///     settings::{object::Segment, Modify, Alignment}
537
    /// };
538
    ///
539
    /// #[derive(Tabled)]
540
    /// struct User {
541
    ///     name: &'static str,
542
    ///     #[tabled(inline("device::"))]
543
    ///     device: Device,
544
    /// }
545
    ///
546
    /// #[derive(Tabled)]
547
    /// enum Device {
548
    ///     PC,
549
    ///     Mobile
550
    /// }
551
    ///
552
    /// let data = vec![
553
    ///     User { name: "Vlad", device: Device::Mobile },
554
    ///     User { name: "Dimitry", device: Device::PC },
555
    ///     User { name: "John", device: Device::PC },
556
    /// ];
557
    ///
558
    /// let mut table = Table::builder(data)
559
    ///     .index()
560
    ///     .column(0)
561
    ///     .transpose()
562
    ///     .build()
563
    ///     .modify(Segment::new(1.., 1..), Alignment::center())
564
    ///     .to_string();
565
    ///
566
    /// assert_eq!(
567
    ///     table,
568
    ///     "+----------------+------+---------+------+\n\
569
    ///      | name           | Vlad | Dimitry | John |\n\
570
    ///      +----------------+------+---------+------+\n\
571
    ///      | device::PC     |      |    +    |  +   |\n\
572
    ///      +----------------+------+---------+------+\n\
573
    ///      | device::Mobile |  +   |         |      |\n\
574
    ///      +----------------+------+---------+------+"
575
    /// )
576
    /// ```
577
0
    pub fn builder<I, T>(iter: I) -> Builder
578
0
    where
579
0
        T: Tabled,
580
0
        I: IntoIterator<Item = T>,
581
    {
582
0
        let mut builder = Builder::with_capacity(1, T::LENGTH);
583
0
        builder.push_record(T::headers());
584
585
0
        for row in iter {
586
0
            builder.push_record(row.fields().into_iter());
587
0
        }
588
589
0
        builder
590
0
    }
591
592
    /// It's a generic function which applies options to the [`Table`].
593
    ///
594
    /// It applies settings immediately.
595
    ///
596
    /// ```
597
    /// use tabled::{Table, settings::Style};
598
    /// use tabled::assert::assert_table;
599
    ///
600
    /// let data = vec![
601
    ///     ("number", "name"),
602
    ///     ("285-324-7322", "Rosalia"),
603
    ///     ("564.549.6468", "Mary"),
604
    /// ];
605
    ///
606
    /// let mut table = Table::new(data);
607
    /// table.with(Style::markdown());
608
    ///
609
    /// assert_table!(
610
    ///     table,
611
    ///     "| &str         | &str    |"
612
    ///     "|--------------|---------|"
613
    ///     "| number       | name    |"
614
    ///     "| 285-324-7322 | Rosalia |"
615
    ///     "| 564.549.6468 | Mary    |"
616
    /// );
617
    /// ```
618
0
    pub fn with<O>(&mut self, option: O) -> &mut Self
619
0
    where
620
0
        O: TableOption<VecRecords<Text<String>>, ColoredConfig, CompleteDimension>,
621
    {
622
0
        let reastimation_hint = option.hint_change();
623
624
0
        option.change(&mut self.records, &mut self.config, &mut self.dimension);
625
0
        self.dimension.reastimate(reastimation_hint);
626
627
0
        self
628
0
    }
Unexecuted instantiation: <tabled::tables::table::Table>::with::<tabled::settings::style::builder::Style<tabled::settings::style::builder::On, tabled::settings::style::builder::On, tabled::settings::style::builder::On, tabled::settings::style::builder::On, tabled::settings::style::builder::On, tabled::settings::style::builder::On, 0, 0>>
Unexecuted instantiation: <tabled::tables::table::Table>::with::<tabled::settings::style::builder::Style<tabled::settings::style::builder::On, tabled::settings::style::builder::On, tabled::settings::style::builder::On, tabled::settings::style::builder::On, (), tabled::settings::style::builder::On, 1, 0>>
Unexecuted instantiation: <tabled::tables::table::Table>::with::<tabled::settings::style::builder::Style<(), (), (), (), (), (), 0, 0>>
Unexecuted instantiation: <tabled::tables::table::Table>::with::<tabled::settings::padding::Padding>
629
630
    /// It's a generic function which applies options to particular cells on the [`Table`].
631
    /// Target cells using [`Object`]s such as [`Cell`], [`Rows`], [`Location`] and more.
632
    ///
633
    /// It applies settings immediately.
634
    ///
635
    /// ```
636
    /// use tabled::{Table, settings::{object::Columns, Alignment}};
637
    /// use tabled::assert::assert_table;
638
    ///
639
    /// let data = vec![
640
    ///     ("number", "name"),
641
    ///     ("285-324-7322", "Rosalia"),
642
    ///     ("564.549.6468", "Mary"),
643
    /// ];
644
    ///
645
    /// let mut table = Table::new(data);
646
    /// table.modify(Columns::first(), Alignment::right());
647
    /// table.modify(Columns::one(1), Alignment::center());
648
    ///
649
    /// assert_table!(
650
    ///     table,
651
    ///     "+--------------+---------+"
652
    ///     "|         &str |  &str   |"
653
    ///     "+--------------+---------+"
654
    ///     "|       number |  name   |"
655
    ///     "+--------------+---------+"
656
    ///     "| 285-324-7322 | Rosalia |"
657
    ///     "+--------------+---------+"
658
    ///     "| 564.549.6468 |  Mary   |"
659
    ///     "+--------------+---------+"
660
    /// );
661
    /// ```
662
    ///
663
    /// [`Cell`]: crate::settings::object::Cell
664
    /// [`Rows`]: crate::settings::object::Rows
665
    /// [`Location`]: crate::settings::location::Locator
666
0
    pub fn modify<T, O>(&mut self, target: T, option: O) -> &mut Self
667
0
    where
668
0
        T: Object<VecRecords<Text<String>>>,
669
0
        O: CellOption<VecRecords<Text<String>>, ColoredConfig> + Clone,
670
    {
671
0
        for entity in target.cells(&self.records) {
672
0
            let opt = option.clone();
673
0
            opt.change(&mut self.records, &mut self.config, entity);
674
0
        }
675
676
0
        let hint = option.hint_change();
677
0
        self.dimension.reastimate(hint);
678
679
0
        self
680
0
    }
681
682
    /// Returns a table shape (count rows, count columns).
683
0
    pub fn shape(&self) -> (usize, usize) {
684
0
        (self.count_rows(), self.count_columns())
685
0
    }
686
687
    /// Returns an amount of rows in the table.
688
0
    pub fn count_rows(&self) -> usize {
689
0
        self.records.count_rows()
690
0
    }
691
692
    /// Returns an amount of columns in the table.
693
0
    pub fn count_columns(&self) -> usize {
694
0
        self.records.count_columns()
695
0
    }
696
697
    /// Returns a table shape (count rows, count columns).
698
0
    pub fn is_empty(&self) -> bool {
699
0
        let (count_rows, count_cols) = self.shape();
700
0
        count_rows == 0 || count_cols == 0
701
0
    }
702
703
    /// Returns total widths of a table, including margin and horizontal lines.
704
0
    pub fn total_height(&self) -> usize {
705
0
        let mut dims = self.dimension.clone();
706
0
        dims.estimate(&self.records, self.config.as_ref());
707
708
0
        let total = (0..self.count_rows())
709
0
            .map(|row| dims.get_height(row))
710
0
            .sum::<usize>();
711
0
        let counth = self.config.count_horizontal(self.count_rows());
712
713
0
        let margin = self.config.get_margin();
714
715
0
        total + counth + margin.top.size + margin.bottom.size
716
0
    }
717
718
    /// Returns total widths of a table, including margin and vertical lines.
719
0
    pub fn total_width(&self) -> usize {
720
0
        let mut dims = self.dimension.clone();
721
0
        dims.estimate(&self.records, self.config.as_ref());
722
723
0
        let total = (0..self.count_columns())
724
0
            .map(|col| dims.get_width(col))
725
0
            .sum::<usize>();
726
0
        let countv = self.config.count_vertical(self.count_columns());
727
728
0
        let margin = self.config.get_margin();
729
730
0
        total + countv + margin.left.size + margin.right.size
731
0
    }
732
733
    /// Returns a table config.
734
0
    pub fn get_config(&self) -> &ColoredConfig {
735
0
        &self.config
736
0
    }
737
738
    /// Returns a table config.
739
0
    pub fn get_config_mut(&mut self) -> &mut ColoredConfig {
740
0
        &mut self.config
741
0
    }
742
743
    /// Returns a used records.
744
0
    pub fn get_records(&self) -> &VecRecords<Text<String>> {
745
0
        &self.records
746
0
    }
747
748
    /// Returns a used records.
749
0
    pub fn get_records_mut(&mut self) -> &mut VecRecords<Text<String>> {
750
0
        &mut self.records
751
0
    }
752
753
    /// Returns a dimension.
754
0
    pub fn get_dimension(&self) -> &CompleteDimension {
755
0
        &self.dimension
756
0
    }
757
758
    /// Returns a dimension.
759
0
    pub fn get_dimension_mut(&mut self) -> &mut CompleteDimension {
760
0
        &mut self.dimension
761
0
    }
762
}
763
764
impl Default for Table {
765
0
    fn default() -> Self {
766
0
        Self {
767
0
            records: VecRecords::default(),
768
0
            config: ColoredConfig::new(configure_grid()),
769
0
            dimension: CompleteDimension::default(),
770
0
        }
771
0
    }
772
}
773
774
impl fmt::Display for Table {
775
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776
0
        if self.is_empty() {
777
0
            return Ok(());
778
0
        }
779
780
0
        let config = use_format_configuration(f, self);
781
0
        let colors = self.config.get_colors();
782
783
0
        if !self.dimension.is_empty() {
784
0
            let mut dims = self.dimension.clone();
785
0
            dims.estimate(&self.records, config.as_ref());
786
787
0
            print_grid(f, &self.records, &config, &dims, colors)
788
        } else {
789
0
            let mut dims = PeekableGridDimension::default();
790
0
            dims.estimate(&self.records, &config);
791
792
0
            print_grid(f, &self.records, &config, &dims, colors)
793
        }
794
0
    }
795
}
796
797
impl<T> FromIterator<T> for Table
798
where
799
    T: IntoIterator,
800
    T::Item: Into<String>,
801
{
802
0
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
803
0
        Builder::from_iter(iter.into_iter().map(|i| i.into_iter().map(|s| s.into()))).build()
804
0
    }
805
}
806
807
impl From<Builder> for Table {
808
0
    fn from(builder: Builder) -> Self {
809
0
        let data = builder.into();
810
0
        let records = VecRecords::new(data);
811
0
        let config = ColoredConfig::new(configure_grid());
812
0
        let dimension = CompleteDimension::default();
813
814
0
        Self {
815
0
            records,
816
0
            config,
817
0
            dimension,
818
0
        }
819
0
    }
820
}
821
822
impl From<Table> for Builder {
823
0
    fn from(val: Table) -> Self {
824
0
        let data = val.records.into();
825
0
        Builder::from_vec(data)
826
0
    }
827
}
828
829
impl<R, D> TableOption<R, ColoredConfig, D> for CompactConfig {
830
0
    fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
831
0
        *cfg.deref_mut() = self.into();
832
0
    }
833
}
834
835
impl<R, D> TableOption<R, ColoredConfig, D> for ColoredConfig {
836
0
    fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
837
0
        *cfg = self;
838
0
    }
839
}
840
841
impl<R, D> TableOption<R, ColoredConfig, D> for SpannedConfig {
842
0
    fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
843
0
        *cfg.deref_mut() = self;
844
0
    }
845
}
846
847
impl<R, D> TableOption<R, ColoredConfig, D> for &SpannedConfig {
848
0
    fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
849
0
        *cfg.deref_mut() = self.clone();
850
0
    }
851
}
852
853
0
fn convert_fmt_alignment(alignment: fmt::Alignment) -> AlignmentHorizontal {
854
0
    match alignment {
855
0
        fmt::Alignment::Left => AlignmentHorizontal::Left,
856
0
        fmt::Alignment::Right => AlignmentHorizontal::Right,
857
0
        fmt::Alignment::Center => AlignmentHorizontal::Center,
858
    }
859
0
}
860
861
0
fn table_padding(alignment: fmt::Alignment, available: usize) -> (usize, usize) {
862
0
    match alignment {
863
0
        fmt::Alignment::Left => (available, 0),
864
0
        fmt::Alignment::Right => (0, available),
865
        fmt::Alignment::Center => {
866
0
            let left = available / 2;
867
0
            let right = available - left;
868
0
            (left, right)
869
        }
870
    }
871
0
}
872
873
0
fn configure_grid() -> SpannedConfig {
874
0
    let mut cfg = SpannedConfig::default();
875
0
    cfg.set_padding(
876
0
        Entity::Global,
877
0
        Sides::new(
878
0
            Indent::spaced(1),
879
0
            Indent::spaced(1),
880
0
            Indent::default(),
881
0
            Indent::default(),
882
        ),
883
    );
884
0
    cfg.set_alignment_horizontal(Entity::Global, AlignmentHorizontal::Left);
885
0
    cfg.set_line_alignment(Entity::Global, false);
886
0
    cfg.set_trim_horizontal(Entity::Global, false);
887
0
    cfg.set_trim_vertical(Entity::Global, false);
888
0
    cfg.set_borders(Style::ascii().get_borders());
889
890
0
    cfg
891
0
}
892
893
0
fn use_format_configuration<'a>(
894
0
    f: &mut fmt::Formatter<'_>,
895
0
    table: &'a Table,
896
0
) -> Cow<'a, SpannedConfig> {
897
0
    if f.align().is_some() || f.width().is_some() {
898
0
        let mut cfg = table.config.as_ref().clone();
899
900
0
        set_align_table(f, &mut cfg);
901
0
        set_width_table(f, &mut cfg, table);
902
903
0
        Cow::Owned(cfg)
904
    } else {
905
0
        Cow::Borrowed(table.config.as_ref())
906
    }
907
0
}
908
909
0
fn set_align_table(f: &fmt::Formatter<'_>, cfg: &mut SpannedConfig) {
910
0
    if let Some(alignment) = f.align() {
911
0
        let alignment = convert_fmt_alignment(alignment);
912
0
        cfg.set_alignment_horizontal(Entity::Global, alignment);
913
0
    }
914
0
}
915
916
0
fn set_width_table(f: &fmt::Formatter<'_>, cfg: &mut SpannedConfig, table: &Table) {
917
0
    if let Some(width) = f.width() {
918
0
        let total_width = table.total_width();
919
0
        if total_width >= width {
920
0
            return;
921
0
        }
922
923
0
        let mut fill = f.fill();
924
0
        if fill == char::default() {
925
0
            fill = ' ';
926
0
        }
927
928
0
        let available = width - total_width;
929
0
        let alignment = f.align().unwrap_or(fmt::Alignment::Left);
930
0
        let (left, right) = table_padding(alignment, available);
931
932
0
        let mut margin = cfg.get_margin();
933
0
        margin.left.size += left;
934
0
        margin.right.size += right;
935
936
0
        if (margin.left.size > 0 && margin.left.fill == char::default()) || fill != char::default()
937
0
        {
938
0
            margin.left.fill = fill;
939
0
        }
940
941
0
        if (margin.right.size > 0 && margin.right.fill == char::default())
942
0
            || fill != char::default()
943
0
        {
944
0
            margin.right.fill = fill;
945
0
        }
946
947
0
        cfg.set_margin(margin);
948
0
    }
949
0
}
950
951
0
fn print_grid<F: fmt::Write, D: Dimension>(
952
0
    f: &mut F,
953
0
    records: &VecRecords<Text<String>>,
954
0
    cfg: &SpannedConfig,
955
0
    dims: D,
956
0
    colors: &ColorMap,
957
0
) -> fmt::Result {
958
0
    if !colors.is_empty() {
959
0
        PeekableGrid::new(records, cfg, &dims, colors).build(f)
960
    } else {
961
0
        PeekableGrid::new(records, cfg, &dims, NoColors).build(f)
962
    }
963
0
}
Unexecuted instantiation: tabled::tables::table::print_grid::<core::fmt::Formatter, &papergrid::dimension::peekable::PeekableGridDimension>
Unexecuted instantiation: tabled::tables::table::print_grid::<core::fmt::Formatter, &tabled::grid::dimension::complete_dimension::CompleteDimension>