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 | |
14 | use 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::single(1), Rows::single(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)] |
58 | pub struct Dup<Dst, Src> { |
59 | src: Src, |
60 | dst: Dst, |
61 | } |
62 | |
63 | impl<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 | |
79 | impl<Dst, Src, R, D, C> TableOption<R, C, D> for Dup<Dst, Src> |
80 | where |
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: Vec = collect_input(records, self.src); |
87 | set_cells(records, &input, self.dst); |
88 | } |
89 | } |
90 | |
91 | fn collect_input<R, O>(records: &mut R, src: O) -> Vec<String> |
92 | where |
93 | O: Object<R>, |
94 | R: Records + ExactRecords + PeekableRecords + RecordsMut<String>, |
95 | { |
96 | let count_rows: usize = records.count_rows(); |
97 | let count_columns: usize = records.count_columns(); |
98 | |
99 | let mut input: Vec = Vec::new(); |
100 | for entity in src.cells(records) { |
101 | for pos: (usize, usize) in entity.iter(count_rows, count_columns) { |
102 | if !is_valid_cell(pos, count_rows, count_columns) { |
103 | continue; |
104 | } |
105 | |
106 | let text: String = records.get_text(pos).to_owned(); |
107 | input.push(text); |
108 | } |
109 | } |
110 | |
111 | input |
112 | } |
113 | |
114 | fn set_cells<R, O>(records: &mut R, src: &[String], dst: O) |
115 | where |
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: usize = records.count_rows(); |
124 | let count_columns: usize = records.count_columns(); |
125 | |
126 | for entity in dst.cells(records) { |
127 | let mut source: Cycle> = src.iter().cycle(); |
128 | for pos: (usize, usize) in entity.iter(count_rows, count_columns) { |
129 | if !is_valid_cell(pos, count_rows, count_columns) { |
130 | continue; |
131 | } |
132 | |
133 | let text: String = source.next().unwrap().clone(); |
134 | records.set(pos, text); |
135 | } |
136 | } |
137 | } |
138 | |
139 | fn is_valid_cell((row: usize, col: usize): Position, count_rows: usize, count_columns: usize) -> bool { |
140 | if row > count_rows { |
141 | return false; |
142 | } |
143 | |
144 | if col > count_columns { |
145 | return false; |
146 | } |
147 | |
148 | true |
149 | } |
150 | |