1use crate::error::{Error, Result};
7use crate::io::Cursor;
8pub use hdf5_core::{DataspaceMessage, DataspaceType, UNLIMITED};
9
10pub fn parse(
15 cursor: &mut Cursor<'_>,
16 _offset_size: u8,
17 length_size: u8,
18 msg_size: usize,
19) -> Result<DataspaceMessage> {
20 let start = cursor.position();
21 let version = cursor.read_u8()?;
22
23 match version {
24 1 => parse_v1(cursor, length_size),
25 2 => parse_v2(cursor, length_size),
26 v => Err(Error::UnsupportedDataspaceVersion(v)),
27 }
28 .and_then(|msg| {
29 let consumed = (cursor.position() - start) as usize;
31 if consumed < msg_size {
32 cursor.skip(msg_size - consumed)?;
33 }
34 Ok(msg)
35 })
36}
37
38fn parse_v1(cursor: &mut Cursor<'_>, length_size: u8) -> Result<DataspaceMessage> {
40 let rank = cursor.read_u8()?;
41 let flags = cursor.read_u8()?;
42 let _reserved = cursor.read_u8()?; let _reserved2 = cursor.read_u32_le()?; let has_max_dims = (flags & 0x01) != 0;
46 let has_permutation = (flags & 0x02) != 0;
49
50 let dataspace_type = if rank == 0 {
51 DataspaceType::Scalar
52 } else {
53 DataspaceType::Simple
54 };
55
56 let mut dims = Vec::with_capacity(rank as usize);
57 for _ in 0..rank {
58 dims.push(cursor.read_length(length_size)?);
59 }
60
61 let max_dims = if has_max_dims {
62 let mut md = Vec::with_capacity(rank as usize);
63 for _ in 0..rank {
64 md.push(cursor.read_length(length_size)?);
65 }
66 Some(md)
67 } else {
68 None
69 };
70
71 if has_permutation {
72 for _ in 0..rank {
74 cursor.read_length(length_size)?;
75 }
76 }
77
78 Ok(DataspaceMessage {
79 rank,
80 dims,
81 max_dims,
82 dataspace_type,
83 })
84}
85
86fn parse_v2(cursor: &mut Cursor<'_>, length_size: u8) -> Result<DataspaceMessage> {
88 let rank = cursor.read_u8()?;
89 let flags = cursor.read_u8()?;
90 let ds_type_byte = cursor.read_u8()?;
91
92 let has_max_dims = (flags & 0x01) != 0;
93
94 let dataspace_type = match ds_type_byte {
95 0 => DataspaceType::Scalar,
96 1 => DataspaceType::Simple,
97 2 => DataspaceType::Null,
98 _ => {
99 return Err(Error::InvalidData(format!(
100 "unknown dataspace type: {}",
101 ds_type_byte
102 )))
103 }
104 };
105
106 let mut dims = Vec::with_capacity(rank as usize);
107 for _ in 0..rank {
108 dims.push(cursor.read_length(length_size)?);
109 }
110
111 let max_dims = if has_max_dims {
112 let mut md = Vec::with_capacity(rank as usize);
113 for _ in 0..rank {
114 md.push(cursor.read_length(length_size)?);
115 }
116 Some(md)
117 } else {
118 None
119 };
120
121 Ok(DataspaceMessage {
122 rank,
123 dims,
124 max_dims,
125 dataspace_type,
126 })
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn parse_v1_scalar() {
135 let data = [
137 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
143 let mut cursor = Cursor::new(&data);
144 let msg = parse(&mut cursor, 8, 8, data.len()).unwrap();
145 assert_eq!(msg.rank, 0);
146 assert_eq!(msg.dataspace_type, DataspaceType::Scalar);
147 assert!(msg.dims.is_empty());
148 assert!(msg.max_dims.is_none());
149 assert_eq!(msg.num_elements().unwrap(), 1);
150 }
151
152 #[test]
153 fn parse_v1_simple_2d() {
154 let mut data = vec![
156 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ];
162 data.extend_from_slice(&10u64.to_le_bytes());
164 data.extend_from_slice(&20u64.to_le_bytes());
166 data.extend_from_slice(&100u64.to_le_bytes());
168 data.extend_from_slice(&u64::MAX.to_le_bytes());
170
171 let mut cursor = Cursor::new(&data);
172 let msg = parse(&mut cursor, 8, 8, data.len()).unwrap();
173 assert_eq!(msg.rank, 2);
174 assert_eq!(msg.dims, vec![10, 20]);
175 assert_eq!(msg.max_dims.as_ref().unwrap(), &vec![100, UNLIMITED]);
176 assert_eq!(msg.dataspace_type, DataspaceType::Simple);
177 assert_eq!(msg.num_elements().unwrap(), 200);
178 }
179
180 #[test]
181 fn parse_v2_simple_1d() {
182 let mut data = vec![
184 0x02, 0x01, 0x00, 0x01, ];
189 data.extend_from_slice(&42u32.to_le_bytes());
191
192 let mut cursor = Cursor::new(&data);
193 let msg = parse(&mut cursor, 4, 4, data.len()).unwrap();
194 assert_eq!(msg.rank, 1);
195 assert_eq!(msg.dims, vec![42]);
196 assert!(msg.max_dims.is_none());
197 assert_eq!(msg.dataspace_type, DataspaceType::Simple);
198 }
199
200 #[test]
201 fn parse_v2_null() {
202 let data = [
203 0x02, 0x00, 0x00, 0x02, ];
208 let mut cursor = Cursor::new(&data);
209 let msg = parse(&mut cursor, 8, 8, data.len()).unwrap();
210 assert_eq!(msg.dataspace_type, DataspaceType::Null);
211 assert_eq!(msg.num_elements().unwrap(), 0);
212 }
213
214 #[test]
215 fn parse_v2_with_max_dims() {
216 let mut data = vec![
217 0x02, 0x03, 0x01, 0x01, ];
222 for &d in &[5u64, 10, 15] {
224 data.extend_from_slice(&d.to_le_bytes());
225 }
226 for &d in &[50u64, 100, u64::MAX] {
228 data.extend_from_slice(&d.to_le_bytes());
229 }
230
231 let mut cursor = Cursor::new(&data);
232 let msg = parse(&mut cursor, 8, 8, data.len()).unwrap();
233 assert_eq!(msg.rank, 3);
234 assert_eq!(msg.dims, vec![5, 10, 15]);
235 let md = msg.max_dims.clone().unwrap();
236 assert_eq!(md, vec![50, 100, UNLIMITED]);
237 assert_eq!(msg.num_elements().unwrap(), 750);
238 }
239
240 #[test]
241 fn unsupported_version() {
242 let data = [0x03, 0x00, 0x00, 0x00];
243 let mut cursor = Cursor::new(&data);
244 assert!(parse(&mut cursor, 8, 8, data.len()).is_err());
245 }
246
247 #[test]
248 fn num_elements_rejects_overflow() {
249 let msg = DataspaceMessage {
250 rank: 2,
251 dims: vec![u64::MAX, 2],
252 max_dims: None,
253 dataspace_type: DataspaceType::Simple,
254 };
255
256 let err = msg.num_elements().unwrap_err();
257 assert!(err.to_string().contains("element count"));
258 }
259}