1pub trait Data {
3 fn at(&self, row: usize, cell: usize) -> String;
5
6 fn rows(&self) -> usize;
8
9 fn columns(&self) -> usize;
11}
12
13#[derive(Debug, Clone)]
15pub struct StringData {
16 rows: Vec<Vec<String>>,
17 columns: usize,
18}
19
20impl StringData {
21 pub fn new(rows: Vec<Vec<String>>) -> Self {
23 let columns = rows.iter().map(|row| row.len()).max().unwrap_or(0);
24 Self { rows, columns }
25 }
26
27 pub fn empty() -> Self {
29 Self {
30 rows: Vec::new(),
31 columns: 0,
32 }
33 }
34
35 pub fn append(&mut self, row: Vec<String>) {
37 self.columns = self.columns.max(row.len());
38 self.rows.push(row);
39 }
40
41 pub fn item(mut self, row: Vec<String>) -> Self {
43 self.append(row);
44 self
45 }
46}
47
48impl Data for StringData {
49 fn at(&self, row: usize, cell: usize) -> String {
50 if row >= self.rows.len() || cell >= self.rows[row].len() {
51 return String::new();
52 }
53 self.rows[row][cell].clone()
54 }
55
56 fn rows(&self) -> usize {
57 self.rows.len()
58 }
59
60 fn columns(&self) -> usize {
61 self.columns
62 }
63}
64
65pub struct Filter<D: Data> {
67 data: D,
68 filter: Option<Box<dyn Fn(usize) -> bool>>,
69}
70
71impl<D: Data> Filter<D> {
72 pub fn new(data: D) -> Self {
74 Self { data, filter: None }
75 }
76
77 pub fn filter<F>(mut self, f: F) -> Self
79 where
80 F: Fn(usize) -> bool + 'static,
81 {
82 self.filter = Some(Box::new(f));
83 self
84 }
85}
86
87impl<D: Data> Data for Filter<D> {
88 fn at(&self, row: usize, cell: usize) -> String {
89 if let Some(ref filter) = self.filter {
90 let mut j = 0;
91 for i in 0..self.data.rows() {
92 if filter(i) {
93 if j == row {
94 return self.data.at(i, cell);
95 }
96 j += 1;
97 }
98 }
99 String::new()
100 } else {
101 self.data.at(row, cell)
102 }
103 }
104
105 fn rows(&self) -> usize {
106 if let Some(ref filter) = self.filter {
107 let mut count = 0;
108 for i in 0..self.data.rows() {
109 if filter(i) {
110 count += 1;
111 }
112 }
113 count
114 } else {
115 self.data.rows()
116 }
117 }
118
119 fn columns(&self) -> usize {
120 self.data.columns()
121 }
122}
123
124pub fn data_to_matrix<D: Data + ?Sized>(data: &D) -> Vec<Vec<String>> {
126 let num_rows = data.rows();
127 let num_cols = data.columns();
128 let mut rows = Vec::with_capacity(num_rows);
129
130 for i in 0..num_rows {
131 let mut row = Vec::with_capacity(num_cols);
132 for j in 0..num_cols {
133 row.push(data.at(i, j));
134 }
135 rows.push(row);
136 }
137 rows
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_string_data_basic() {
146 let data = StringData::new(vec![
147 vec!["A".to_string(), "B".to_string()],
148 vec!["C".to_string(), "D".to_string(), "E".to_string()],
149 ]);
150
151 assert_eq!(data.rows(), 2);
152 assert_eq!(data.columns(), 3); assert_eq!(data.at(0, 0), "A");
154 assert_eq!(data.at(0, 1), "B");
155 assert_eq!(data.at(1, 2), "E");
156 assert_eq!(data.at(0, 2), ""); assert_eq!(data.at(2, 0), ""); }
159
160 #[test]
161 fn test_string_data_append() {
162 let mut data = StringData::empty();
163 assert_eq!(data.rows(), 0);
164 assert_eq!(data.columns(), 0);
165
166 data.append(vec!["A".to_string(), "B".to_string()]);
167 assert_eq!(data.rows(), 1);
168 assert_eq!(data.columns(), 2);
169
170 data.append(vec!["C".to_string()]);
171 assert_eq!(data.rows(), 2);
172 assert_eq!(data.columns(), 2); }
174
175 #[test]
176 fn test_string_data_builder() {
177 let data = StringData::empty()
178 .item(vec!["Name".to_string(), "Age".to_string()])
179 .item(vec!["Alice".to_string(), "30".to_string()])
180 .item(vec![
181 "Bob".to_string(),
182 "25".to_string(),
183 "Engineer".to_string(),
184 ]);
185
186 assert_eq!(data.rows(), 3);
187 assert_eq!(data.columns(), 3);
188 assert_eq!(data.at(1, 0), "Alice");
189 assert_eq!(data.at(2, 2), "Engineer");
190 }
191
192 #[test]
193 fn test_filter_basic() {
194 let data = StringData::new(vec![
195 vec!["A".to_string(), "1".to_string()],
196 vec!["B".to_string(), "2".to_string()],
197 vec!["C".to_string(), "3".to_string()],
198 vec!["D".to_string(), "4".to_string()],
199 ]);
200
201 let filtered = Filter::new(data).filter(|row| row.is_multiple_of(2));
203
204 assert_eq!(filtered.rows(), 2);
205 assert_eq!(filtered.columns(), 2);
206 assert_eq!(filtered.at(0, 0), "A"); assert_eq!(filtered.at(1, 0), "C"); assert_eq!(filtered.at(0, 1), "1");
209 assert_eq!(filtered.at(1, 1), "3");
210 }
211
212 #[test]
213 fn test_data_to_matrix() {
214 let data = StringData::new(vec![
215 vec!["A".to_string(), "B".to_string()],
216 vec!["C".to_string()],
217 ]);
218
219 let matrix = data_to_matrix(&data);
220 assert_eq!(matrix.len(), 2);
221 assert_eq!(matrix[0], vec!["A", "B"]);
222 assert_eq!(matrix[1], vec!["C", ""]); }
224}