1pub use multigrid::*;
2pub use multiproduct::*;
3pub use single::*;
4
5use super::GpvEncoder;
6use crate::WriteToBuffer;
7
8const SECT0_LEN: usize = 16;
9
10pub 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
62pub 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
99pub 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
133pub 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
160pub trait WriteGrib2Ident {
278 fn section1_len(&self) -> usize;
279
280 fn write_section1(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
281}
282
283pub trait WriteGrib2LocalUse {
286 fn section2_len(&self) -> usize;
287
288 fn write_section2(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
289}
290
291pub trait WriteGrib2GridDef {
294 fn section3_len(&self) -> usize;
295
296 fn write_section3(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
297}
298
299pub trait WriteGrib2ProductDef {
302 fn section4_len(&self) -> usize;
303
304 fn write_section4(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
305}
306
307pub 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
316macro_rules! add_impl_for_u8_slices {
317 ($(($trait:ty,$len_method:ident,$write_method:ident,$sect_num:expr),)*) => ($(
318 impl<T: AsRef<[u8]>> $trait for T {
319 fn $len_method(&self) -> usize {
320 self.as_ref().len() + 5
321 }
322
323 fn $write_method(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
324 let len = self.$len_method();
325 if buf.len() < len {
326 return Err("destination buffer is too small");
327 }
328
329 let mut pos = 0;
330 pos += write_section_header(len as u32, $sect_num, &mut buf[pos..])?;
331 buf[pos..len].copy_from_slice(self.as_ref());
332 Ok(len)
333 }
334 }
335 )*);
336}
337
338add_impl_for_u8_slices![
339 (WriteGrib2Ident, section1_len, write_section1, 1),
340 (WriteGrib2LocalUse, section2_len, write_section2, 2),
341 (WriteGrib2GridDef, section3_len, write_section3, 3),
342 (WriteGrib2ProductDef, section4_len, write_section4, 4),
343];
344
345macro_rules! add_impl_for_payload_structs {
346 ($(($trait:ty,$ty:ty,$len_method:ident,$write_method:ident,$sect_num:expr),)*) => ($(
347 impl $trait for $ty {
348 fn $len_method(&self) -> usize {
349 self.num_bytes_required() + 5
350 }
351
352 fn $write_method(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
353 let len = self.$len_method();
354 if buf.len() < len {
355 return Err("destination buffer is too small");
356 }
357
358 let mut pos = 0;
359 pos += write_section_header(len as u32, $sect_num, &mut buf[pos..])?;
360 pos += self.write_to_buffer(&mut buf[pos..])?;
361 Ok(pos)
362 }
363 }
364 )*);
365}
366
367add_impl_for_payload_structs![
368 (
369 WriteGrib2Ident,
370 crate::def::grib2::Section1Payload,
371 section1_len,
372 write_section1,
373 1
374 ),
375 (
376 WriteGrib2GridDef,
377 crate::def::grib2::Section3Payload,
378 section3_len,
379 write_section3,
380 3
381 ),
382];
383
384pub trait WriteGrib2DataSections {
387 fn section5_len(&self) -> usize;
389
390 fn write_section5(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
392
393 fn section6_len(&self) -> usize;
395
396 fn write_section6(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
398
399 fn section7_len(&self) -> usize;
401
402 fn write_section7(&self, buf: &mut [u8]) -> Result<usize, &'static str>;
404}
405
406fn write_section0(
407 discipline: u8,
408 reserved: [u8; 2],
409 len: usize,
410 buf: &mut [u8],
411) -> Result<usize, &'static str> {
412 if buf.len() < SECT0_LEN {
413 return Err("destination buffer is too small");
414 }
415
416 let sect = crate::def::grib2::Section0 {
417 identifier: [0x47, 0x52, 0x49, 0x42],
418 reserved,
419 discipline,
420 edition_num: 2,
421 total_len: len as u64,
422 };
423
424 let mut pos = 0;
425 pos += sect.write_to_buffer(&mut buf[pos..])?;
426 Ok(pos)
427}
428
429fn write_section8(buf: &mut [u8]) -> Result<usize, &'static str> {
430 const SIGNATURE: [u8; 4] = [0x37, 0x37, 0x37, 0x37];
431 if buf.len() < SIGNATURE.num_bytes_required() {
432 return Err("destination buffer is too small");
433 }
434 SIGNATURE.write_to_buffer(buf)
435}
436
437pub(crate) fn write_section_header(
438 len: u32,
439 sect_num: u8,
440 buf: &mut [u8],
441) -> Result<usize, &'static str> {
442 crate::def::grib2::SectionHeader { len, sect_num }.write_to_buffer(buf)
443}
444
445impl<'a, 'd, P> WriteGrib2MessageIterL3 for (&'a P, &'a GpvEncoder<'d>)
446where
447 P: WriteGrib2ProductDef,
448{
449 type S4<'s>
450 = P
451 where
452 Self: 's;
453
454 type SD<'s>
455 = GpvEncoder<'d>
456 where
457 Self: 's;
458
459 fn section4(&self) -> &Self::S4<'_> {
460 self.0
461 }
462
463 fn data_sections(&self) -> &Self::SD<'_> {
464 self.1
465 }
466}
467
468mod multigrid;
469mod multiproduct;
470mod single;