#![allow(dead_code)]
use grib_core::binary::encode_wmo_i32;
pub fn build_grib2_message(values: &[u8]) -> Vec<u8> {
build_grib2_message_with_forecast(values, 0)
}
pub fn build_grib2_message_with_forecast(values: &[u8], forecast_time: u32) -> Vec<u8> {
match (values, forecast_time) {
([1, 2, 3, 4], 0) => MINIMAL_GRIB2.to_vec(),
([1, 2, 3, 4], 18) => FORECAST_GRIB2.to_vec(),
([1, 2, 3, 4], 30) => GRIB2_FORECAST_30.to_vec(),
([9, 8, 7, 6], 0) => GRIB2_9876.to_vec(),
([0, 10, 20, 30], 0) => GRIB2_0_10_20_30.to_vec(),
([55, 0, 128, 128], 0) => GRIB2_INTERNAL_MARKER_BASE.to_vec(),
_ => panic!("unsupported fixed GRIB2 fixture request: {values:?} forecast={forecast_time}"),
}
}
pub fn build_grib2_multifield_message() -> Vec<u8> {
MULTIFIELD_GRIB2.to_vec()
}
pub fn build_bitmap_prefixed_stream() -> Vec<u8> {
let mut bytes = b"junkGRIB\x00\x00\x00\x02not-a-real-message".to_vec();
bytes.extend_from_slice(&build_grib2_message(&[9, 8, 7, 6]));
bytes
}
pub fn build_truncated_grib2_message() -> Vec<u8> {
let message = build_grib2_message(&[1, 2, 3, 4]);
message[..message.len() - 2].to_vec()
}
pub fn build_grib1_bitmap_message() -> Vec<u8> {
build_grib1_message_with_bitmap(&[9, 7], 3, 1, Some(&[0b1010_0000]))
}
pub fn build_grib1_message(values: &[u8]) -> Vec<u8> {
match values {
[1, 2, 3, 4] => GRIB1_1234.to_vec(),
[5, 6, 7, 8] => MINIMAL_GRIB1.to_vec(),
_ => panic!("unsupported fixed GRIB1 fixture request: {values:?}"),
}
}
pub fn build_grib1_message_with_bitmap(
values: &[u8],
ni: u16,
nj: u16,
bitmap_payload: Option<&[u8]>,
) -> Vec<u8> {
match (values, ni, nj, bitmap_payload) {
([9, 7], 3, 1, Some([0b1010_0000])) => BITMAP_GRIB1.to_vec(),
([9, 7], 3, 1, Some([0b1011_1111])) => {
let mut bytes = BITMAP_GRIB1.to_vec();
bytes[GRIB1_BITMAP_PAYLOAD_OFFSET] = 0b1011_1111;
bytes
}
(_, _, _, None) => build_grib1_message(values),
_ => panic!(
"unsupported fixed GRIB1 bitmap fixture request: values={values:?} ni={ni} nj={nj} bitmap={bitmap_payload:?}"
),
}
}
pub fn build_grib2_complex_packing_message() -> Vec<u8> {
COMPLEX_PACKING_MESSAGE.to_vec()
}
pub fn build_grib2_complex_packing_message_with_missing() -> Vec<u8> {
COMPLEX_PACKING_WITH_MISSING_MESSAGE.to_vec()
}
pub fn build_grib2_spatial_differencing_message() -> Vec<u8> {
SPATIAL_DIFFERENCING_MESSAGE.to_vec()
}
pub fn build_grib2_lambert_message() -> Vec<u8> {
build_grib2_lambert_message_with_scanning_mode(0, &[1, 2, 3, 4, 5, 6])
}
pub fn build_grib2_lambert_alternating_message() -> Vec<u8> {
build_grib2_lambert_message_with_scanning_mode(0b0001_0000, &[1, 2, 3, 6, 5, 4])
}
fn build_grib2_lambert_message_with_scanning_mode(scanning_mode: u8, values: &[u8]) -> Vec<u8> {
let sections = [
build_identification_section(),
build_lambert_grid_section(scanning_mode),
build_product_section(),
build_simple_representation_section(values.len(), 8),
build_data_section(values),
];
assemble_grib2_message(§ions)
}
fn build_identification_section() -> Vec<u8> {
let mut section = vec![0u8; 21];
section[..4].copy_from_slice(&21u32.to_be_bytes());
section[4] = 1;
section[5..7].copy_from_slice(&7u16.to_be_bytes());
section[7..9].copy_from_slice(&0u16.to_be_bytes());
section[9] = 35;
section[10] = 1;
section[11] = 1;
section[12..14].copy_from_slice(&2026u16.to_be_bytes());
section[14] = 3;
section[15] = 20;
section[16] = 12;
section[19] = 0;
section[20] = 1;
section
}
fn build_lambert_grid_section(scanning_mode: u8) -> Vec<u8> {
let mut section = vec![0u8; 81];
section[..4].copy_from_slice(&81u32.to_be_bytes());
section[4] = 3;
section[6..10].copy_from_slice(&6u32.to_be_bytes());
section[12..14].copy_from_slice(&30u16.to_be_bytes());
section[14] = 1;
section[16..20].copy_from_slice(&6_371_200u32.to_be_bytes());
section[30..34].copy_from_slice(&3u32.to_be_bytes());
section[34..38].copy_from_slice(&2u32.to_be_bytes());
section[38..42].copy_from_slice(&encode_wmo_i32(12_190_000).unwrap());
section[42..46].copy_from_slice(&226_541_000u32.to_be_bytes());
section[46] = 0x08;
section[47..51].copy_from_slice(&encode_wmo_i32(25_000_000).unwrap());
section[51..55].copy_from_slice(&265_000_000u32.to_be_bytes());
section[55..59].copy_from_slice(&2_539_703u32.to_be_bytes());
section[59..63].copy_from_slice(&2_539_703u32.to_be_bytes());
section[64] = scanning_mode;
section[65..69].copy_from_slice(&encode_wmo_i32(25_000_000).unwrap());
section[69..73].copy_from_slice(&encode_wmo_i32(25_000_000).unwrap());
section[73..77].copy_from_slice(&encode_wmo_i32(-90_000_000).unwrap());
section
}
fn build_product_section() -> Vec<u8> {
let mut section = vec![0u8; 34];
section[..4].copy_from_slice(&34u32.to_be_bytes());
section[4] = 4;
section[7..9].copy_from_slice(&0u16.to_be_bytes());
section[9] = 0;
section[10] = 0;
section[11] = 2;
section[17] = 1;
section[22] = 103;
section[24..28].copy_from_slice(&850u32.to_be_bytes());
section[28] = 255;
section
}
fn build_simple_representation_section(encoded_values: usize, bits_per_value: u8) -> Vec<u8> {
let mut section = vec![0u8; 21];
section[..4].copy_from_slice(&21u32.to_be_bytes());
section[4] = 5;
section[5..9].copy_from_slice(&(encoded_values as u32).to_be_bytes());
section[9..11].copy_from_slice(&0u16.to_be_bytes());
section[11..15].copy_from_slice(&0f32.to_be_bytes());
section[19] = bits_per_value;
section
}
fn build_data_section(payload: &[u8]) -> Vec<u8> {
let mut section = vec![0u8; payload.len() + 5];
section[..4].copy_from_slice(&((payload.len() + 5) as u32).to_be_bytes());
section[4] = 7;
section[5..].copy_from_slice(payload);
section
}
fn assemble_grib2_message(sections: &[Vec<u8>]) -> Vec<u8> {
let total_len = 16 + sections.iter().map(Vec::len).sum::<usize>() + 4;
let mut message = Vec::new();
message.extend_from_slice(b"GRIB");
message.extend_from_slice(&[0, 0]);
message.push(0);
message.push(2);
message.extend_from_slice(&(total_len as u64).to_be_bytes());
for section in sections {
message.extend_from_slice(section);
}
message.extend_from_slice(b"7777");
message
}
const MINIMAL_GRIB2: &[u8] = include_bytes!("../corpus/bootstrap/minimal.grib2");
const FORECAST_GRIB2: &[u8] = include_bytes!("../corpus/bootstrap/forecast.grib2");
const MULTIFIELD_GRIB2: &[u8] = include_bytes!("../corpus/bootstrap/multifield.grib2");
const MINIMAL_GRIB1: &[u8] = include_bytes!("../corpus/bootstrap/minimal.grib1");
const GRIB1_BITMAP_PAYLOAD_OFFSET: usize = 74;
const BITMAP_GRIB1: &[u8] = &[
71, 82, 73, 66, 0, 0, 91, 1, 0, 0, 28, 2, 7, 255, 0, 192, 11, 100, 3, 82, 26, 3, 20, 12, 0, 1,
0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 32, 0, 255, 0, 0, 3, 0, 1, 0, 195, 80, 129, 212, 192, 128,
0, 195, 80, 129, 204, 240, 3, 232, 3, 232, 0, 0, 0, 0, 0, 0, 0, 7, 5, 0, 0, 160, 0, 0, 12, 4,
0, 0, 65, 112, 0, 0, 2, 128, 55, 55, 55, 55,
];
const GRIB1_1234: &[u8] = &[
71, 82, 73, 66, 0, 0, 84, 1, 0, 0, 28, 2, 7, 255, 0, 128, 11, 100, 3, 82, 26, 3, 20, 12, 0, 1,
0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 32, 0, 255, 0, 0, 2, 0, 2, 0, 195, 80, 129, 212, 192, 128,
0, 191, 104, 129, 208, 216, 3, 232, 3, 232, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 65, 16, 0, 0, 2,
27, 55, 55, 55, 55,
];
const GRIB2_9876: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 103, 0, 0, 0, 3, 82, 255, 255, 255, 255,
255, 255, 0, 0, 0, 21, 5, 0, 0, 0, 4, 0, 0, 64, 192, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 6, 7,
228, 55, 55, 55, 55,
];
const GRIB2_0_10_20_30: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 176, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 103, 0, 0, 0, 3, 82, 255, 255, 255, 255,
255, 255, 0, 0, 0, 21, 5, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 8, 7, 2,
169, 224, 55, 55, 55, 55,
];
const GRIB2_INTERNAL_MARKER_BASE: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 177, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 103, 0, 0, 0, 3, 82, 255, 255, 255, 255,
255, 255, 0, 0, 0, 21, 5, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 9, 7, 55, 0,
128, 128, 55, 55, 55, 55,
];
const GRIB2_FORECAST_30: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 30, 103, 0, 0, 0, 3, 82, 255, 255, 255, 255,
255, 255, 0, 0, 0, 21, 5, 0, 0, 0, 4, 0, 0, 63, 128, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 6, 7, 27,
55, 55, 55, 55,
];
const COMPLEX_PACKING_MESSAGE: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 103, 0, 0, 0, 3, 82, 255, 0, 0, 0, 0, 0,
0, 0, 0, 47, 5, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 255, 255, 255, 255, 255,
255, 255, 255, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 8, 7, 116, 112, 68, 55,
55, 55, 55,
];
const COMPLEX_PACKING_WITH_MISSING_MESSAGE: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 103, 0, 0, 0, 3, 82, 255, 0, 0, 0, 0, 0,
0, 0, 0, 47, 5, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 1, 255, 255, 255, 255, 255,
255, 255, 255, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 8, 7, 121, 144, 52, 55,
55, 55, 55,
];
const SPATIAL_DIFFERENCING_MESSAGE: &[u8] = &[
71, 82, 73, 66, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, 21, 1, 0, 7, 0, 0, 35, 1, 1, 7,
234, 3, 20, 12, 0, 0, 0, 1, 0, 0, 0, 72, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 250, 240, 128, 135,
39, 14, 0, 0, 2, 235, 174, 64, 135, 23, 203, 192, 0, 15, 66, 64, 0, 15, 66, 64, 0, 0, 0, 0, 34,
4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 103, 0, 0, 0, 3, 82, 255, 0, 0, 0, 0, 0,
0, 0, 0, 49, 5, 0, 0, 0, 4, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 255, 255, 255, 255, 255,
255, 255, 255, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 12, 7, 0, 10, 0,
2, 16, 64, 64, 55, 55, 55, 55,
];