1#![expect(clippy::type_complexity)]
2use std::path::PathBuf;
3
4use super::{
5 BEGIN_TITLE,
6 utils::{name_str, space, space_newline},
7};
8use crate::{err::ParseError, span::LocatedSpan};
9use nom::{
10 IResult, Parser,
11 branch::alt,
12 bytes::complete::{tag, take_until},
13 character::complete::char,
14 combinator::{map, opt},
15 multi::{many1, separated_list1},
16 sequence::delimited,
17};
18
19const FAILED_MEAS: &str = "failed";
20
21#[inline]
22fn float(i: LocatedSpan) -> IResult<LocatedSpan, Option<f64>> {
23 alt((
24 map(super::utils::float, Some),
25 map(tag(FAILED_MEAS), |_| None),
26 ))
27 .parse_complete(i)
28}
29
30#[inline]
31fn data_meas_csv_nom(
32 i: LocatedSpan<'_>,
33) -> IResult<LocatedSpan<'_>, (Vec<&str>, Vec<Vec<Option<f64>>>)> {
34 map(
35 (
36 take_until(BEGIN_TITLE),
37 take_until("\n"),
38 space_newline,
39 separated_list1((space, char(','), space), map(name_str, |(s, _)| s)),
40 opt(char('#')),
41 opt((space, char(','))),
42 many1(delimited(
43 space_newline,
44 separated_list1((space, char(','), space), float),
45 opt((space, char(','))),
46 )),
47 ),
48 |(_, _, _, names, _, _, value_table): (_, _, _, Vec<&str>, _, _, Vec<Vec<Option<f64>>>)| {
49 (names, value_table)
50 },
51 )
52 .parse_complete(i)
53}
54
55pub struct MeasCols<'a> {
56 names: Vec<&'a str>,
57 idx: usize,
58 vt: &'a [Vec<Option<f64>>],
59 prefix: Option<&'a str>,
60}
61
62impl<'a> MeasCols<'a> {
63 pub fn new(
64 names: Vec<&'a str>,
65 value_table: &'a Vec<Vec<Option<f64>>>,
66 data_prefix: Option<&'a str>,
67 ) -> Self {
68 Self {
69 names,
70 idx: 0,
71 vt: value_table,
72 prefix: data_prefix,
73 }
74 }
75}
76
77pub struct Col<'a> {
78 vt: &'a [Vec<Option<f64>>],
79 col: usize,
80 row: usize,
81}
82
83impl<'a> Iterator for MeasCols<'a> {
84 type Item = (&'a str, Col<'a>);
85
86 fn next(&mut self) -> Option<Self::Item> {
87 while self.idx < self.names.len() {
88 let i = self.idx;
89 let name = self.names[i];
90 self.idx += 1;
91
92 if let Some(p) = self.prefix {
93 if !name.starts_with(p) {
94 continue;
95 }
96 }
97
98 return Some((
99 name,
100 Col {
101 vt: self.vt,
102 col: i,
103 row: 0,
104 },
105 ));
106 }
107 None
108 }
109}
110
111impl<'a> Iterator for Col<'a> {
112 type Item = Option<f64>;
113
114 fn next(&mut self) -> Option<Self::Item> {
115 if self.row >= self.vt.len() {
116 return None;
117 }
118 let v = self.vt[self.row][self.col]; self.row += 1;
120 Some(v)
121 }
122}
123
124#[inline]
125pub fn data_meas_csv(path: PathBuf, s: &str) -> Option<(Vec<&str>, Vec<Vec<Option<f64>>>)> {
126 match data_meas_csv_nom(s.into()) {
127 Ok((_, out)) => Some(out),
128 Err(e) => {
129 let err: ParseError = e.into();
130 err.report(&mut true, &crate::FileId::Include { path }, s);
131 None
132 }
133 }
134}
135
136#[test]
137fn sim_mt0_csv() {
138 crate::utlis::test::init_logger();
139 const DATA: &str = include_str!("../../tests/sim.mt0.csv");
140 let (names, value_table) =
141 data_meas_csv(PathBuf::from("tests/sim.mt0.csv"), DATA.into()).unwrap();
142 for (k, v) in MeasCols::new(names, &value_table, Some("kcell")) {
143 dbg!(k, v.collect::<Vec<_>>());
144 }
145}