1pub use complex::*;
2use grib_template_helpers::WriteToBuffer;
3pub use simple::*;
4
5use crate::def::grib2::template::param_set;
6
7pub fn encode_gpv(data: &[f64], method: EncodingMethod) -> EncodeOutput {
9 let output = match method {
10 EncodingMethod::SimplePacking(simple_packing_strategy) => {
11 let encoder = simple::Encoder::new(data, simple_packing_strategy);
12 EncodeOutputInner::SimplePacking(encoder.encode())
13 }
14 EncodingMethod::ComplexPacking(
15 simple_packing_strategy,
16 complex_packing_strategy,
17 _spatial_differencing_option,
18 ) => {
19 let encoder =
20 complex::Encoder::new(data, simple_packing_strategy, complex_packing_strategy);
21 EncodeOutputInner::ComplexPacking(encoder.encode())
22 }
23 };
24 EncodeOutput(output)
25}
26
27#[derive(Debug, PartialEq, Eq, Clone)]
28pub enum EncodingMethod {
29 SimplePacking(SimplePackingStrategy),
31 ComplexPacking(
33 SimplePackingStrategy,
34 ComplexPackingStrategy,
35 SpatialDifferencingOption,
36 ),
37}
38
39#[derive(Debug)]
42pub struct EncodeOutput(EncodeOutputInner);
43
44impl EncodeOutput {
45 pub fn params(&self) -> EncodeOutputParams<'_> {
47 match &self.0 {
48 EncodeOutputInner::SimplePacking(encoded) => {
49 EncodeOutputParams::SimplePacking(encoded.params())
50 }
51 EncodeOutputInner::ComplexPacking(encoded) => {
52 let (simple, complex) = encoded.params();
53 EncodeOutputParams::ComplexPacking(simple, complex)
54 }
55 }
56 }
57}
58
59impl WriteGrib2DataSections for EncodeOutput {
60 fn section5_len(&self) -> usize {
61 match &self.0 {
62 EncodeOutputInner::SimplePacking(encoded) => encoded.section5_len(),
63 EncodeOutputInner::ComplexPacking(encoded) => encoded.section5_len(),
64 }
65 }
66
67 fn write_section5(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
68 match &self.0 {
69 EncodeOutputInner::SimplePacking(encoded) => encoded.write_section5(buf),
70 EncodeOutputInner::ComplexPacking(encoded) => encoded.write_section5(buf),
71 }
72 }
73
74 fn section6_len(&self) -> usize {
75 match &self.0 {
76 EncodeOutputInner::SimplePacking(encoded) => encoded.section6_len(),
77 EncodeOutputInner::ComplexPacking(encoded) => encoded.section6_len(),
78 }
79 }
80
81 fn write_section6(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
82 match &self.0 {
83 EncodeOutputInner::SimplePacking(encoded) => encoded.write_section6(buf),
84 EncodeOutputInner::ComplexPacking(encoded) => encoded.write_section6(buf),
85 }
86 }
87
88 fn section7_len(&self) -> usize {
89 match &self.0 {
90 EncodeOutputInner::SimplePacking(encoded) => encoded.section7_len(),
91 EncodeOutputInner::ComplexPacking(encoded) => encoded.section7_len(),
92 }
93 }
94
95 fn write_section7(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
96 match &self.0 {
97 EncodeOutputInner::SimplePacking(encoded) => encoded.write_section7(buf),
98 EncodeOutputInner::ComplexPacking(encoded) => encoded.write_section7(buf),
99 }
100 }
101}
102
103pub enum EncodeOutputParams<'a> {
104 SimplePacking(&'a param_set::SimplePacking),
105 ComplexPacking(&'a param_set::SimplePacking, &'a param_set::ComplexPacking),
106}
107
108#[derive(Debug)]
109enum EncodeOutputInner {
110 SimplePacking(simple::Encoded),
111 ComplexPacking(complex::Encoded),
112}
113
114trait Encode {
115 type Output;
116
117 fn encode(&self) -> Self::Output;
118}
119
120pub trait WriteGrib2DataSections {
123 fn section5_len(&self) -> usize;
125
126 fn write_section5(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
128
129 fn section6_len(&self) -> usize;
131
132 fn write_section6(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
134
135 fn section7_len(&self) -> usize;
137
138 fn write_section7(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
140}
141
142pub fn write_section0(discipline: u8, len: usize, buf: &mut [u8]) -> Result<usize, &'static str> {
143 const HEAD: [u8; 6] = [0x47, 0x52, 0x49, 0x42, 0xff, 0xff];
144 const EDITION: u8 = 2;
145 const LEN: usize = 16;
146 if buf.len() < LEN {
147 return Err("destination buffer is too small");
148 }
149
150 let mut pos = 0;
151 pos += HEAD.write_to_buffer(&mut buf[pos..])?;
152 pos += discipline.write_to_buffer(&mut buf[pos..])?;
153 pos += EDITION.write_to_buffer(&mut buf[pos..])?;
154 pos += (len as u64).write_to_buffer(&mut buf[pos..])?;
155 Ok(pos)
156}
157
158pub fn write_section1(
159 payload: &crate::def::grib2::Section1Payload,
160 buf: &mut [u8],
161) -> Result<usize, &'static str> {
162 const LEN: usize = 0x15;
163 if buf.len() < LEN {
164 return Err("destination buffer is too small");
165 }
166
167 let mut pos = 0;
168 pos += (LEN as u32).write_to_buffer(&mut buf[pos..])?;
169 pos += 1_u8.write_to_buffer(&mut buf[pos..])?;
170 pos += payload.write_to_buffer(&mut buf[pos..])?;
171 Ok(pos)
172}
173
174pub fn write_section3(
175 payload: &crate::def::grib2::Section3Payload,
176 buf: &mut [u8],
177) -> Result<usize, &'static str> {
178 let len: usize = 5 + payload.num_bytes_required();
179 if buf.len() < len {
180 return Err("destination buffer is too small");
181 }
182
183 let mut pos = 0;
184 pos += (len as u32).write_to_buffer(&mut buf[pos..])?;
185 pos += 3_u8.write_to_buffer(&mut buf[pos..])?;
186 pos += payload.write_to_buffer(&mut buf[pos..])?;
187 Ok(pos)
188}
189
190pub fn write_section8(buf: &mut [u8]) -> Result<usize, &'static str> {
191 const SIGNATURE: [u8; 4] = [0x37, 0x37, 0x37, 0x37];
192 if buf.len() < SIGNATURE.num_bytes_required() {
193 return Err("destination buffer is too small");
194 }
195 SIGNATURE.write_to_buffer(buf)
196}
197
198mod bitmap;
199mod complex;
200mod helpers;
201mod simple;
202mod writer;
203
204#[cfg(test)]
205mod tests {
206 use grib_template_helpers::TryFromSlice as _;
207
208 use super::*;
209 use crate::def::grib2::Section1;
210
211 #[test]
212 fn grib2_section1_roundtrip_test() -> Result<(), Box<dyn std::error::Error>> {
213 let sect = Section1 {
214 header: crate::def::grib2::SectionHeader {
215 len: 21,
216 sect_num: 1,
217 },
218 payload: crate::def::grib2::Section1Payload {
219 centre_id: 0xffff,
220 subcentre_id: 0,
221 master_table_version: 29,
222 local_table_version: 0,
223 ref_time_significance: 0,
224 ref_time: crate::def::grib2::RefTime {
225 year: 2026,
226 month: 1,
227 day: 2,
228 hour: 3,
229 minute: 4,
230 second: 5,
231 },
232 prod_status: 0,
233 data_type: 0,
234 optional: None,
235 },
236 };
237 let mut buf = vec![0; 21];
238 write_section1(§.payload, &mut buf)?;
239 let decoded = Section1::try_from_slice(&buf, &mut 0)?;
240 assert_eq!(decoded, sect);
241 Ok(())
242 }
243}