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