fit_rust/protocol/
data_field.rs

1use crate::protocol::consts::{COORD_SEMICIRCLES_CALC, PSEUDO_EPOCH};
2use crate::protocol::get_field_offset::get_field_offset_fn;
3use crate::protocol::get_field_scale::get_field_scale_fn;
4use crate::protocol::get_field_string_value::{
5    get_field_key_from_string, get_field_string_value, FieldType,
6};
7use crate::protocol::get_field_type::get_field_type_fn;
8use crate::protocol::io::{
9    read_i16, read_i32, read_i64, read_i8, read_u16, read_u16_arr, read_u32, read_u32_arr,
10    read_u64, read_u8, read_u8_arr, skip_bytes, write_bin,
11};
12use crate::protocol::message_type::MessageType;
13use crate::protocol::value::Value;
14use crate::protocol::{
15    DefinitionMessage, FieldDefinition, MatchFieldTypeFn, MatchOffsetFn, MatchScaleFn,
16};
17use binrw::{BinResult, Endian};
18use copyless::VecHelper;
19use std::fmt::{Debug, Formatter};
20use std::io::{Read, Seek, Write};
21
22#[derive(Clone, PartialEq)]
23pub struct DataField {
24    pub field_num: u8,
25
26    pub value: Value,
27}
28
29impl Debug for DataField {
30    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31        write!(f, " {{ t: {:?}, v: {:?} }}", &self.field_num, &self.value)
32    }
33}
34
35impl DataField {
36    pub fn new(fnum: u8, v: Value) -> Self {
37        Self {
38            field_num: fnum,
39            value: v,
40        }
41    }
42
43    #[binrw::parser(reader, endian)]
44    pub fn parse_data_field(
45        message_type: MessageType,
46        fields: &Vec<FieldDefinition>,
47    ) -> BinResult<Vec<DataField>> {
48        let mut values = Vec::with_capacity(fields.len());
49        if message_type == MessageType::None {
50            let size_sum: u8 = fields.iter().map(|field| field.size).sum();
51            println!(
52                "message_type == MessageType::None, skip_bytes: {}",
53                size_sum
54            );
55            skip_bytes(reader, size_sum);
56        } else {
57            for fd in fields.iter() {
58                let data = DataField::read_next_field(fd.size, fd.base_type.val, reader, endian);
59                values
60                    .alloc()
61                    .init(DataField::new(fd.definition_number, data));
62            }
63            // check each value in case the raw value needs further processing
64            let scales = get_field_scale_fn(message_type);
65            let offsets = get_field_offset_fn(message_type);
66            let fields = get_field_type_fn(message_type);
67            for v in &mut values {
68                DataField::process_read_value(v, fields, scales, offsets);
69            }
70        }
71        // values.shrink_to_fit();
72        Ok(values)
73    }
74
75    #[allow(clippy::cognitive_complexity)]
76    pub fn read_next_field<R>(size: u8, base_type: u8, reader: &mut R, endian: Endian) -> Value
77    where
78        R: Read + Seek,
79    {
80        match base_type {
81            0 | 13 => {
82                // enum / byte
83                if size > 1 {
84                    let c = read_u8_arr(reader, size);
85                    if c.is_empty() {
86                        Value::None
87                    } else {
88                        Value::ArrU8(c)
89                    }
90                } else {
91                    match read_u8(reader) {
92                        v => Value::U8(v),
93                    }
94                }
95            }
96            1 => {
97                // sint8
98                if size > 1 {
99                    let c = read_u8_arr(reader, size);
100                    if c.is_empty() {
101                        Value::None
102                    } else {
103                        Value::ArrU8(c)
104                    }
105                } else {
106                    match read_i8(reader) {
107                        v => Value::I8(v),
108                    }
109                }
110            }
111            2 => {
112                // uint8
113                if size > 1 {
114                    let c = read_u8_arr(reader, size);
115                    if c.is_empty() {
116                        Value::None
117                    } else {
118                        Value::ArrU8(c)
119                    }
120                } else {
121                    match read_u8(reader) {
122                        v => Value::U8(v),
123                    }
124                }
125            }
126            3 => {
127                // sint16
128                let number_of_values = size / 2;
129                if number_of_values > 1 {
130                    let c = read_u8_arr(reader, size);
131                    if c.is_empty() {
132                        Value::None
133                    } else {
134                        Value::ArrU8(c)
135                    }
136                } else {
137                    let val = read_i16(reader, endian);
138                    Value::I16(val)
139                }
140            }
141            4 => {
142                // uint16
143                let number_of_values = size / 2;
144                if number_of_values > 1 {
145                    let c = read_u16_arr(reader, endian, number_of_values);
146                    if c.is_empty() {
147                        Value::None
148                    } else {
149                        Value::ArrU16(c)
150                    }
151                } else {
152                    let val = read_u16(reader, endian);
153                    Value::U16(val)
154                }
155            }
156            5 => {
157                // sint32
158                let number_of_values = size / 4;
159                if number_of_values > 1 {
160                    let c = read_u8_arr(reader, size);
161                    if c.is_empty() {
162                        Value::None
163                    } else {
164                        Value::ArrU8(c)
165                    }
166                } else {
167                    let val = read_i32(reader, endian);
168                    Value::I32(val)
169                }
170            }
171            6 => {
172                // uint32
173                let number_of_values = size / 4;
174                if number_of_values > 1 {
175                    let c = read_u32_arr(reader, endian, number_of_values);
176                    if c.is_empty() {
177                        Value::None
178                    } else {
179                        Value::ArrU32(c)
180                    }
181                } else {
182                    let val = read_u32(reader, endian);
183                    Value::U32(val)
184                }
185            }
186            7 => {
187                // string
188                let mut buf: Vec<_> = Vec::with_capacity(size.into());
189                let _ = reader.take(size.into()).read_to_end(&mut buf);
190                if let Ok(string) = String::from_utf8(buf) {
191                    Value::String(string)
192                } else {
193                    Value::None
194                }
195            }
196            8 => {
197                // float32
198                let number_of_values = size / 4;
199                if number_of_values > 1 {
200                    let c = read_u8_arr(reader, size);
201                    if c.is_empty() {
202                        Value::None
203                    } else {
204                        Value::ArrU8(c)
205                    }
206                } else {
207                    let uval = read_u32(reader, endian);
208                    let val = f32::from_bits(uval);
209                    Value::F32(val)
210                }
211            }
212            9 => {
213                // float64
214                let number_of_values = size / 8;
215                if number_of_values > 1 {
216                    let c = read_u8_arr(reader, size);
217                    if c.is_empty() {
218                        Value::None
219                    } else {
220                        Value::ArrU8(c)
221                    }
222                } else {
223                    let uval = read_u64(reader, endian);
224                    let val = f64::from_bits(uval);
225                    Value::F64(val)
226                }
227            }
228            10 => {
229                // uint8z
230                if size > 1 {
231                    let c = read_u8_arr(reader, size);
232                    if c.is_empty() {
233                        Value::None
234                    } else {
235                        Value::ArrU8(c)
236                    }
237                } else {
238                    let val = read_u8(reader);
239                    Value::U8(val)
240                }
241            }
242            11 => {
243                // uint16z
244                let number_of_values = size / 2;
245                if number_of_values > 1 {
246                    let c = read_u8_arr(reader, size);
247                    if c.is_empty() {
248                        Value::None
249                    } else {
250                        Value::ArrU8(c)
251                    }
252                } else {
253                    let val = read_u16(reader, endian);
254                    Value::U16(val)
255                }
256            }
257            12 => {
258                // uint32z
259                let number_of_values = size / 4;
260                if number_of_values > 1 {
261                    let c = read_u8_arr(reader, size);
262                    if c.is_empty() {
263                        Value::None
264                    } else {
265                        Value::ArrU8(c)
266                    }
267                } else {
268                    let val = read_u32(reader, endian);
269                    Value::U32(val)
270                }
271            }
272            14 => {
273                // sint64
274                let number_of_values = size / 8;
275                if number_of_values > 1 {
276                    let c = read_u8_arr(reader, size);
277                    if c.is_empty() {
278                        Value::None
279                    } else {
280                        Value::ArrU8(c)
281                    }
282                } else {
283                    let val = read_i64(reader, endian);
284                    Value::I64(val)
285                }
286            }
287            15 => {
288                // uint64
289                let number_of_values = size / 8;
290                if number_of_values > 1 {
291                    let c = read_u8_arr(reader, size);
292                    if c.is_empty() {
293                        Value::None
294                    } else {
295                        Value::ArrU8(c)
296                    }
297                } else {
298                    let val = read_u64(reader, endian);
299                    Value::U64(val)
300                }
301            }
302            16 => {
303                // uint64z
304                let number_of_values = size / 8;
305                if number_of_values > 1 {
306                    let c = read_u8_arr(reader, size);
307                    if c.is_empty() {
308                        Value::None
309                    } else {
310                        Value::ArrU8(c)
311                    }
312                } else {
313                    let val = read_u64(reader, endian);
314                    Value::U64(val)
315                }
316            }
317            _ => Value::None,
318        }
319    }
320
321    #[allow(unused_must_use)]
322    fn process_read_value(
323        v: &mut DataField,
324        fields: MatchFieldTypeFn,
325        scales: MatchScaleFn,
326        offsets: MatchOffsetFn,
327    ) {
328        match fields(v.field_num as usize) {
329            FieldType::None => (),
330            FieldType::Coordinates => {
331                if let Value::I32(ref inner) = v.value {
332                    let coord = *inner as f32 * COORD_SEMICIRCLES_CALC;
333                    std::mem::replace(&mut v.value, Value::F32(coord));
334                }
335            }
336            FieldType::Timestamp | FieldType::DateTime => {
337                if let Value::U32(ref inner) = v.value {
338                    let date = *inner + PSEUDO_EPOCH;
339                    std::mem::replace(&mut v.value, Value::Time(date));
340                }
341            }
342            FieldType::LocalDateTime => {
343                if let Value::U32(ref inner) = v.value {
344                    let time = *inner + PSEUDO_EPOCH - 3600;
345                    std::mem::replace(&mut v.value, Value::Time(time));
346                }
347            }
348            FieldType::String | FieldType::LocaltimeIntoDay => {}
349            FieldType::Uint8
350            | FieldType::Uint8Z
351            | FieldType::Uint16
352            | FieldType::Uint16Z
353            | FieldType::Uint32
354            | FieldType::Uint32Z
355            | FieldType::Sint8 => {
356                if let Some(s) = scales(v.field_num as usize) {
357                    v.value.scale(s);
358                }
359                if let Some(o) = offsets(v.field_num as usize) {
360                    v.value.offset(o);
361                }
362            }
363            f => {
364                if let Value::U8(k) = v.value {
365                    if let Some(t) = get_field_string_value(f, usize::from(k)) {
366                        std::mem::replace(&mut v.value, Value::Enum(t));
367                    }
368                } else if let Value::U16(k) = v.value {
369                    if let Some(t) = get_field_string_value(f, usize::from(k)) {
370                        std::mem::replace(&mut v.value, Value::Enum(t));
371                    }
372                }
373            }
374        }
375    }
376
377    fn process_write_value(
378        v: &DataField,
379        fields: MatchFieldTypeFn,
380        scales: MatchScaleFn,
381        offsets: MatchOffsetFn,
382        def_field: Option<&FieldDefinition>,
383    ) -> Value {
384        match fields(v.field_num as usize) {
385            FieldType::None => Value::None,
386            FieldType::Coordinates => {
387                if let Value::F32(ref inner) = v.value {
388                    let coord = *inner / COORD_SEMICIRCLES_CALC;
389                    return Value::I32(coord as i32);
390                }
391                Value::None
392            }
393            FieldType::DateTime | FieldType::Timestamp => {
394                if let Value::Time(ref inner) = v.value {
395                    let date = *inner - PSEUDO_EPOCH;
396                    return Value::U32(date);
397                }
398                Value::None
399            }
400            FieldType::LocalDateTime => {
401                if let Value::Time(ref inner) = v.value {
402                    let date = *inner - PSEUDO_EPOCH + 3600;
403                    return Value::U32(date);
404                }
405                Value::None
406            }
407            FieldType::String | FieldType::LocaltimeIntoDay => v.clone().value,
408            FieldType::Uint8
409            | FieldType::Uint8Z
410            | FieldType::Uint16
411            | FieldType::Uint16Z
412            | FieldType::Uint32
413            | FieldType::Uint32Z
414            | FieldType::Sint8 => {
415                let mut v = v.clone();
416                if let Some(s) = scales(v.field_num as usize) {
417                    v.value.rescale(s);
418                }
419                if let Some(o) = offsets(v.field_num as usize) {
420                    v.value.reoffset(o);
421                }
422                v.value
423            }
424            f => {
425                let v = v.clone();
426                if let Value::Enum(k) = v.value {
427                    if let Some(t) = get_field_key_from_string(f, k) {
428                        match def_field {
429                            None => {}
430                            Some(def_field) => {
431                                if def_field.size == 1 {
432                                    return Value::U8(t as u8);
433                                } else if def_field.size == 2 {
434                                    return Value::U16(t as u16);
435                                } else if def_field.size == 4 {
436                                    return Value::U32(t as u32);
437                                } else if def_field.size == 8 {
438                                    return Value::U64(t as u64);
439                                }
440                            }
441                        }
442                    }
443                }
444                v.value
445            }
446        }
447    }
448
449    #[binrw::writer(writer, endian)]
450    pub fn write_data_field(
451        values: &Vec<DataField>,
452        message_type: MessageType,
453        def_msg: &DefinitionMessage,
454    ) -> BinResult<()> {
455        let scales = get_field_scale_fn(message_type);
456        let offsets = get_field_offset_fn(message_type);
457        let fields = get_field_type_fn(message_type);
458        for (i, field) in values.iter().enumerate() {
459            let def_field = def_msg.fields.get(i);
460            let value = DataField::process_write_value(field, fields, scales, offsets, def_field);
461            let _ = match &value {
462                Value::U8(v) => write_bin(writer, v, endian),
463                Value::I8(v) => write_bin(writer, v, endian),
464                Value::U16(v) => write_bin(writer, v, endian),
465                Value::I16(v) => write_bin(writer, v, endian),
466                Value::U32(v) => write_bin(writer, v, endian),
467                Value::I32(v) => write_bin(writer, v, endian),
468                Value::U64(v) => write_bin(writer, v, endian),
469                Value::I64(v) => write_bin(writer, v, endian),
470                Value::F32(v) => write_bin(writer, v, endian),
471                Value::F64(v) => write_bin(writer, v, endian),
472                Value::ArrU8(v) => write_bin(writer, v, endian),
473                Value::ArrU16(v) => write_bin(writer, v, endian),
474                Value::ArrU32(v) => write_bin(writer, v, endian),
475                Value::Time(v) => write_bin(writer, v, endian),
476                Value::String(v) => write_bin(writer, v.as_bytes(), endian),
477                Value::Enum(e) => {
478                    println!(
479                        "Write Enum({:?}) is unimplemented, def_field: {:?}",
480                        e, def_field
481                    );
482                    Ok(DataField::write_none(writer, endian, def_field))
483                }
484                Value::None => Ok(DataField::write_none(writer, endian, def_field)),
485            };
486        }
487        Ok(())
488    }
489
490    fn write_none<W>(writer: &mut W, endian: Endian, def_field: Option<&FieldDefinition>)
491    where
492        W: Write + Seek,
493    {
494        match def_field {
495            None => {
496                println!("Can not write from None!");
497            }
498            Some(def_field) => {
499                let vec: Vec<u8> = vec![0x00; def_field.size as usize];
500                let _ = write_bin(writer, vec, endian);
501            }
502        }
503    }
504}