1use crate::Table;
2
3use super::Builder;
4
5/// [`IndexBuilder`] helps to add an index to the table.
6///
7/// Index is a column on the left of the table.
8///
9/// It also can be used to transpose the table.
10///
11/// Creates a new [`IndexBuilder`] instance.
12///
13/// It creates a default index a range from 0 to N. (N - count rows)
14/// It also sets a default columns to the range 0 .. N (N - count columns).
15///nfo<'a>
16/// # Example
17///
18/// ```
19/// use tabled::builder::Builder;
20///
21/// let mut builder = Builder::default();
22/// builder.set_header(["i", "col-1", "col-2"]);
23/// builder.push_record(["0", "value-1", "value-2"]);
24///
25/// let table = builder.index().build().to_string();
26///
27/// assert_eq!(
28/// table,
29/// "+---+---+---------+---------+\n\
30/// | | i | col-1 | col-2 |\n\
31/// +---+---+---------+---------+\n\
32/// | 0 | 0 | value-1 | value-2 |\n\
33/// +---+---+---------+---------+"
34/// )
35/// ```
36///
37/// # Example
38///
39/// ```
40/// use tabled::builder::Builder;
41///
42/// let table = Builder::default()
43/// .index()
44/// .build();
45/// ```
46#[derive(Debug, Clone)]
47pub struct IndexBuilder {
48 /// Index is an index data.
49 /// It's always set.
50 index: Vec<String>,
51 /// Name of an index
52 name: Option<String>,
53 /// A flag which checks if we need to actually use index.
54 ///
55 /// It might happen when it's only necessary to [`Self::transpose`] table.
56 print_index: bool,
57 /// A flag which checks if table was transposed.
58 transposed: bool,
59 /// Data originated in [`Builder`].
60 data: Vec<Vec<String>>,
61}
62
63impl IndexBuilder {
64 /// No flag makes builder to not use an index.
65 ///
66 /// It may be useful when only [`Self::transpose`] need to be used.
67 ///
68 /// ```
69 /// use tabled::builder::Builder;
70 ///
71 /// let mut builder = Builder::default();
72 /// builder.set_header(["i", "col-1", "col-2"]);
73 /// builder.push_record(["0", "value-1", "value-2"]);
74 /// builder.push_record(["2", "value-3", "value-4"]);
75 ///
76 /// let table = builder.index().hide().build().to_string();
77 ///
78 /// assert_eq!(
79 /// table,
80 /// "+---+---------+---------+\n\
81 /// | i | col-1 | col-2 |\n\
82 /// +---+---------+---------+\n\
83 /// | 0 | value-1 | value-2 |\n\
84 /// +---+---------+---------+\n\
85 /// | 2 | value-3 | value-4 |\n\
86 /// +---+---------+---------+"
87 /// )
88 /// ```
89 pub fn hide(mut self) -> Self {
90 self.print_index = false;
91 self
92 }
93
94 /// Set an index name.
95 ///
96 /// When [`None`] the name won't be used.
97 ///
98 /// # Example
99 ///
100 /// ```
101 /// use tabled::builder::Builder;
102 ///
103 /// let mut builder = Builder::default();
104 /// builder.set_header(["i", "column1", "column2"]);
105 /// builder.push_record(["0", "value1", "value2"]);
106 ///
107 /// let table = builder.index()
108 /// .column(1)
109 /// .name(Some(String::from("index")))
110 /// .build();
111 ///
112 /// assert_eq!(
113 /// table.to_string(),
114 /// "+--------+---+---------+\n\
115 /// | | i | column2 |\n\
116 /// +--------+---+---------+\n\
117 /// | index | | |\n\
118 /// +--------+---+---------+\n\
119 /// | value1 | 0 | value2 |\n\
120 /// +--------+---+---------+"
121 /// )
122 /// ```
123 pub fn name(mut self, name: Option<String>) -> Self {
124 self.name = name;
125 self
126 }
127
128 /// Sets a index to the chosen column.
129 ///
130 /// Also sets a name of the index to the column name.
131 ///
132 /// # Example
133 ///
134 /// ```
135 /// use tabled::builder::Builder;
136 ///
137 /// let mut builder = Builder::default();
138 /// builder.set_header(["i", "column1", "column2"]);
139 /// builder.push_record(["0", "value1", "value2"]);
140 ///
141 /// let table = builder.index().column(1).build();
142 ///
143 /// assert_eq!(
144 /// table.to_string(),
145 /// "+---------+---+---------+\n\
146 /// | | i | column2 |\n\
147 /// +---------+---+---------+\n\
148 /// | column1 | | |\n\
149 /// +---------+---+---------+\n\
150 /// | value1 | 0 | value2 |\n\
151 /// +---------+---+---------+"
152 /// )
153 /// ```
154 pub fn column(mut self, column: usize) -> Self {
155 if column >= matrix_count_columns(&self.data) {
156 return self;
157 }
158
159 self.index = get_column(&mut self.data, column);
160
161 let name = remove_or_default(&mut self.index, 0);
162 self.name = Some(name);
163
164 self
165 }
166
167 /// Transpose index and columns.
168 ///
169 /// # Example
170 ///
171 /// ```
172 /// use tabled::builder::Builder;
173 ///
174 /// let mut builder = Builder::default();
175 /// builder.set_header(["i", "column-1", "column-2", "column-3"]);
176 /// builder.push_record(["0", "value-1", "value-2", "value-3"]);
177 /// builder.push_record(["1", "value-4", "value-5", "value-6"]);
178 /// builder.push_record(["2", "value-7", "value-8", "value-9"]);
179 ///
180 /// let table = builder.index().column(1).transpose().build();
181 ///
182 /// assert_eq!(
183 /// table.to_string(),
184 /// "+----------+---------+---------+---------+\n\
185 /// | column-1 | value-1 | value-4 | value-7 |\n\
186 /// +----------+---------+---------+---------+\n\
187 /// | i | 0 | 1 | 2 |\n\
188 /// +----------+---------+---------+---------+\n\
189 /// | column-2 | value-2 | value-5 | value-8 |\n\
190 /// +----------+---------+---------+---------+\n\
191 /// | column-3 | value-3 | value-6 | value-9 |\n\
192 /// +----------+---------+---------+---------+"
193 /// )
194 /// ```
195 pub fn transpose(mut self) -> Self {
196 let columns = &mut self.data[0];
197 std::mem::swap(&mut self.index, columns);
198
199 let columns = self.data.remove(0);
200
201 make_rows_columns(&mut self.data);
202
203 self.data.insert(0, columns);
204
205 self.transposed = !self.transposed;
206
207 self
208 }
209
210 /// Builds a table.
211 pub fn build(self) -> Table {
212 let builder: Builder = self.into();
213 builder.build()
214 }
215}
216
217impl From<Builder> for IndexBuilder {
218 fn from(builder: Builder) -> Self {
219 let has_header: bool = builder.has_header();
220
221 let mut data: Vec<Vec<_>> = builder.into();
222
223 if !has_header {
224 let count_columns: usize = matrix_count_columns(&data);
225 data.insert(index:0, element:build_range_index(count_columns));
226 }
227
228 // we exclude first row which contains a header
229 let data_len: usize = data.len().saturating_sub(1);
230 let index: Vec = build_range_index(data_len);
231
232 Self {
233 index,
234 name: None,
235 print_index: true,
236 transposed: false,
237 data,
238 }
239 }
240}
241
242impl From<IndexBuilder> for Builder {
243 fn from(b: IndexBuilder) -> Self {
244 build_index(b)
245 }
246}
247
248fn build_index(mut b: IndexBuilder) -> Builder {
249 if b.index.is_empty() {
250 return Builder::default();
251 }
252
253 // add index column
254 if b.print_index {
255 b.index.insert(index:0, element:String::default());
256
257 insert_column(&mut b.data, column:b.index, col:0);
258 }
259
260 if let Some(name: String) = b.name {
261 if b.transposed && b.print_index {
262 b.data[0][0] = name;
263 } else {
264 b.data.insert(index:1, element:vec![name]);
265 }
266 }
267
268 Builder::from(b.data)
269}
270
271fn build_range_index(n: usize) -> Vec<String> {
272 (0..n).map(|i: usize| i.to_string()).collect()
273}
274
275fn remove_or_default<T: Default>(v: &mut Vec<T>, i: usize) -> T {
276 if v.len() > i {
277 v.remove(index:i)
278 } else {
279 T::default()
280 }
281}
282
283fn get_column<T: Default>(v: &mut [Vec<T>], col: usize) -> Vec<T> {
284 let mut column: Vec = Vec::with_capacity(v.len());
285 for row: &mut Vec in v.iter_mut() {
286 let value: T = remove_or_default(v:row, i:col);
287 column.push(value);
288 }
289
290 column
291}
292
293fn make_rows_columns<T: Default>(v: &mut Vec<Vec<T>>) {
294 let count_columns: usize = matrix_count_columns(v);
295
296 let mut columns: Vec> = Vec::with_capacity(count_columns);
297 for _ in 0..count_columns {
298 let column: Vec = get_column(v, col:0);
299 columns.push(column);
300 }
301
302 v.clear();
303
304 for column: Vec in columns {
305 v.push(column);
306 }
307}
308
309fn insert_column<T: Default>(v: &mut [Vec<T>], mut column: Vec<T>, col: usize) {
310 for row: &mut Vec in v.iter_mut() {
311 let value: T = remove_or_default(&mut column, i:col);
312 row.insert(index:col, element:value);
313 }
314}
315
316fn matrix_count_columns<T>(v: &[Vec<T>]) -> usize {
317 v.first().map_or(default:0, |row: &Vec| row.len())
318}
319