1#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5
6use crate::error::FormatError;
7
8#[derive(Debug, Clone, PartialEq)]
10pub enum DataspaceType {
11 Scalar,
13 Simple,
15 Null,
17}
18
19#[derive(Debug, Clone, PartialEq)]
21pub struct Dataspace {
22 pub space_type: DataspaceType,
24 pub rank: u8,
26 pub dimensions: Vec<u64>,
28 pub max_dimensions: Option<Vec<u64>>,
30}
31
32fn ensure_len(data: &[u8], offset: usize, needed: usize) -> Result<(), FormatError> {
33 match offset.checked_add(needed) {
34 Some(end) if end <= data.len() => Ok(()),
35 _ => Err(FormatError::UnexpectedEof {
36 expected: offset.saturating_add(needed),
37 available: data.len(),
38 }),
39 }
40}
41
42fn read_length(data: &[u8], offset: usize, length_size: u8) -> Result<u64, FormatError> {
43 let s = length_size as usize;
44 ensure_len(data, offset, s)?;
45 let slice = &data[offset..offset + s];
46 Ok(match length_size {
47 2 => u16::from_le_bytes([slice[0], slice[1]]) as u64,
48 4 => u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]]) as u64,
49 8 => u64::from_le_bytes([
50 slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
51 ]),
52 _ => {
53 return Err(FormatError::InvalidLengthSize(length_size));
54 }
55 })
56}
57
58impl Dataspace {
59 pub fn parse(data: &[u8], length_size: u8) -> Result<Dataspace, FormatError> {
63 ensure_len(data, 0, 4)?;
64
65 let version = data[0];
66 let rank = data[1];
67 let flags = data[2];
68
69 let (space_type, header_size) = match version {
70 1 => {
71 ensure_len(data, 0, 8)?;
73 let st = if rank == 0 {
74 DataspaceType::Scalar
75 } else {
76 DataspaceType::Simple
77 };
78 (st, 8usize)
79 }
80 2 => {
81 let type_byte = data[3];
83 let st = match type_byte {
84 0 => DataspaceType::Scalar,
85 1 => DataspaceType::Simple,
86 2 => DataspaceType::Null,
87 _ => return Err(FormatError::InvalidDataspaceType(type_byte)),
88 };
89 (st, 4usize)
90 }
91 _ => return Err(FormatError::InvalidDataspaceVersion(version)),
92 };
93
94 let ls = length_size as usize;
95 let mut pos = header_size;
96
97 let mut dimensions = Vec::with_capacity(rank as usize);
99 for _ in 0..rank {
100 let dim = read_length(data, pos, length_size)?;
101 dimensions.push(dim);
102 pos += ls;
103 }
104
105 let max_dimensions = if flags & 0x01 != 0 {
107 let mut max_dims = Vec::with_capacity(rank as usize);
108 for _ in 0..rank {
109 let val = read_length(data, pos, length_size)?;
110 max_dims.push(val);
111 pos += ls;
112 }
113 Some(max_dims)
114 } else {
115 None
116 };
117
118 if version == 1 && flags & 0x02 != 0 {
120 let _skip = rank as usize * ls;
122 }
124
125 Ok(Dataspace {
126 space_type,
127 rank,
128 dimensions,
129 max_dimensions,
130 })
131 }
132
133 pub fn serialize(&self, length_size: u8) -> Vec<u8> {
135 let mut buf = Vec::new();
136 buf.push(2); buf.push(self.rank);
138 let flags = if self.max_dimensions.is_some() { 0x01 } else { 0x00 };
139 buf.push(flags);
140 let type_byte = match self.space_type {
141 DataspaceType::Scalar => 0,
142 DataspaceType::Simple => 1,
143 DataspaceType::Null => 2,
144 };
145 buf.push(type_byte);
146 for &dim in &self.dimensions {
147 Self::write_length(&mut buf, dim, length_size);
148 }
149 if let Some(ref max_dims) = self.max_dimensions {
150 for &md in max_dims {
151 Self::write_length(&mut buf, md, length_size);
152 }
153 }
154 buf
155 }
156
157 fn write_length(buf: &mut Vec<u8>, val: u64, size: u8) {
158 match size {
159 2 => buf.extend_from_slice(&(val as u16).to_le_bytes()),
160 4 => buf.extend_from_slice(&(val as u32).to_le_bytes()),
161 8 => buf.extend_from_slice(&val.to_le_bytes()),
162 _ => {}
163 }
164 }
165
166 pub fn num_elements(&self) -> u64 {
168 match self.space_type {
169 DataspaceType::Null => 0,
170 DataspaceType::Scalar => 1,
171 DataspaceType::Simple => {
172 if self.dimensions.is_empty() {
173 0
174 } else {
175 self.dimensions.iter().product()
176 }
177 }
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 fn build_v1_dataspace(rank: u8, flags: u8, dims: &[u64], max_dims: Option<&[u64]>) -> Vec<u8> {
187 let length_size = 8u8;
188 let mut buf = Vec::new();
189 buf.push(1); buf.push(rank);
191 buf.push(flags);
192 buf.push(0); buf.extend_from_slice(&[0u8; 4]); for &d in dims {
195 buf.extend_from_slice(&d.to_le_bytes());
196 }
197 if let Some(md) = max_dims {
198 for &d in md {
199 buf.extend_from_slice(&d.to_le_bytes());
200 }
201 }
202 let _ = length_size;
203 buf
204 }
205
206 fn build_v2_dataspace(
207 rank: u8,
208 flags: u8,
209 type_byte: u8,
210 dims: &[u64],
211 max_dims: Option<&[u64]>,
212 ) -> Vec<u8> {
213 let mut buf = Vec::new();
214 buf.push(2); buf.push(rank);
216 buf.push(flags);
217 buf.push(type_byte);
218 for &d in dims {
219 buf.extend_from_slice(&d.to_le_bytes());
220 }
221 if let Some(md) = max_dims {
222 for &d in md {
223 buf.extend_from_slice(&d.to_le_bytes());
224 }
225 }
226 buf
227 }
228
229 #[test]
230 fn scalar_v1() {
231 let data = build_v1_dataspace(0, 0, &[], None);
232 let ds = Dataspace::parse(&data, 8).unwrap();
233 assert_eq!(ds.space_type, DataspaceType::Scalar);
234 assert_eq!(ds.rank, 0);
235 assert!(ds.dimensions.is_empty());
236 assert!(ds.max_dimensions.is_none());
237 assert_eq!(ds.num_elements(), 1);
238 }
239
240 #[test]
241 fn null_v2() {
242 let data = build_v2_dataspace(0, 0, 2, &[], None);
243 let ds = Dataspace::parse(&data, 8).unwrap();
244 assert_eq!(ds.space_type, DataspaceType::Null);
245 assert_eq!(ds.num_elements(), 0);
246 }
247
248 #[test]
249 fn simple_1d() {
250 let data = build_v1_dataspace(1, 0, &[5], None);
251 let ds = Dataspace::parse(&data, 8).unwrap();
252 assert_eq!(ds.space_type, DataspaceType::Simple);
253 assert_eq!(ds.rank, 1);
254 assert_eq!(ds.dimensions, vec![5]);
255 assert!(ds.max_dimensions.is_none());
256 assert_eq!(ds.num_elements(), 5);
257 }
258
259 #[test]
260 fn simple_2d() {
261 let data = build_v1_dataspace(2, 0, &[3, 4], None);
262 let ds = Dataspace::parse(&data, 8).unwrap();
263 assert_eq!(ds.rank, 2);
264 assert_eq!(ds.dimensions, vec![3, 4]);
265 assert_eq!(ds.num_elements(), 12);
266 }
267
268 #[test]
269 fn simple_3d_with_max_dims_unlimited() {
270 let data = build_v1_dataspace(
271 3,
272 0x01,
273 &[2, 3, 4],
274 Some(&[10, u64::MAX, 100]),
275 );
276 let ds = Dataspace::parse(&data, 8).unwrap();
277 assert_eq!(ds.rank, 3);
278 assert_eq!(ds.dimensions, vec![2, 3, 4]);
279 let md = ds.max_dimensions.clone().unwrap();
280 assert_eq!(md, vec![10, u64::MAX, 100]);
281 assert_eq!(ds.num_elements(), 24);
282 }
283
284 #[test]
285 fn v2_simple() {
286 let data = build_v2_dataspace(1, 0, 1, &[7], None);
287 let ds = Dataspace::parse(&data, 8).unwrap();
288 assert_eq!(ds.space_type, DataspaceType::Simple);
289 assert_eq!(ds.dimensions, vec![7]);
290 }
291
292 #[test]
293 fn v2_scalar() {
294 let data = build_v2_dataspace(0, 0, 0, &[], None);
295 let ds = Dataspace::parse(&data, 8).unwrap();
296 assert_eq!(ds.space_type, DataspaceType::Scalar);
297 assert_eq!(ds.num_elements(), 1);
298 }
299
300 #[test]
301 fn v1_with_4byte_length() {
302 let mut buf = Vec::new();
303 buf.push(1); buf.push(1); buf.push(0); buf.push(0); buf.extend_from_slice(&[0u8; 4]); buf.extend_from_slice(&10u32.to_le_bytes()); let ds = Dataspace::parse(&buf, 4).unwrap();
310 assert_eq!(ds.dimensions, vec![10]);
311 }
312
313 #[test]
314 fn truncated_data_error() {
315 let data = [1u8, 2]; let err = Dataspace::parse(&data, 8).unwrap_err();
317 assert!(matches!(err, FormatError::UnexpectedEof { .. }));
318 }
319
320 #[test]
321 fn invalid_version_error() {
322 let data = [5u8, 0, 0, 0, 0, 0, 0, 0];
323 let err = Dataspace::parse(&data, 8).unwrap_err();
324 assert_eq!(err, FormatError::InvalidDataspaceVersion(5));
325 }
326
327 #[test]
328 fn invalid_v2_type_error() {
329 let data = build_v2_dataspace(0, 0, 5, &[], None);
330 let err = Dataspace::parse(&data, 8).unwrap_err();
331 assert_eq!(err, FormatError::InvalidDataspaceType(5));
332 }
333
334 #[test]
335 fn v1_with_max_dims() {
336 let data = build_v1_dataspace(1, 0x01, &[5], Some(&[10]));
337 let ds = Dataspace::parse(&data, 8).unwrap();
338 assert_eq!(ds.max_dimensions, Some(vec![10]));
339 }
340}