use regex::Regex;
use std::sync::OnceLock;
#[derive(Default, Clone, Debug, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum DataUnit {
V,
mV,
#[default]
uV,
nV,
C, ARU, S, uS,
N,
NA,
}
#[derive(Default, Clone, Debug, PartialEq)]
pub struct ChannelInfo {
pub header_id: String,
pub label: String,
pub reference: String,
pub resolution: Option<f32>,
pub unit: DataUnit,
}
static CHANINFO_REGEX: OnceLock<Regex> = OnceLock::new();
pub fn parse_chan_info(textcontent: &str) -> Vec<ChannelInfo> {
let re = CHANINFO_REGEX.get_or_init(|| {
Regex::new(r"([Cch].\d.*)=([\w\.,]*)").unwrap()
});
let mut results = vec![];
for caps in re.captures_iter(textcontent) {
let header_id = caps.get(1).map(|m| m.as_str());
if header_id.is_some() { let header_id = header_id.unwrap().to_string();
let second_capture = caps.get(2).map(|m| m.as_str()).unwrap();
let split_values: Vec<&str> = second_capture.split(',').collect();
if split_values.len() == 4 {
let label: String = split_values[0].to_string();
let reference: String = split_values[1].to_string();
let _res = split_values[2].parse::<f32>();
let resolution: Option<f32> = if _res.is_ok() {Some(_res.unwrap())} else {Option::None};
let unit = split_values[3];
let unit = match unit {
"V" => DataUnit::V,
"mV" => DataUnit::mV,
"uV"|"µV" => DataUnit::uV,
"nV" => DataUnit::nV,
"C"|"°C" => DataUnit::C,
"S" => DataUnit::S,
"uS"|"µS" => DataUnit::uS,
"ARU" => DataUnit::ARU,
"N" => DataUnit::N,
"n/a" => DataUnit::NA,
_ => DataUnit::NA,
};
let chan = ChannelInfo{
header_id,
label,
reference,
resolution,
unit
};
results.push(chan);
}
}
}
results
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_chan_info() {
let input = "; Commas in channel names are coded as.
Ch1=Fp1,,0.0488281,µV";
let output = parse_chan_info(input);
let expected = vec![ChannelInfo{
header_id: "Ch1".to_string(),
label: "Fp1".to_string(),
reference: "".to_string(),
resolution: Some(0.0488281),
unit: DataUnit::uV,
}];
assert_eq!(output, expected);
}
#[test]
fn test_parse_chan_info_empty() {
let input = "[Common Infos]
Codepage=
DataFile=01_data.eeg";
let output = parse_chan_info(input);
let expected = vec![];
assert_eq!(output, expected);
}
}