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