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