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