1use crate::codec::range_decoder::RangeDecoder;
2use crate::codec::range_encoder::RangeEncoder;
3use crate::error::{FpZipError, Result};
4
5pub const FPZ_MAJ_VERSION: u32 = 0x0110;
7
8pub const FPZ_MIN_VERSION: u32 = 4;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[repr(u8)]
14pub enum FpZipType {
15 Float = 0,
17 Double = 1,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct FpZipHeader {
28 pub data_type: FpZipType,
30 pub prec: u32,
32 pub nx: u32,
34 pub ny: u32,
36 pub nz: u32,
38 pub nf: u32,
40}
41
42impl FpZipHeader {
43 pub fn new(data_type: FpZipType, nx: u32, ny: u32, nz: u32, nf: u32) -> Self {
44 let prec = match data_type {
45 FpZipType::Float => 32,
46 FpZipType::Double => 64,
47 };
48 Self {
49 data_type,
50 prec,
51 nx,
52 ny,
53 nz,
54 nf,
55 }
56 }
57
58 pub fn total_elements(&self) -> u64 {
60 self.nx as u64 * self.ny as u64 * self.nz as u64 * self.nf as u64
61 }
62
63 pub fn write_to_encoder(&self, enc: &mut RangeEncoder) {
65 enc.encode_uint(b'f' as u32, 8);
67 enc.encode_uint(b'p' as u32, 8);
68 enc.encode_uint(b'z' as u32, 8);
69 enc.encode_uint(0, 8);
70
71 enc.encode_uint(FPZ_MAJ_VERSION, 16);
73 enc.encode_uint(FPZ_MIN_VERSION, 8);
74
75 enc.encode_uint(self.data_type as u32, 1);
77 enc.encode_uint(self.prec, 7);
78
79 enc.encode_uint(self.nx, 32);
81 enc.encode_uint(self.ny, 32);
82 enc.encode_uint(self.nz, 32);
83 enc.encode_uint(self.nf, 32);
84 }
85
86 pub fn read_from_decoder(dec: &mut RangeDecoder) -> Result<Self> {
88 let f = dec.decode_uint(8);
90 let p = dec.decode_uint(8);
91 let z = dec.decode_uint(8);
92 let nul = dec.decode_uint(8);
93 if f != b'f' as u32 || p != b'p' as u32 || z != b'z' as u32 || nul != 0 {
94 let magic = f | (p << 8) | (z << 16) | (nul << 24);
95 return Err(FpZipError::InvalidMagic(magic));
96 }
97
98 let maj = dec.decode_uint(16);
100 let min = dec.decode_uint(8);
101 if maj != FPZ_MAJ_VERSION {
102 return Err(FpZipError::UnsupportedVersion(maj as u16));
103 }
104 if min != FPZ_MIN_VERSION {
105 return Err(FpZipError::UnsupportedVersion(min as u16));
106 }
107
108 let type_bit = dec.decode_uint(1);
110 let prec = dec.decode_uint(7);
111
112 let data_type = match type_bit {
113 0 => FpZipType::Float,
114 1 => FpZipType::Double,
115 _ => return Err(FpZipError::InvalidDataType(type_bit as u8)),
116 };
117
118 let nx = dec.decode_uint(32);
120 let ny = dec.decode_uint(32);
121 let nz = dec.decode_uint(32);
122 let nf = dec.decode_uint(32);
123
124 Ok(Self {
125 data_type,
126 prec,
127 nx,
128 ny,
129 nz,
130 nf,
131 })
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn round_trip_header_via_encoder() {
141 let h = FpZipHeader::new(FpZipType::Float, 10, 20, 30, 2);
142 let mut enc = RangeEncoder::new();
143 h.write_to_encoder(&mut enc);
144 let data = enc.finish();
145
146 let mut dec = RangeDecoder::new(&data);
147 dec.init();
148 let h2 = FpZipHeader::read_from_decoder(&mut dec).unwrap();
149 assert_eq!(h.data_type, h2.data_type);
150 assert_eq!(h.nx, h2.nx);
151 assert_eq!(h.ny, h2.ny);
152 assert_eq!(h.nz, h2.nz);
153 assert_eq!(h.nf, h2.nf);
154 }
155
156 #[test]
157 fn total_elements() {
158 let h = FpZipHeader::new(FpZipType::Double, 10, 20, 30, 2);
159 assert_eq!(h.total_elements(), 12000);
160 }
161
162 #[test]
163 fn invalid_magic_returns_error() {
164 let mut enc = RangeEncoder::new();
166 enc.encode_uint(b'X' as u32, 8);
167 enc.encode_uint(b'Y' as u32, 8);
168 enc.encode_uint(b'Z' as u32, 8);
169 enc.encode_uint(0, 8);
170 enc.encode_uint(FPZ_MAJ_VERSION, 16);
172 enc.encode_uint(FPZ_MIN_VERSION, 8);
173 enc.encode_uint(0, 1);
174 enc.encode_uint(32, 7);
175 enc.encode_uint(1, 32);
176 enc.encode_uint(1, 32);
177 enc.encode_uint(1, 32);
178 enc.encode_uint(1, 32);
179 let data = enc.finish();
180
181 let mut dec = RangeDecoder::new(&data);
182 dec.init();
183 assert!(matches!(
184 FpZipHeader::read_from_decoder(&mut dec),
185 Err(FpZipError::InvalidMagic(_))
186 ));
187 }
188
189 #[test]
190 fn round_trip_double_header() {
191 let h = FpZipHeader::new(FpZipType::Double, 65, 64, 63, 3);
192 let mut enc = RangeEncoder::new();
193 h.write_to_encoder(&mut enc);
194 let data = enc.finish();
195
196 let mut dec = RangeDecoder::new(&data);
197 dec.init();
198 let h2 = FpZipHeader::read_from_decoder(&mut dec).unwrap();
199 assert_eq!(h, h2);
200 }
201}