grib/encoder/message.rs
1pub use multigrid::*;
2pub use multiproduct::*;
3pub use single::*;
4
5use super::GpvEncoder;
6use crate::WriteToBuffer;
7
8const SECT0_LEN: usize = 16;
9
10/// A functionality to write an entire GRIB2 message. This trait works in
11/// conjunction with [`WriteGrib2MessageIterL1`], [`WriteGrib2MessageIterL2`],
12/// and [`WriteGrib2MessageIterL3`] to write the message.
13pub trait WriteGrib2Message {
14 type S1<'a>: WriteGrib2Ident
15 where
16 Self: 'a;
17
18 type Item<'a>: WriteGrib2MessageIterL1
19 where
20 Self: 'a;
21
22 type Iter<'a>: Iterator<Item = Self::Item<'a>>
23 where
24 Self: 'a;
25
26 fn discipline(&self) -> u8;
27 fn reserved(&self) -> [u8; 2] {
28 [0xff, 0xff]
29 }
30 fn section1(&self) -> &Self::S1<'_>;
31 fn iter(&self) -> Self::Iter<'_>;
32
33 fn num_octets(&self) -> usize {
34 SECT0_LEN
35 + self.section1().section1_len()
36 + self.iter().map(|m| m.num_octets()).sum::<usize>()
37 + crate::SECT8_ES_SIZE
38 }
39
40 fn write(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
41 let total_len = self.num_octets();
42 if buf.len() < total_len {
43 return Err("destination buffer is too small");
44 }
45
46 let mut pos = 0;
47 pos += write_section0(
48 self.discipline(),
49 self.reserved(),
50 total_len,
51 &mut buf[pos..],
52 )?;
53 pos += self.section1().write_section1(&mut buf[pos..])?;
54 for m in self.iter() {
55 pos += m.write(&mut buf[pos..])?;
56 }
57 pos += write_section8(&mut buf[pos..])?;
58 Ok(pos)
59 }
60}
61
62/// A functionality to write elements of the L1 iterator in a GRIB2 message.
63/// This trait works in conjunction with [`WriteGrib2Message`],
64/// [`WriteGrib2MessageIterL2`], and [`WriteGrib2MessageIterL3`] to write the
65/// message.
66pub trait WriteGrib2MessageIterL1 {
67 type S2<'a>: WriteGrib2LocalUse
68 where
69 Self: 'a;
70
71 type Item<'a>: WriteGrib2MessageIterL2
72 where
73 Self: 'a;
74
75 type Iter<'a>: Iterator<Item = Self::Item<'a>>
76 where
77 Self: 'a;
78
79 fn section2(&self) -> Option<&Self::S2<'_>>;
80 fn iter(&self) -> Self::Iter<'_>;
81
82 fn num_octets(&self) -> usize {
83 self.section2().map_or(0, |m| m.section2_len())
84 + self.iter().map(|m| m.num_octets()).sum::<usize>()
85 }
86
87 fn write(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
88 let mut pos = 0;
89 if let Some(section2) = self.section2() {
90 pos += section2.write_section2(&mut buf[pos..])?;
91 }
92 for m in self.iter() {
93 pos += m.write(&mut buf[pos..])?;
94 }
95 Ok(pos)
96 }
97}
98
99/// A functionality to write elements of the L2 iterator in a GRIB2 message.
100/// This trait works in conjunction with [`WriteGrib2Message`],
101/// [`WriteGrib2MessageIterL1`], and [`WriteGrib2MessageIterL3`] to write the
102/// message.
103pub trait WriteGrib2MessageIterL2 {
104 type S3<'a>: WriteGrib2GridDef
105 where
106 Self: 'a;
107
108 type Item<'a>: WriteGrib2MessageIterL3
109 where
110 Self: 'a;
111
112 type Iter<'a>: Iterator<Item = Self::Item<'a>>
113 where
114 Self: 'a;
115
116 fn section3(&self) -> &Self::S3<'_>;
117 fn iter(&self) -> Self::Iter<'_>;
118
119 fn num_octets(&self) -> usize {
120 self.section3().section3_len() + self.iter().map(|m| m.num_octets()).sum::<usize>()
121 }
122
123 fn write(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
124 let mut pos = 0;
125 pos += self.section3().write_section3(&mut buf[pos..])?;
126 for m in self.iter() {
127 pos += m.write(&mut buf[pos..])?;
128 }
129 Ok(pos)
130 }
131}
132
133/// A functionality to write elements of the L3 iterator in a GRIB2 message.
134/// This trait works in conjunction with [`WriteGrib2Message`],
135/// [`WriteGrib2MessageIterL1`], and [`WriteGrib2MessageIterL2`] to write the
136/// message.
137pub trait WriteGrib2MessageIterL3 {
138 type S4<'a>: WriteGrib2ProductDef
139 where
140 Self: 'a;
141 type SD<'a>: WriteGrib2PointValues
142 where
143 Self: 'a;
144
145 fn section4(&self) -> &Self::S4<'_>;
146 fn data_sections(&self) -> &Self::SD<'_>;
147
148 fn num_octets(&self) -> usize {
149 self.section4().section4_len() + self.data_sections().data_sections_len()
150 }
151
152 fn write(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
153 let mut pos = 0;
154 pos += self.section4().write_section4(&mut buf[pos..])?;
155 pos += self.data_sections().write_data_sections(&mut buf[pos..])?;
156 Ok(pos)
157 }
158}
159
160/// A functionality to write the byte sequence of Section 1 (Identification
161/// Section) of a GRIB2 message.
162///
163/// # Examples
164///
165/// This trait is implemented for the payload struct of Section 1
166/// ([`def::grib2::Section1Payload`](crate::def::grib2::Section1Payload)).
167///
168/// ```
169/// use grib::{TryFromSlice, def::grib2, encoder::WriteGrib2Ident};
170///
171/// fn main() -> Result<(), Box<dyn std::error::Error>> {
172/// let sect = grib2::Section1 {
173/// header: grib2::SectionHeader {
174/// len: 21,
175/// sect_num: 1,
176/// },
177/// payload: grib2::Section1Payload {
178/// centre_id: 0xffff,
179/// subcentre_id: 0,
180/// master_table_version: 29,
181/// local_table_version: 0,
182/// ref_time_significance: 0,
183/// ref_time: grib2::template::param_set::DateTime {
184/// year: 2026,
185/// month: 1,
186/// day: 2,
187/// hour: 3,
188/// minute: 4,
189/// second: 5,
190/// },
191/// prod_status: 0,
192/// data_type: 0,
193/// optional: None,
194/// },
195/// };
196/// let mut buf = vec![0; sect.payload.section1_len()];
197/// sect.payload.write_section1(&mut buf)?;
198/// let decoded = grib2::Section1::try_from_slice(&buf, &mut 0);
199/// assert_eq!(decoded, Ok(sect));
200///
201/// Ok(())
202/// }
203/// ```
204///
205/// This trait is also implemented for the byte sequence of the payload of
206/// Section 1.
207///
208/// ```
209/// use grib::{TryFromSlice, def::grib2, encoder::WriteGrib2Ident};
210///
211/// fn main() -> Result<(), Box<dyn std::error::Error>> {
212/// let mut input = [
213/// 0xff, 0xff, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x07, 0xea, 0x01, 0x02, 0x03, 0x04, 0x05,
214/// 0x00, 0x00,
215/// ];
216/// let mut buf = vec![0; input.section1_len()];
217/// input.write_section1(&mut buf)?;
218///
219/// // The output is simply the input byte sequence with a section header appended to it.
220/// assert_eq!(&buf[5..], input);
221///
222/// let decoded = grib2::Section1::try_from_slice(&buf, &mut 0);
223/// let expected = Ok(grib2::Section1 {
224/// header: grib2::SectionHeader {
225/// len: 21,
226/// sect_num: 1,
227/// },
228/// payload: grib2::Section1Payload {
229/// centre_id: 0xffff,
230/// subcentre_id: 0,
231/// master_table_version: 29,
232/// local_table_version: 0,
233/// ref_time_significance: 0,
234/// ref_time: grib2::template::param_set::DateTime {
235/// year: 2026,
236/// month: 1,
237/// day: 2,
238/// hour: 3,
239/// minute: 4,
240/// second: 5,
241/// },
242/// prod_status: 0,
243/// data_type: 0,
244/// optional: None,
245/// },
246/// });
247/// assert_eq!(decoded, expected);
248///
249/// Ok(())
250/// }
251/// ```
252///
253/// Since no constraints can be placed on the byte sequence, `write_section1`
254/// can, of course, be executed on any byte sequence; however, if it is executed
255/// on an inappropriate byte sequence, the resulting byte sequence will not be
256/// correctly interpreted as Section 1.
257///
258/// ```
259/// use grib::{TryFromSlice, def::grib2, encoder::WriteGrib2Ident};
260///
261/// fn main() -> Result<(), Box<dyn std::error::Error>> {
262/// let mut input = [0xff, 0xff];
263/// let mut buf = vec![0; input.section1_len()];
264/// input.write_section1(&mut buf)?;
265///
266/// // The output is simply the input byte sequence with a section header appended to it.
267/// assert_eq!(&buf[5..], input);
268///
269/// // The output cannot be correctly interpreted as Section 1.
270/// let decoded = grib2::Section1::try_from_slice(&buf, &mut 0);
271/// let expected = Err("slice length is too short");
272/// assert_eq!(decoded, expected);
273///
274/// Ok(())
275/// }
276/// ```
277pub trait WriteGrib2Ident {
278 fn section1_len(&self) -> usize;
279
280 fn write_section1(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
281}
282
283/// A functionality to write the byte sequence of Section 2 (Local Use Section)
284/// of a GRIB2 message.
285pub trait WriteGrib2LocalUse {
286 fn section2_len(&self) -> usize;
287
288 fn write_section2(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
289}
290
291/// A functionality to write the byte sequence of Section 3 (Grid Definition
292/// Section) of a GRIB2 message.
293pub trait WriteGrib2GridDef {
294 fn section3_len(&self) -> usize;
295
296 fn write_section3(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
297}
298
299/// A functionality to write the byte sequence of Section 4 (Product Definition
300/// Section) of a GRIB2 message.
301pub trait WriteGrib2ProductDef {
302 fn section4_len(&self) -> usize;
303
304 fn write_section4(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
305}
306
307/// A functionality to write the byte sequence of Section 5 (Data
308/// Representation Section), Section 6 (Bit-map section), and Section 7 (Data
309/// Section) of a GRIB2 message.
310pub trait WriteGrib2PointValues {
311 fn data_sections_len(&self) -> usize;
312
313 fn write_data_sections(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
314}
315
316/// A serializer that writes the byte sequence of sections concerning GPV data
317/// to the output buffer.
318pub trait WriteGrib2DataSections {
319 /// Returns the length of the byte sequence in Section 5.
320 fn section5_len(&self) -> usize;
321
322 /// Writes the byte sequence of Section 5 to the output buffer.
323 fn write_section5(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
324
325 /// Returns the length of the byte sequence in Section 6.
326 fn section6_len(&self) -> usize;
327
328 /// Writes the byte sequence of Section 6 to the output buffer.
329 fn write_section6(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
330
331 /// Returns the length of the byte sequence in Section 7.
332 fn section7_len(&self) -> usize;
333
334 /// Writes the byte sequence of Section 7 to the output buffer.
335 fn write_section7(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
336}
337
338fn write_section0(
339 discipline: u8,
340 reserved: [u8; 2],
341 len: usize,
342 buf: &mut [u8],
343) -> Result<usize, &'static str> {
344 if buf.len() < SECT0_LEN {
345 return Err("destination buffer is too small");
346 }
347
348 let sect = crate::def::grib2::Section0 {
349 identifier: [0x47, 0x52, 0x49, 0x42],
350 reserved,
351 discipline,
352 edition_num: 2,
353 total_len: len as u64,
354 };
355
356 let mut pos = 0;
357 pos += sect.write_to_buffer(&mut buf[pos..])?;
358 Ok(pos)
359}
360
361fn write_section8(buf: &mut [u8]) -> Result<usize, &'static str> {
362 const SIGNATURE: [u8; 4] = [0x37, 0x37, 0x37, 0x37];
363 if buf.len() < SIGNATURE.num_bytes_required() {
364 return Err("destination buffer is too small");
365 }
366 SIGNATURE.write_to_buffer(buf)
367}
368
369pub(crate) fn write_section_header(
370 len: u32,
371 sect_num: u8,
372 buf: &mut [u8],
373) -> Result<usize, &'static str> {
374 crate::def::grib2::SectionHeader { len, sect_num }.write_to_buffer(buf)
375}
376
377mod impls;
378mod multigrid;
379mod multiproduct;
380mod single;