rust_hdf5/format/messages/
dataspace.rs1use crate::format::bytes::read_le_uint as read_size;
12use crate::format::{FormatContext, FormatError, FormatResult};
13
14const VERSION: u8 = 2;
15const FLAG_MAX_DIMS: u8 = 0x01;
16
17const DS_TYPE_SCALAR: u8 = 0;
19const DS_TYPE_SIMPLE: u8 = 1;
20const _DS_TYPE_NULL: u8 = 2;
21
22#[derive(Debug, Clone, PartialEq)]
24pub struct DataspaceMessage {
25 pub dims: Vec<u64>,
27 pub max_dims: Option<Vec<u64>>,
29}
30
31impl DataspaceMessage {
32 pub fn scalar() -> Self {
36 Self {
37 dims: Vec::new(),
38 max_dims: None,
39 }
40 }
41
42 pub fn simple(dims: &[u64]) -> Self {
44 Self {
45 dims: dims.to_vec(),
46 max_dims: None,
47 }
48 }
49
50 pub fn unlimited(current: &[u64]) -> Self {
52 Self {
53 dims: current.to_vec(),
54 max_dims: Some(vec![u64::MAX; current.len()]),
55 }
56 }
57
58 pub fn encode(&self, ctx: &FormatContext) -> Vec<u8> {
61 let ndims = self.dims.len();
62 let ss = ctx.sizeof_size as usize;
63 let has_max = self.max_dims.is_some();
64 let flags: u8 = if has_max { FLAG_MAX_DIMS } else { 0 };
65
66 let ds_type = if ndims == 0 {
68 DS_TYPE_SCALAR
69 } else {
70 DS_TYPE_SIMPLE
71 };
72
73 let body_len = 4 + ndims * ss + if has_max { ndims * ss } else { 0 };
74 let mut buf = Vec::with_capacity(body_len);
75
76 buf.push(VERSION);
77 buf.push(ndims as u8);
78 buf.push(flags);
79 buf.push(ds_type); for &d in &self.dims {
83 buf.extend_from_slice(&d.to_le_bytes()[..ss]);
84 }
85
86 if let Some(ref maxes) = self.max_dims {
88 for &m in maxes {
89 buf.extend_from_slice(&m.to_le_bytes()[..ss]);
90 }
91 }
92
93 buf
94 }
95
96 pub fn decode(buf: &[u8], ctx: &FormatContext) -> FormatResult<(Self, usize)> {
99 if buf.len() < 4 {
100 return Err(FormatError::BufferTooShort {
101 needed: 4,
102 available: buf.len(),
103 });
104 }
105
106 let version = buf[0];
107 match version {
108 1 => Self::decode_v1(buf, ctx),
109 VERSION => Self::decode_v2(buf, ctx),
110 _ => Err(FormatError::InvalidVersion(version)),
111 }
112 }
113
114 fn decode_v2(buf: &[u8], ctx: &FormatContext) -> FormatResult<(Self, usize)> {
116 let ndims = buf[1] as usize;
117 let flags = buf[2];
118 let _ds_type = buf[3]; let has_max = (flags & FLAG_MAX_DIMS) != 0;
120 let ss = ctx.sizeof_size as usize;
121
122 let needed = 4 + ndims * ss + if has_max { ndims * ss } else { 0 };
123 if buf.len() < needed {
124 return Err(FormatError::BufferTooShort {
125 needed,
126 available: buf.len(),
127 });
128 }
129
130 let mut pos = 4;
131
132 let mut dims = Vec::with_capacity(ndims);
133 for _ in 0..ndims {
134 dims.push(read_size(&buf[pos..], ss));
135 pos += ss;
136 }
137
138 let max_dims = if has_max {
139 let mut v = Vec::with_capacity(ndims);
140 for _ in 0..ndims {
141 v.push(read_size(&buf[pos..], ss));
142 pos += ss;
143 }
144 Some(v)
145 } else {
146 None
147 };
148
149 Ok((Self { dims, max_dims }, pos))
150 }
151
152 fn decode_v1(buf: &[u8], ctx: &FormatContext) -> FormatResult<(Self, usize)> {
166 if buf.len() < 8 {
167 return Err(FormatError::BufferTooShort {
168 needed: 8,
169 available: buf.len(),
170 });
171 }
172
173 let ndims = buf[1] as usize;
174 let flags = buf[2];
175 let has_max = (flags & FLAG_MAX_DIMS) != 0;
176 let has_perm = (flags & 0x02) != 0;
177 let ss = ctx.sizeof_size as usize;
178
179 let mut needed = 8 + ndims * ss;
181 if has_max {
182 needed += ndims * ss;
183 }
184 if has_perm {
185 needed += ndims * ss;
186 }
187 if buf.len() < needed {
188 return Err(FormatError::BufferTooShort {
189 needed,
190 available: buf.len(),
191 });
192 }
193
194 let mut pos = 8; let mut dims = Vec::with_capacity(ndims);
197 for _ in 0..ndims {
198 dims.push(read_size(&buf[pos..], ss));
199 pos += ss;
200 }
201
202 let max_dims = if has_max {
203 let mut v = Vec::with_capacity(ndims);
204 for _ in 0..ndims {
205 v.push(read_size(&buf[pos..], ss));
206 pos += ss;
207 }
208 Some(v)
209 } else {
210 None
211 };
212
213 if has_perm {
215 pos += ndims * ss;
216 }
217
218 Ok((Self { dims, max_dims }, pos))
219 }
220}
221
222#[cfg(test)]
225mod tests {
226 use super::*;
227
228 fn ctx8() -> FormatContext {
229 FormatContext {
230 sizeof_addr: 8,
231 sizeof_size: 8,
232 }
233 }
234
235 fn ctx4() -> FormatContext {
236 FormatContext {
237 sizeof_addr: 4,
238 sizeof_size: 4,
239 }
240 }
241
242 #[test]
243 fn roundtrip_scalar() {
244 let msg = DataspaceMessage::scalar();
245 let encoded = msg.encode(&ctx8());
246 assert_eq!(encoded.len(), 4); let (decoded, consumed) = DataspaceMessage::decode(&encoded, &ctx8()).unwrap();
248 assert_eq!(consumed, 4);
249 assert_eq!(decoded, msg);
250 }
251
252 #[test]
253 fn roundtrip_simple_1d() {
254 let msg = DataspaceMessage::simple(&[100]);
255 let encoded = msg.encode(&ctx8());
256 assert_eq!(encoded.len(), 12);
258 let (decoded, consumed) = DataspaceMessage::decode(&encoded, &ctx8()).unwrap();
259 assert_eq!(consumed, 12);
260 assert_eq!(decoded, msg);
261 }
262
263 #[test]
264 fn roundtrip_simple_3d_ctx4() {
265 let msg = DataspaceMessage::simple(&[10, 20, 30]);
266 let encoded = msg.encode(&ctx4());
267 assert_eq!(encoded.len(), 16);
269 let (decoded, consumed) = DataspaceMessage::decode(&encoded, &ctx4()).unwrap();
270 assert_eq!(consumed, 16);
271 assert_eq!(decoded, msg);
272 }
273
274 #[test]
275 fn roundtrip_unlimited() {
276 let msg = DataspaceMessage::unlimited(&[5, 10]);
277 let encoded = msg.encode(&ctx8());
278 assert_eq!(encoded.len(), 36);
280 let (decoded, consumed) = DataspaceMessage::decode(&encoded, &ctx8()).unwrap();
281 assert_eq!(consumed, 36);
282 assert_eq!(decoded, msg);
283 assert_eq!(decoded.max_dims.as_ref().unwrap(), &vec![u64::MAX; 2]);
284 }
285
286 #[test]
287 fn roundtrip_partial_max() {
288 let msg = DataspaceMessage {
289 dims: vec![3, 4],
290 max_dims: Some(vec![100, u64::MAX]),
291 };
292 let encoded = msg.encode(&ctx8());
293 let (decoded, _) = DataspaceMessage::decode(&encoded, &ctx8()).unwrap();
294 assert_eq!(decoded, msg);
295 }
296
297 #[test]
298 fn decode_bad_version() {
299 let buf = [99u8, 0, 0, 0]; let err = DataspaceMessage::decode(&buf, &ctx8()).unwrap_err();
301 match err {
302 FormatError::InvalidVersion(99) => {}
303 other => panic!("unexpected error: {:?}", other),
304 }
305 }
306
307 #[test]
308 fn decode_v1_simple_1d() {
309 let mut buf = vec![
311 1, 1, 0, 0, ];
316 buf.extend_from_slice(&[0u8; 4]); buf.extend_from_slice(&100u64.to_le_bytes()); let (msg, consumed) = DataspaceMessage::decode(&buf, &ctx8()).unwrap();
320 assert_eq!(consumed, 16); assert_eq!(msg.dims, vec![100]);
322 assert_eq!(msg.max_dims, None);
323 }
324
325 #[test]
326 fn decode_v1_with_max_dims() {
327 let mut buf = vec![
328 1, 2, 1, 0, ];
333 buf.extend_from_slice(&[0u8; 4]); buf.extend_from_slice(&10u64.to_le_bytes()); buf.extend_from_slice(&20u64.to_le_bytes()); buf.extend_from_slice(&u64::MAX.to_le_bytes()); buf.extend_from_slice(&100u64.to_le_bytes()); let (msg, consumed) = DataspaceMessage::decode(&buf, &ctx8()).unwrap();
340 assert_eq!(consumed, 40); assert_eq!(msg.dims, vec![10, 20]);
342 assert_eq!(msg.max_dims, Some(vec![u64::MAX, 100]));
343 }
344
345 #[test]
346 fn decode_buffer_too_short() {
347 let buf = [2u8, 1, 0]; let err = DataspaceMessage::decode(&buf, &ctx8()).unwrap_err();
349 match err {
350 FormatError::BufferTooShort { .. } => {}
351 other => panic!("unexpected error: {:?}", other),
352 }
353 }
354
355 #[test]
356 fn decode_buffer_too_short_for_dims() {
357 let buf = [2u8, 1, 0, 1, 0, 0];
359 let err = DataspaceMessage::decode(&buf, &ctx8()).unwrap_err();
360 match err {
361 FormatError::BufferTooShort {
362 needed: 12,
363 available: 6,
364 } => {}
365 other => panic!("unexpected error: {:?}", other),
366 }
367 }
368
369 #[test]
370 fn version_byte_is_two() {
371 let msg = DataspaceMessage::simple(&[42]);
372 let encoded = msg.encode(&ctx8());
373 assert_eq!(encoded[0], 2);
374 }
375}