Compare commits

...

3 Commits

Author SHA1 Message Date
Misha Vicha
1c56fdb5bd Improves the handling of Header::from_record
The correct vector capacity is now automatically initialized
2025-10-01 10:33:00 +02:00
Misha Vicha
136fe97fb7 Adds autodoc comments to headparse 2025-10-01 10:29:34 +02:00
Misha Vicha
5735a3b0b5 Renames headproc to more descriptive headparse 2025-10-01 10:12:08 +02:00
2 changed files with 45 additions and 17 deletions

View File

@@ -2,14 +2,16 @@ use std::{collections::HashMap, u64, vec};
use crate::SignalFormat; use crate::SignalFormat;
/// Record information obtained from the header. /// Holds the essential header information about the record, like the amount of
/// signals, and the sampling frequency.
/// ///
/// Only the `name`, `signal_count`, and `sampling_freq` values are required by default. /// Only the `name`, `signal_count`, and `sampling_freq` values are required by
/// default.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Record { struct Record {
name: String, name: String,
seg_num: Option<u64>, seg_num: Option<u64>,
signal_count: u64, signal_count: usize,
sampling_freq: u64, sampling_freq: u64,
counter_freq: Option<u64>, counter_freq: Option<u64>,
base_counter_val: Option<u64>, base_counter_val: Option<u64>,
@@ -19,7 +21,11 @@ struct Record {
} }
impl Record { impl Record {
/// Attempts to generate the record information from a string of the argument line /// Attempts to generate the record information from a string of the argument
/// line that's provided by the WFDB header file
///
/// Returns a `Result<Record, &str>`, with the error field potentially
/// describing why the parsing operation failed
pub fn from_str(argument_line: &str) -> Result<Record, &str> { pub fn from_str(argument_line: &str) -> Result<Record, &str> {
let args: Vec<&str> = argument_line.split(' ').collect(); let args: Vec<&str> = argument_line.split(' ').collect();
if args.len() < 2 { if args.len() < 2 {
@@ -27,7 +33,7 @@ impl Record {
} }
let name = args[0].to_string(); let name = args[0].to_string();
let seg_num: Option<u64>; let seg_num: Option<u64>;
let sig_count: u64; let sig_count: usize;
let sampling_freq: u64; let sampling_freq: u64;
// Everything else is initialized with None, this is for sake of me not getting a stroke // Everything else is initialized with None, this is for sake of me not getting a stroke
let mut counter_freq: Option<u64> = None; let mut counter_freq: Option<u64> = None;
@@ -53,7 +59,7 @@ impl Record {
} else { } else {
seg_num = None; seg_num = None;
} }
match seg_sig[0].parse::<u64>() { match seg_sig[0].parse::<usize>() {
Ok(value) => { Ok(value) => {
sig_count = value; sig_count = value;
} }
@@ -134,6 +140,8 @@ impl Record {
} }
} }
/// Keys for all the data that can possibly be parsed from the values appended
/// to the ADC block
#[derive(Debug, Eq, Hash, PartialEq)] #[derive(Debug, Eq, Hash, PartialEq)]
enum AdcBlockKeys { enum AdcBlockKeys {
Gain, Gain,
@@ -141,7 +149,9 @@ enum AdcBlockKeys {
Units Units
} }
/// Holds the information relevant to individual signals and their specifications
///
/// By minimum, only carries the `filename`, `format`, and `adc_zero` attributes
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct SignalSpec { struct SignalSpec {
filename: String, filename: String,
@@ -161,11 +171,14 @@ struct SignalSpec {
} }
impl SignalSpec { impl SignalSpec {
/// Attempts to generate a valid signal specification struct from a supplied string. /// Attempts to generate a valid signal specification struct from a supplied
/// Returns a `Result<SignalSpec, &str>` containing possible error information. /// string.
/// Returns a `Result<SignalSpec, &str>` containing possible error information
/// relevant to parsing failures.
/// ///
/// ## Arguments /// ## Arguments
/// - `argument_line` - argument line for the signal specification, taken from header file /// - `argument_line` - argument line for the signal specification, taken
/// from header file
pub fn from_str(argument_line: &str) -> Result<SignalSpec, &str> { pub fn from_str(argument_line: &str) -> Result<SignalSpec, &str> {
let args: Vec<&str> = argument_line.split(' ').collect(); let args: Vec<&str> = argument_line.split(' ').collect();
@@ -308,8 +321,10 @@ impl SignalSpec {
Ok(value) => { Ok(value) => {
initial_val = Some(value); initial_val = Some(value);
}, },
Err(_) => {} // Standard: If this field is missing, adc_zero value is presumed. // Standard: If this field is missing,
// the adc_zero value is presumed.
// We do this on the data parsing part. // We do this on the data parsing part.
Err(_) => {}
} }
if args.len() <= 6 { if args.len() <= 6 {
@@ -361,6 +376,8 @@ impl SignalSpec {
) )
} }
/// Parses the WFDB signal format from the format number, if it exists and
/// is implemented
fn parse_format(formatnum: u64) -> SignalFormat { fn parse_format(formatnum: u64) -> SignalFormat {
match formatnum { match formatnum {
16 => SignalFormat::Format16, 16 => SignalFormat::Format16,
@@ -370,6 +387,9 @@ impl SignalSpec {
} }
} }
/// Holds all the possible data from the WFDB header file, those being the record
/// line data and all the possible signal specifications present on the following
/// lines
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Header { pub struct Header {
record: Option<Record>, record: Option<Record>,
@@ -386,8 +406,13 @@ impl Header {
Header { record: None, signal_specs: vec![] } Header { record: None, signal_specs: vec![] }
} }
/// Creates a Header from a supplied Record struct.
///
/// Initializes the signal_specs vector with the correct capacity provided
/// by the record.
fn from_record(record: Record) -> Header { fn from_record(record: Record) -> Header {
Header { record: Some(record), signal_specs: vec![] } let capacity = record.signal_count;
Header { record: Some(record), signal_specs: Vec::with_capacity(capacity) }
} }
fn add_signal_spec(&mut self, spec: SignalSpec) { fn add_signal_spec(&mut self, spec: SignalSpec) {
@@ -402,13 +427,16 @@ impl Header {
} }
} }
/// Attempts to parse the header file /// Attempts to parse the header file.
///
/// Returns a Result either containing the `Header` struct, or the
/// error string describing why we couldn't parse the header.
pub fn parse_header(header_data: &str) -> Result<Header, &str> { pub fn parse_header(header_data: &str) -> Result<Header, &str> {
let header_lines: Vec<&str> = header_data.split("\n").collect(); let header_lines: Vec<&str> = header_data.split("\n").collect();
let mut found_record: bool = false; let mut found_record: bool = false;
let mut header: Header = Header::new(); let mut header: Header = Header::new();
let mut specs_read: u64 = 0; let mut specs_read: usize = 0;
let mut specs_max: u64 = 0; let mut specs_max: usize = 0;
for line in header_lines { for line in header_lines {
// Ignore commented lines // Ignore commented lines
if line.starts_with("#") { if line.starts_with("#") {

View File

@@ -1,7 +1,7 @@
use std::{env::{self}, io::Error, path::Path}; use std::{env::{self}, io::Error, path::Path};
use std::fs; use std::fs;
pub mod headproc; // The HEAder PROCessing pub mod headparse; // The HEAder parsing
/// Use for handling possible formats of the WFDB data /// Use for handling possible formats of the WFDB data
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@@ -32,7 +32,7 @@ fn main() -> Result<(), Error>{
let hea_file_result = fs::read_to_string(filepath); let hea_file_result = fs::read_to_string(filepath);
match hea_file_result { match hea_file_result {
Ok(file_data) => { Ok(file_data) => {
let header = headproc::parse_header(file_data.as_str()); let header = headparse::parse_header(file_data.as_str());
dbg!(header); dbg!(header);
} }
Err(e) => return Err(e) Err(e) => return Err(e)