rust_csv/
lib.rs

1use std::fmt;
2use std::fs::File;
3use std::io::{self, BufRead, BufReader, BufWriter, Write};
4use std::path::Path;
5
6const CSV_SEP: &str = ",";
7
8type CsvCell = String;
9type CsvHead = Vec<CsvCell>;
10type CsvRow = Vec<CsvCell>;
11
12/**
13 * CSV File
14 *
15 * CSV file manupulation for Rust Lang.
16 */
17#[derive(Debug, Default)]
18pub struct CsvFile {
19    heads: CsvHead,
20    rows: Vec<CsvRow>,
21}
22
23impl CsvFile {
24    /**
25     * New
26     *
27     * New Instance of CSV file.
28     */
29    pub fn new() -> Self {
30        Self::default()
31    }
32
33    /**
34     * Heads
35     *
36     * Get headers.
37     */
38    pub fn heads(&self) -> &CsvHead {
39        &self.heads
40    }
41
42    /**
43     * Head Pos
44     *
45     * Head position
46     */
47    pub fn head_pos(&self, name: &str) -> Option<usize> {
48        self.heads.iter().position(|head| head.eq(name))
49    }
50
51    /**
52     * Rows
53     *
54     * Get rows.
55     */
56    pub fn rows(&self) -> &Vec<CsvRow> {
57        &self.rows
58    }
59
60    /**
61     * Cols
62     *
63     * Get all the columns.
64     */
65    pub fn cols(&self, name: &str) -> Option<CsvRow> {
66        let index = self.head_pos(name)?;
67
68        let cols = self
69            .rows
70            .iter()
71            .map(|row| {
72                if let Some(data) = row.get(index) {
73                    data.to_string()
74                } else {
75                    "".to_string()
76                }
77            })
78            .collect::<Vec<String>>();
79
80        Some(cols)
81    }
82
83    /**
84     * Row
85     *
86     * Get the row.
87     */
88    pub fn row(&self, position: usize) -> Option<&CsvRow> {
89        self.rows.get(position)
90    }
91
92    /**
93     * Cell
94     *
95     * Get the cell.
96     */
97    pub fn cell(&self, row: usize, col: usize) -> Option<&CsvCell> {
98        let row_data = self.rows.get(row)?;
99
100        row_data.get(col)
101    }
102}
103
104impl CsvFile {
105    /**
106     * Push Head
107     *
108     * Push new head.
109     */
110    pub fn push_head(&mut self, name: &str) {
111        self.heads.push(name.to_string());
112    }
113
114    /**
115     * Set Head
116     *
117     * Set head to target position.
118     */
119    pub fn set_head(&mut self, position: usize, name: &str) {
120        if let None = self.heads.get(position) {
121            return;
122        }
123
124        self.heads[position] = name.to_string();
125    }
126
127    /**
128     * Insert Head
129     *
130     * Insert new head.
131     */
132    pub fn insert_head(&mut self, position: usize, name: &str) {
133        self.heads.insert(position, name.to_string());
134    }
135
136    /**
137     * Delete Head
138     *
139     *
140     */
141    pub fn delete_head(&mut self, position: usize) -> String {
142        self.heads.remove(position)
143    }
144
145    /**
146     * Pop Head
147     *
148     *
149     */
150    pub fn pop_head(&mut self) -> Option<String> {
151        self.heads.pop()
152    }
153
154    /**
155     * Push Col
156     *
157     * Push new column.
158     */
159    pub fn push_col(&mut self, row: usize, value: &str) {
160        if let None = self.rows.get(row) {
161            return;
162        }
163
164        self.rows[row].push(value.to_string());
165    }
166
167    /**
168     * Set Col
169     *
170     * Set column to target position.
171     */
172    pub fn set_col(&mut self, row: usize, col: usize, value: &str) {
173        if let None = self.rows.get(row) {
174            return;
175        }
176
177        if let None = self.rows[row].get(col) {
178            return;
179        }
180
181        self.rows[row][col] = value.to_string();
182    }
183
184    /**
185     * Insert Col
186     *
187     * Insert new column.
188     */
189    pub fn insert_col(&mut self, row: usize, position: usize, value: &str) {
190        self.rows[row].insert(position, value.to_string())
191    }
192
193    /**
194     * Delete Col
195     *
196     * Delete all columns.
197     */
198    pub fn delete_col(&mut self, position: usize) {
199        self.delete_head(position);
200
201        // Rows
202        for row in self.rows.iter_mut() {
203            if let None = row.get(position) {
204                continue;
205            }
206
207            row.remove(position);
208        }
209    }
210
211    /**
212     * Pop Col
213     *
214     * Pop all columns.
215     */
216    pub fn pop_col(&mut self) {
217        self.pop_head();
218
219        // rows
220        self.rows.iter_mut().for_each(|row| {
221            row.pop();
222        });
223    }
224
225    /**
226     * Push Row
227     *
228     * Push new row.
229     */
230    pub fn push_row(&mut self, value: &[&str]) {
231        self.rows.push(self.row_mapper(value));
232    }
233
234    /**
235     * Set Row
236     *
237     * Set row to target position.
238     */
239    pub fn set_row(&mut self, position: usize, value: &[&str]) {
240        if let None = self.rows.get(position) {
241            return;
242        }
243
244        self.rows[position] = self.row_mapper(value);
245    }
246
247    /**
248     * Insert Row
249     *
250     * Insert new row.
251     */
252    pub fn insert_row(&mut self, position: usize, value: &[&str]) {
253        self.rows.insert(position, self.row_mapper(value));
254    }
255
256    /**
257     * Delete Row
258     *
259     *
260     */
261    pub fn delete_row(&mut self, position: usize) -> Option<Vec<String>> {
262        if let None = self.rows.get(position) {
263            return None;
264        }
265
266        Some(self.rows.remove(position))
267    }
268
269    /**
270     * Pop Row
271     *
272     *
273     */
274    pub fn pop_row(&mut self) -> Option<Vec<String>> {
275        self.rows.pop()
276    }
277
278    /**
279     * Row Mapper
280     *
281     * Maps slices into CsvRow.
282     */
283    fn row_mapper(&self, value: &[&str]) -> CsvRow {
284        value
285            .iter()
286            .map(std::string::ToString::to_string)
287            .collect::<Vec<String>>()
288    }
289}
290
291impl CsvFile {
292    /**
293     * Read
294     *
295     * Read CSV file.
296     */
297    pub fn read<P: AsRef<Path>>(path: P) -> Result<CsvFile, io::Error> {
298        let file = File::open(path)?;
299        let buf = BufReader::new(file);
300
301        let contents = buf
302            .lines()
303            .flatten()
304            .filter(|line| !line.is_empty())
305            .map(|row| {
306                row.split(CSV_SEP)
307                    .map(std::string::ToString::to_string)
308                    .collect::<Vec<String>>()
309            })
310            .collect::<Vec<CsvRow>>();
311
312        Ok(CsvFile {
313            heads: contents[0].clone(),
314            rows: contents[1..].to_vec(),
315        })
316    }
317
318    /**
319     * Write
320     *
321     * Write CSV file.
322     */
323    pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<(), io::Error> {
324        let file = File::create(path)?;
325        let mut buf = BufWriter::new(file);
326
327        if !self.heads.is_empty() {
328            buf.write(self.heads().join(CSV_SEP).as_bytes())?;
329            buf.write("\n".as_bytes())?;
330        }
331
332        for row in self.rows().into_iter() {
333            buf.write(row.join(CSV_SEP).as_bytes())?;
334            buf.write("\n".as_bytes())?;
335        }
336
337        buf.flush()
338    }
339}
340
341impl fmt::Display for CsvFile {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        // border
344        for head in self.heads.iter() {
345            write!(f, "- {} -", "-".repeat(head.len()))?;
346        }
347        write!(f, "\n")?;
348
349        // heads
350        for head in self.heads.iter() {
351            write!(f, "- {} -", head)?;
352        }
353        write!(f, "\n")?;
354
355        // border
356        for head in self.heads.iter() {
357            write!(f, "- {} -", "-".repeat(head.len()))?;
358        }
359        write!(f, "\n")?;
360
361        // rows
362        for row in self.rows.iter() {
363            for col in row.iter() {
364                write!(f, "- {} -", col)?;
365            }
366
367            write!(f, "\n")?;
368        }
369
370        write!(f, "")
371    }
372}