tabled/settings/duplicate/mod.rs
1//! This module contains an [`Dup`] setting the [`Table`].
2//!
3//! # Example
4//!
5//! ```
6//! # use tabled::{Table, settings::{Dup, object::{Columns, Rows}}};
7//! # let data: Vec<&'static str> = Vec::new();
8//! let mut table = Table::new(&data);
9//! table.with(Dup::new(Rows::first(), Columns::first()));
10//! ```
11//!
12//! [`Table`]: crate::Table
13
14use crate::{
15 grid::config::Position,
16 grid::records::{ExactRecords, PeekableRecords, Records, RecordsMut},
17 settings::{object::Object, TableOption},
18};
19
20/// [`Dup`] duplicates a given set of cells into another set of ones [`Table`].
21///
22/// # Example
23///
24/// ```
25/// use tabled::{Table, settings::{object::Rows, Dup}};
26///
27/// let data = [
28/// ["1", "2", "3"],
29/// ["Some\nMulti\nLine\nText", "and a line", "here"],
30/// ["4", "5", "6"],
31/// ];
32///
33/// let mut table = Table::new(&data);
34/// table.with(Dup::new(Rows::one(1), Rows::one(2)));
35///
36/// assert_eq!(
37/// table.to_string(),
38/// "+-------+------------+------+\n\
39/// | 0 | 1 | 2 |\n\
40/// +-------+------------+------+\n\
41/// | Some | and a line | here |\n\
42/// | Multi | | |\n\
43/// | Line | | |\n\
44/// | Text | | |\n\
45/// +-------+------------+------+\n\
46/// | Some | and a line | here |\n\
47/// | Multi | | |\n\
48/// | Line | | |\n\
49/// | Text | | |\n\
50/// +-------+------------+------+\n\
51/// | 4 | 5 | 6 |\n\
52/// +-------+------------+------+",
53/// )
54/// ```
55///
56/// [`Table`]: crate::Table
57#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
58pub struct Dup<Dst, Src> {
59 src: Src,
60 dst: Dst,
61}
62
63impl<Dst, Src> Dup<Dst, Src> {
64 /// New creates a new [`Dup`] modifier.
65 ///
66 /// # Example
67 ///
68 /// ```
69 /// # use tabled::{Table, settings::{Dup, object::{Columns, Rows}}};
70 /// # let data: Vec<&'static str> = Vec::new();
71 /// let mut table = Table::new(&data);
72 /// table.with(Dup::new(Rows::first(), Columns::last()));
73 /// ```
74 pub fn new(dst: Dst, src: Src) -> Self {
75 Self { src, dst }
76 }
77}
78
79impl<Dst, Src, R, D, C> TableOption<R, C, D> for Dup<Dst, Src>
80where
81 Dst: Object<R>,
82 Src: Object<R>,
83 R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
84{
85 fn change(self, records: &mut R, _: &mut C, _: &mut D) {
86 let input = collect_input(records, self.src);
87 set_cells(records, &input, self.dst);
88 }
89}
90
91fn collect_input<R, O>(records: &mut R, src: O) -> Vec<String>
92where
93 O: Object<R>,
94 R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
95{
96 let count_rows = records.count_rows();
97 let count_columns = records.count_columns();
98
99 let mut input = Vec::new();
100 for entity in src.cells(records) {
101 for pos in entity.iter(count_rows, count_columns) {
102 if !is_valid_cell(pos, count_rows, count_columns) {
103 continue;
104 }
105
106 let text = records.get_text(pos).to_owned();
107 input.push(text);
108 }
109 }
110
111 input
112}
113
114fn set_cells<R, O>(records: &mut R, src: &[String], dst: O)
115where
116 O: Object<R>,
117 R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
118{
119 if src.is_empty() {
120 return;
121 }
122
123 let count_rows = records.count_rows();
124 let count_columns = records.count_columns();
125
126 for entity in dst.cells(records) {
127 let mut source = src.iter().cycle();
128 for pos in entity.iter(count_rows, count_columns) {
129 if !is_valid_cell(pos, count_rows, count_columns) {
130 continue;
131 }
132
133 let text = source.next().unwrap().clone();
134 records.set(pos, text);
135 }
136 }
137}
138
139fn is_valid_cell(pos: Position, count_rows: usize, count_columns: usize) -> bool {
140 if pos.row > count_rows {
141 return false;
142 }
143
144 if pos.col > count_columns {
145 return false;
146 }
147
148 true
149}