nmeasis 26.4.1

A memory-safe NMEA 0183 parser with a C FFI
Documentation
use crate::{
    encoder::NmeaEncode,
    macros::{write_byte, write_str},
    message::NmeaMessageError,
    number::NmeaNumber,
    parser::NmeaParse,
    time::NmeaTime,
};

/// GST - GPS Pseudorange Noise Statistics
#[derive(Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Gst<'a> {
    /// 1. UTC time of the associated GGA Fix
    pub time: &'a str,
    /// 2. Total RMS std dev of ranges inputs to the Nav solution
    pub rms: &'a str,
    /// 3. Std Dev of semi-major axis of error ellipse (meters)
    pub ellipse_semi_major_error: &'a str,
    /// 4. Std Dev of semi-minor axis of error ellipse (meters)
    pub ellipse_semi_minor_error: &'a str,
    /// 5. Orientation of the semimajor axis of error ellipse (true north degrees)
    pub ellipse_orientation_error: &'a str,
    /// 6. Std Dev of latitude error (meters)
    pub latitude_error: &'a str,
    /// 7. Std Dev of longitude error (meters)
    pub longitude_error: &'a str,
    /// 8. Std Dev of altitude error (meters)
    pub altitude_error: &'a str,
}

impl<'a> NmeaParse<'a> for Gst<'a> {
    fn parse(fields: &'a str) -> Result<Self, NmeaMessageError> {
        let mut f = fields.splitn(8, ',');
        Ok(Self {
            time: f.next().ok_or(NmeaMessageError::MissingField)?,
            rms: f.next().ok_or(NmeaMessageError::MissingField)?,
            ellipse_semi_major_error: f.next().ok_or(NmeaMessageError::MissingField)?,
            ellipse_semi_minor_error: f.next().ok_or(NmeaMessageError::MissingField)?,
            ellipse_orientation_error: f.next().ok_or(NmeaMessageError::MissingField)?,
            latitude_error: f.next().ok_or(NmeaMessageError::MissingField)?,
            longitude_error: f.next().ok_or(NmeaMessageError::MissingField)?,
            altitude_error: f.next().ok_or(NmeaMessageError::MissingField)?,
        })
    }
}

impl NmeaEncode for Gst<'_> {
    fn encoded_len(&self) -> usize {
        self.time.len()
            + self.rms.len()
            + self.ellipse_semi_major_error.len()
            + self.ellipse_semi_minor_error.len()
            + self.ellipse_orientation_error.len()
            + self.latitude_error.len()
            + self.longitude_error.len()
            + self.altitude_error.len()
            + 7
    }

    fn encode(&self, buf: &mut [u8]) -> usize {
        let mut pos = 0;
        write_str!(buf, pos, self.time);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.rms);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.ellipse_semi_major_error);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.ellipse_semi_minor_error);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.ellipse_orientation_error);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.latitude_error);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.longitude_error);
        write_byte!(buf, pos, b',');
        write_str!(buf, pos, self.altitude_error);
        pos
    }
}

impl Gst<'_> {
    #[must_use]
    pub fn time(&self) -> Option<NmeaTime> {
        NmeaTime::parse(self.time)
    }

    #[must_use]
    pub fn rms(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.rms)
    }

    #[must_use]
    pub fn ellipse_semi_major_error(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.ellipse_semi_major_error)
    }

    #[must_use]
    pub fn ellipse_semi_minor_error(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.ellipse_semi_minor_error)
    }

    #[must_use]
    pub fn ellipse_orientation_error(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.ellipse_orientation_error)
    }

    #[must_use]
    pub fn latitude_error(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.latitude_error)
    }

    #[must_use]
    pub fn longitude_error(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.longitude_error)
    }

    #[must_use]
    pub fn altitude_error(&self) -> Option<NmeaNumber> {
        NmeaNumber::parse(self.altitude_error)
    }
}