numeric_csv_parsing/
numeric_csv_parsing.rs1use std::{num::ParseFloatError, vec};
2
3use validiter::{AtLeast, ConstOver, Ensure};
4
5fn main() {
6 #[derive(Debug)]
15 enum MatParseErr {
16 NotAFloat(usize, usize, ParseFloatError),
17 NoColumns(usize),
18 Negative(usize, usize, f64),
19 NoRows,
20 JaggedArray(usize, Vec<f64>, usize, usize),
21 }
22
23 let csv = "1.2, 3.0
25 4.2, 0.5";
26
27 let mat = csv
29 .lines()
30 .enumerate()
31 .map(|(i, line)| {
32 line.split(",")
33 .map(|s| s.trim())
34 .enumerate()
35 .map(|(j, s)| {
36 s.parse::<f64>()
37 .map_err(|parse_err| MatParseErr::NotAFloat(i, j, parse_err))
38 })
39 .ensure(|val| *val >= 0.0, |j, val| MatParseErr::Negative(i, j, val))
40 .at_least(1, |_| MatParseErr::NoColumns(i))
41 .collect::<Result<Vec<f64>, MatParseErr>>()
42 })
43 .at_least(1, |_| MatParseErr::NoRows)
44 .const_over(
45 |vec| vec.len(),
46 |i, vec, len, expected_len| MatParseErr::JaggedArray(i, vec, len, *expected_len),
47 )
48 .collect::<Result<Vec<_>, _>>();
49
50 match mat {
51 Ok(mat) => {
52 assert_eq!(mat, vec![vec![1.2, 3.0], vec![4.2, 0.5]]);
53 println!("{mat:?}")
54 }
55 Err(mperr) => match mperr {
56 MatParseErr::NotAFloat(i, j, err) => println!("Got {err} at pos [{i}, {j}]"),
57 MatParseErr::NoColumns(i) => {
58 println!("Row {i} is without any data, which would force the matrix to be empty")
59 }
60 MatParseErr::Negative(i, j, val) => {
61 println!("value {val} at pos [{i}, {j}] is negative")
62 }
63 MatParseErr::NoRows => println!("There are no rows in the matrix"),
64 MatParseErr::JaggedArray(i, _vec, len, expected_len) => {
65 println!("Row {i} has len {len}, when all rows should have length {expected_len}")
66 }
67 },
68 }
69}