1#[derive(Debug, Clone)]
5pub struct Indicator {
6 pub edition: u8,
8 pub discipline: u8,
10 pub total_length: u64,
12}
13
14impl Indicator {
15 pub fn parse(data: &[u8]) -> Option<Self> {
17 if data.len() < 8 || &data[0..4] != b"GRIB" {
18 return None;
19 }
20
21 let edition = data[7];
22 match edition {
23 1 => {
24 let length = ((data[4] as u64) << 16) | ((data[5] as u64) << 8) | (data[6] as u64);
25 Some(Self {
26 edition,
27 discipline: 0,
28 total_length: length,
29 })
30 }
31 2 => {
32 if data.len() < 16 {
33 return None;
34 }
35 let discipline = data[6];
36 let length = u64::from_be_bytes(data[8..16].try_into().ok()?);
37 Some(Self {
38 edition,
39 discipline,
40 total_length: length,
41 })
42 }
43 _ => None,
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn parse_grib2_indicator() {
54 let mut data = Vec::new();
55 data.extend_from_slice(b"GRIB");
56 data.extend_from_slice(&[0, 0]);
57 data.push(0); data.push(2); data.extend_from_slice(&100u64.to_be_bytes());
60 let ind = Indicator::parse(&data).unwrap();
61 assert_eq!(ind.edition, 2);
62 assert_eq!(ind.discipline, 0);
63 assert_eq!(ind.total_length, 100);
64 }
65
66 #[test]
67 fn parse_grib1_indicator() {
68 let mut data = vec![0u8; 8];
69 data[0..4].copy_from_slice(b"GRIB");
70 data[4] = 0;
71 data[5] = 3;
72 data[6] = 232; data[7] = 1;
74 let ind = Indicator::parse(&data).unwrap();
75 assert_eq!(ind.edition, 1);
76 assert_eq!(ind.total_length, 1000);
77 }
78
79 #[test]
80 fn reject_invalid_magic() {
81 assert!(Indicator::parse(b"NOPE1234").is_none());
82 }
83}