1use alloc::borrow::ToOwned as _;
2use alloc::vec::Vec;
3
4use tracing::instrument;
5
6use super::{read_field_values, DataFrameKind, DataFrameProperty};
7use crate::headers::{ParseError, ParseResult};
8use crate::parser::{Encoding, InternalResult};
9use crate::predictor::{Predictor, PredictorContext};
10use crate::{Headers, Reader};
11
12#[derive(Debug, Clone)]
13pub(crate) struct GpsHomeFrame(pub(crate) GpsPosition);
14
15#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
16pub(crate) struct GpsPosition {
17 pub(crate) latitude: i32,
18 pub(crate) longitude: i32,
19}
20
21#[derive(Debug, Clone)]
22pub(crate) struct GpsHomeFrameDef<'data>([GpsHomeFieldDef<'data>; 2], Vec<Encoding>);
23
24impl<'data> GpsHomeFrameDef<'data> {
25 pub(crate) fn builder() -> GpsHomeFrameDefBuilder<'data> {
26 GpsHomeFrameDefBuilder::default()
27 }
28
29 pub(crate) fn validate(
30 &self,
31 check_predictor: impl Fn(DataFrameKind, &'data str, Predictor, usize) -> ParseResult<()>,
32 _check_unit: impl Fn(DataFrameKind, &'data str, super::Unit) -> ParseResult<()>,
33 ) -> ParseResult<()> {
34 for (
35 i,
36 GpsHomeFieldDef {
37 name, predictor, ..
38 },
39 ) in self.0.iter().enumerate()
40 {
41 check_predictor(DataFrameKind::GpsHome, name, *predictor, i)?;
42 }
43
44 Ok(())
45 }
46
47 #[instrument(level = "trace", name = "GpsHomeFrameDef::parse", skip_all)]
48 pub(crate) fn parse(
49 &self,
50 data: &mut Reader,
51 headers: &Headers,
52 ) -> InternalResult<GpsHomeFrame> {
53 let raw = read_field_values(data, &self.0, |f| f.encoding)?;
54 let _ = read_field_values(data, &self.1, |&f| f)?;
55
56 let ctx = PredictorContext::new(headers);
57 let values = raw
58 .iter()
59 .zip(self.0.iter())
60 .map(|(&raw_value, field)| {
61 let value = field.predictor.apply(raw_value, true, None, &ctx);
62
63 tracing::trace!(
64 field = field.name,
65 encoding = ?field.encoding,
66 predictor = ?field.predictor,
67 raw = raw_value,
68 value,
69 );
70
71 value.cast_signed()
72 })
73 .collect::<Vec<_>>();
74
75 let [latitude, longitude, ..] = values[..] else {
77 unreachable!()
78 };
79
80 Ok(GpsHomeFrame(GpsPosition {
81 latitude,
82 longitude,
83 }))
84 }
85}
86
87#[allow(dead_code)]
88#[derive(Debug, Clone)]
89pub(crate) struct GpsHomeFieldDef<'data> {
90 pub(crate) name: &'data str,
91 pub(crate) predictor: Predictor,
92 pub(crate) encoding: Encoding,
93}
94
95#[derive(Debug, Default)]
96pub(crate) struct GpsHomeFrameDefBuilder<'data> {
97 names: Option<&'data str>,
98 predictors: Option<&'data str>,
99 encodings: Option<&'data str>,
100 signs: Option<&'data str>,
101}
102
103impl<'data> GpsHomeFrameDefBuilder<'data> {
104 pub(crate) fn update(&mut self, property: DataFrameProperty, value: &'data str) {
105 let value = Some(value);
106
107 match property {
108 DataFrameProperty::Name => self.names = value,
109 DataFrameProperty::Predictor => self.predictors = value,
110 DataFrameProperty::Encoding => self.encodings = value,
111 DataFrameProperty::Signed => self.signs = value,
112 }
113 }
114
115 pub(crate) fn parse(self) -> ParseResult<Option<GpsHomeFrameDef<'data>>> {
116 let kind = DataFrameKind::Gps;
117
118 if self.names.is_none()
119 && self.predictors.is_none()
120 && self.encodings.is_none()
121 && self.signs.is_none()
122 {
123 return Ok(None);
124 }
125
126 let mut names = super::parse_names(kind, self.names)?;
127 let mut predictors = super::parse_predictors(kind, self.predictors)?;
128 let mut encodings = super::parse_encodings(kind, self.encodings)?;
129 let mut signs = super::parse_signs(kind, self.signs)?;
130
131 let mut fields =
132 (names.by_ref().zip(signs.by_ref())).zip(predictors.by_ref().zip(encodings.by_ref()));
133
134 let latitude =
135 if let Some(((name @ "GPS_home[0]", true), (predictor, encoding))) = fields.next() {
136 GpsHomeFieldDef {
137 name,
138 predictor: predictor?,
139 encoding: encoding?,
140 }
141 } else {
142 tracing::error!("missing GPS_home[0] field definition");
143 return Err(ParseError::MissingField {
144 frame: DataFrameKind::GpsHome,
145 field: "GPS_home[0]".to_owned(),
146 });
147 };
148
149 let longitude =
150 if let Some(((name @ "GPS_home[1]", true), (predictor, encoding))) = fields.next() {
151 GpsHomeFieldDef {
152 name,
153 predictor: predictor?,
154 encoding: encoding?,
155 }
156 } else {
157 tracing::error!("missing GPS_home[1] field definition");
158 return Err(ParseError::MissingField {
159 frame: DataFrameKind::GpsHome,
160 field: "GPS_home[1]".to_owned(),
161 });
162 };
163
164 let rest = fields
165 .map(|(_, (_, encoding))| encoding)
166 .collect::<Result<Vec<_>, _>>()?;
167
168 if !rest.is_empty() {
169 tracing::warn!(
170 "expected only GPS_home[0] & GPS_home[1] fields in gps home frames, found {} more",
171 rest.len()
172 );
173 }
174
175 if names.next().is_some()
176 || predictors.next().is_some()
177 || encodings.next().is_some()
178 || signs.next().is_some()
179 {
180 tracing::error!("not all GPS home definition headers are of equal length");
181 return Err(ParseError::MalformedFrameDef(DataFrameKind::GpsHome));
182 }
183
184 Ok(Some(GpsHomeFrameDef([latitude, longitude], rest)))
185 }
186}