igc_parser 0.1.7

A high-level parsing/deserializing crate for IGC flight recorder files
Documentation
use crate::{error::IGCError::FileHeaderInitError, StrWrapper};
use crate::records::util::Date;
use crate::Result;
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};

#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, Clone)]
pub enum FileHeader {
    Date(Date),
    FixAccuracy(u16),
    PilotInCharge(StrWrapper),
    SecondPilot(StrWrapper),
    GliderType(StrWrapper),
    GliderID(StrWrapper),
    GPSDatum(StrWrapper),
    Firmware(StrWrapper),
    Hardware(StrWrapper),
    LoggerType(StrWrapper),
    GPSManufacturer(StrWrapper),
    PressureSensor(StrWrapper),
    CompetitionID(StrWrapper),
    CompetitionClass(StrWrapper),
}

fn get_file_header_with_string_content<'a>(line: &'a str, header_name: &str) -> Result<&'a str> {
    if line.len() < header_name.len() { return Err(FileHeaderInitError(format!("'{line}' does not have the correct length to be parsed as a pilot in charge record"))) };
    Ok(&line[header_name.len()..])
}

impl FileHeader {
    pub(crate) fn parse(line: &str) -> Result<Self> {
        match &line[0..5] {
            "HFDTE" => {
                if line.len() != 11 { 
                    match &line[5..10]{
                        "DATE:" =>
                        { 
                            let date = Date::parse(&line[10..16])?;
                            Ok(FileHeader::Date(date))
                        }
                        _ => return Err(FileHeaderInitError(format!("'{line}' does not have the correct length to be parsed as a file header date"))) 
                    }
                } else {
                    let date = Date::parse(&line[5..11])?;
                    Ok(FileHeader::Date(date))
                }
            },
            "HFFXA" => {
                if line.len() != 8 { return Err(FileHeaderInitError(format!("'{line}' does not have the correct length to be parsed as a file header fix accuracy"))) };
                let accuracy = line[6..8].parse::<u16>();
                match accuracy {
                    Ok(accuracy) => Ok(FileHeader::FixAccuracy(accuracy)),
                    Err(_) => Err(FileHeaderInitError(format!("'{line}' can not be parsed as a fix accuracy number"))),
                }
            },
            "HFPLT" => {
                let pilot_in_charge = get_file_header_with_string_content(line, "HFPLTPILOTINCHARGE:")?;
                Ok(FileHeader::PilotInCharge(pilot_in_charge.to_string().into()))
            },
            "HFCM2" => {
                let second_pilot = get_file_header_with_string_content(line, "HFCM2CREW2:")?;
                Ok(FileHeader::SecondPilot(second_pilot.to_string().into()))
            },
            "HFGTY" => {
                let content = get_file_header_with_string_content(line, "HFGTYGLIDERTYPE:")?;
                Ok(FileHeader::GliderType(content.to_string().into()))
            },
            "HFGID" => {
                let content = get_file_header_with_string_content(line, "HFGIDGLIDERID:")?;
                Ok(FileHeader::GliderID(content.to_string().into()))
            },
            "HFDTM" => {
                let content = get_file_header_with_string_content(line, "HFDTMNNNGPSDATUM:")?;
                Ok(FileHeader::GPSDatum(content.to_string().into()))
            },
            "HFRFW" => {
                let content = get_file_header_with_string_content(line, "HFRFWFIRMWAREVERSION:")?;
                Ok(FileHeader::Firmware(content.to_string().into()))
            },
            "HFRHW" => {
                let content = get_file_header_with_string_content(line, "HFRHWHARDWAREVERSION:")?;
                Ok(FileHeader::Hardware(content.to_string().into()))
            },
            "HFFTY" => {
                let content = get_file_header_with_string_content(line, "HFFTYFRTYPE:")?;
                Ok(FileHeader::LoggerType(content.to_string().into()))
            },
            "HFGPS" => {
                let content = get_file_header_with_string_content(line, "HFGPS")?;
                Ok(FileHeader::GPSManufacturer(content.to_string().into()))
            },
            "HFPRS" => {
                let content = get_file_header_with_string_content(line, "HFPRSPRESSALTSENSOR:")?;
                Ok(FileHeader::PressureSensor(content.to_string().into()))
            },
            "HFCID" => {
                let content = get_file_header_with_string_content(line, "HFCIDCOMPETITIONID:")?;
                Ok(FileHeader::CompetitionID(content.to_string().into()))
            },
            "HFCCL" => {
                let content = get_file_header_with_string_content(line, "HFCCLCOMPETITIONCLASS:")?;
                Ok(FileHeader::CompetitionClass(content.to_string().into()))
            },
            _ => Err(FileHeaderInitError(format!("'{line}' does not have a valid file header start")))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;


    #[test]
    fn get_file_header_with_string_content_test() {
        let line = "HFPLTPILOTINCHARGE:John Doe";
        let header_name = "HFPLTPILOTINCHARGE:";
        let result = get_file_header_with_string_content(line, header_name);
        assert_eq!(result.unwrap(), "John Doe");

        // too short
        let line = "HFPLTPILOTINCHARGE";
        let header_name = "HFPLTPILOTINCHARGE:";
        let result = get_file_header_with_string_content(line, header_name);
        assert!(result.is_err());

        let line = "HFFXA1AB";
        assert!(FileHeader::parse(line).is_err());
        let line = "HABCD123";
        assert!(FileHeader::parse(line).is_err());
    }
}