1use serde::Serialize;
2#[derive(Debug, Clone, Copy, Serialize)]
3pub enum Flags {
4 Complex,
5 Real,
6}
7#[derive(Debug, Serialize)]
8pub struct VarData {
9 pub name: String,
10 pub typee: String,
11 pub values: Vec<f64>,
12 pub angles: Option<Vec<f64>>,
13}
14#[derive(Debug, Serialize)]
15pub struct Plot {
16 pub title: String,
17 pub date: String,
18 pub plotname: String,
19 pub flags: Flags,
20 pub no_of_variables: usize,
21 pub no_of_points: usize,
22 pub data: Vec<VarData>,
23}
24
25#[derive(thiserror::Error, Debug)]
26pub enum SpiceParseError {
27 #[error("Cannot parse integer")]
28 ParseInt(#[from] std::num::ParseIntError),
29 #[error("Cannot parse float")]
30 ParseFloat(#[from] std::num::ParseFloatError),
31 #[error("Number of variables mismatch")]
32 NoOfVarMismatch,
33 #[error("Number of values mismatch")]
34 NoOfValMismatch,
35 #[error("Unknown value in flags")]
36 UnknownFlag,
37}
38fn flush_values(
39 no_of_variables: usize,
40 temp_values: &mut Vec<(f64, f64)>,
41 data: &mut Vec<VarData>,
42 flags: Flags,
43) -> Result<(), SpiceParseError> {
44 if temp_values.len() != 0 {
45 if temp_values.len() != no_of_variables {
46 return Result::Err(SpiceParseError::NoOfValMismatch);
47 }
48 let mut idx: usize = 0;
49 for val in temp_values.iter() {
50 data[idx].values.push(val.0);
51 if let Flags::Complex = flags {
52 if let Option::Some(vec) = &mut data[idx].angles {
53 vec.push(val.1);
54 }
55 }
56 idx += 1;
57 }
58 temp_values.clear();
59 }
60 Ok(())
61}
62pub fn parse(file: &str) -> Result<Plot, SpiceParseError> {
63 let mut title: String = String::new();
64 let mut date: String = String::new();
65 let mut plotname: String = String::new();
66 let mut flags: Flags = Flags::Real;
67 let mut no_of_variables: usize = 0;
68 let mut no_of_points: usize = 0;
69 let mut data: Vec<VarData> = Vec::new();
70 enum Modes {
71 Meta,
72 Variable,
73 Value,
74 }
75 let mut mode: Modes = Modes::Meta;
76 let mut variable_counter: usize = 0;
77 let mut temp_values: Vec<(f64, f64)> = Vec::new();
78 for lin in file.lines() {
79 if lin.trim().len() == 0 {
80 continue;
81 }
82 match mode {
83 Modes::Meta => {
84 let parts: Vec<&str> = lin.trim().split(':').collect();
85 match parts[0] {
86 "Title" => title = String::from(parts[1].trim()),
87 "Date" => date = String::from(parts[1..].join("").trim()),
88 "Plotname" => plotname = String::from(parts[1].trim()),
89 "Flags" => {
90 flags = match parts[1].trim() {
91 "complex" => Flags::Complex,
92 "real" => Flags::Real,
93 _ => {
94 return Result::Err(SpiceParseError::UnknownFlag);
95 }
96 }
97 }
98 "No. Variables" => no_of_variables = parts[1].trim().parse()?,
99 "No. Points" => no_of_points = parts[1].trim().parse()?,
100 "Variables" => mode = Modes::Variable,
101 "Values" => mode = Modes::Value,
102 _ => {}
103 };
104 }
105 Modes::Variable => {
106 if variable_counter == no_of_variables {
107 return Result::Err(SpiceParseError::NoOfVarMismatch);
108 }
109 variable_counter += 1;
110
111 if variable_counter == no_of_variables {
112 mode = Modes::Meta;
113 }
114 let parts: Vec<&str> = lin.trim().split("\t").collect();
115 data.push(VarData {
116 name: String::from(parts[1].trim()),
117 typee: String::from(parts[2].trim()),
118 values: Vec::new(),
119 angles: match flags {
120 Flags::Real => None,
121 Flags::Complex => Some(Vec::new()),
122 },
123 })
124 }
125 Modes::Value => {
126 let parts: Vec<&str> = lin.trim().split('\t').collect();
127 let mut num = parts[0];
128 if parts.len() == 2 {
129 flush_values(no_of_variables, &mut temp_values, &mut data, flags)?;
130 num = parts[1];
131 };
132 let val = match flags {
133 Flags::Real => (num.parse()?, 0f64),
134 Flags::Complex => {
135 let pts: Vec<&str> = num.split(",").collect();
136 let real: f64 = pts[0].parse()?;
137 let imaginary: f64 = pts[1].parse()?;
138 (
139 (real.powi(2) + imaginary.powi(2)).sqrt(),
140 (imaginary / real).atan(),
141 )
142 }
143 };
144 temp_values.push(val);
145 }
146 };
147 }
148 flush_values(no_of_variables, &mut temp_values, &mut data, flags)?;
149 Result::Ok(Plot {
150 title,
151 date,
152 plotname,
153 flags,
154 no_of_variables,
155 no_of_points,
156 data,
157 })
158}
159pub fn parse_and_get_csv(file: &str) -> Result<String, SpiceParseError> {
160 let mut ret = String::new();
161 let plot = parse(file)?;
162 for var_data in plot.data.iter() {
163 ret += var_data.name.as_str();
164 ret += " - ";
165 ret += var_data.typee.as_str();
166 ret += ",";
167 if let Flags::Complex = plot.flags {
168 ret += var_data.typee.as_str();
169 ret += "(phase),";
170 }
171 }
172 ret.remove(ret.len() - 1);
173 ret += "\n";
174 for i in 0..plot.no_of_points {
175 for j in 0..plot.no_of_variables {
176 let val: String = match plot.flags {
177 Flags::Real => plot.data[j].values[i].to_string(),
178 Flags::Complex => {
179 if let Some(angles) = &plot.data[j].angles {
180 let mut a = plot.data[j].values[i].to_string();
181 a += ",";
182 a += angles[i].to_degrees().to_string().as_str();
183 a += "°";
184 a
185 } else {
186 String::from("")
187 }
188 }
189 };
190 ret += val.as_str();
191 ret += if j != (plot.no_of_variables - 1) {
192 ","
193 } else {
194 "\n"
195 };
196 }
197 }
198 Ok(ret)
199}
200#[cfg(test)]
201pub mod tests;