use crate::{
coordinates::NmeaCoordinates,
encoder::NmeaEncode,
faa::FaaMode,
macros::{write_byte, write_str},
message::NmeaMessageError,
parser::NmeaParse,
time::NmeaTime,
};
#[derive(Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Gll<'a> {
pub latitude: &'a str,
pub latitude_dir: &'a str,
pub longitude: &'a str,
pub longitude_dir: &'a str,
pub time: &'a str,
pub status: &'a str,
pub faa_mode: Option<&'a str>,
}
impl<'a> NmeaParse<'a> for Gll<'a> {
fn parse(fields: &'a str) -> Result<Self, NmeaMessageError> {
let mut f = fields.splitn(7, ',');
Ok(Self {
latitude: f.next().ok_or(NmeaMessageError::MissingField)?,
latitude_dir: f.next().ok_or(NmeaMessageError::MissingField)?,
longitude: f.next().ok_or(NmeaMessageError::MissingField)?,
longitude_dir: f.next().ok_or(NmeaMessageError::MissingField)?,
time: f.next().ok_or(NmeaMessageError::MissingField)?,
status: f.next().ok_or(NmeaMessageError::MissingField)?,
faa_mode: f.next().filter(|s| !s.is_empty()),
})
}
}
impl NmeaEncode for Gll<'_> {
fn encoded_len(&self) -> usize {
self.latitude.len()
+ self.latitude_dir.len()
+ self.longitude.len()
+ self.longitude_dir.len()
+ self.time.len()
+ self.status.len()
+ self.faa_mode.map_or(0, |fa| fa.len() + 1)
+ 5
}
fn encode(&self, buf: &mut [u8]) -> usize {
let mut pos = 0;
write_str!(buf, pos, self.latitude);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.latitude_dir);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.longitude);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.longitude_dir);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.time);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.status);
if let Some(faa_mode) = self.faa_mode {
write_byte!(buf, pos, b',');
write_str!(buf, pos, faa_mode);
}
pos
}
}
impl Gll<'_> {
#[must_use]
pub fn coordinates(&self) -> Option<NmeaCoordinates> {
NmeaCoordinates::parse(
self.latitude,
self.latitude_dir,
self.longitude,
self.longitude_dir,
)
}
#[must_use]
pub fn time(&self) -> Option<NmeaTime> {
NmeaTime::parse(self.time)
}
#[must_use]
pub fn is_valid(&self) -> bool {
self.status == "A"
}
pub fn faa_mode(&self) -> Option<FaaMode> {
self.faa_mode.and_then(FaaMode::parse)
}
}