1use crate::format::{FormatError, FormatResult};
24
25const VERSION: u8 = 3;
26
27const FLAG_MASK_ALLOC: u8 = 0x03;
29const FLAG_MASK_FILL: u8 = 0x03;
30const FLAG_SHIFT_FILL: u8 = 2;
31const FLAG_UNDEFINED: u8 = 0x10;
32const FLAG_HAVE_VALUE: u8 = 0x20;
33const FLAGS_ALL: u8 =
34 FLAG_MASK_ALLOC | (FLAG_MASK_FILL << FLAG_SHIFT_FILL) | FLAG_UNDEFINED | FLAG_HAVE_VALUE;
35
36pub const ALLOC_TIME_EARLY: u8 = 1;
41
42pub const ALLOC_TIME_LATE: u8 = 2;
45
46pub const ALLOC_TIME_INCR: u8 = 3;
50
51pub const FILL_TIME_ALLOC: u8 = 0;
55
56pub const FILL_TIME_NEVER: u8 = 1;
66
67pub const FILL_TIME_IFSET: u8 = 2;
78
79#[derive(Debug, Clone, PartialEq)]
81pub struct FillValueMessage {
82 pub alloc_time: u8,
84 pub fill_write_time: u8,
86 pub fill_defined: u8,
88 pub fill_value: Option<Vec<u8>>,
90}
91
92impl Default for FillValueMessage {
93 fn default() -> Self {
94 Self {
95 alloc_time: ALLOC_TIME_LATE,
96 fill_write_time: FILL_TIME_IFSET,
97 fill_defined: 1, fill_value: None,
99 }
100 }
101}
102
103impl FillValueMessage {
104 pub fn with_value(data: Vec<u8>) -> Self {
106 Self {
107 alloc_time: ALLOC_TIME_LATE,
108 fill_write_time: FILL_TIME_IFSET,
109 fill_defined: 2,
110 fill_value: Some(data),
111 }
112 }
113
114 pub fn undefined() -> Self {
116 Self {
117 alloc_time: ALLOC_TIME_LATE,
118 fill_write_time: FILL_TIME_NEVER,
119 fill_defined: 0,
120 fill_value: None,
121 }
122 }
123
124 pub fn encode(&self) -> Vec<u8> {
128 self.encode_for(crate::format::ObjectFormat::Modern)
129 }
130
131 pub fn encode_for(&self, format: crate::format::ObjectFormat) -> Vec<u8> {
141 if format.fill_value_version() < VERSION {
142 let mut buf = Vec::with_capacity(12);
143 buf.push(format.fill_value_version());
144 buf.push(self.alloc_time);
145 buf.push(self.fill_write_time);
146 if self.fill_defined == 0 {
147 buf.push(0);
148 return buf;
149 }
150 buf.push(1);
151 let value = self.fill_value.as_deref().unwrap_or(&[]);
152 buf.extend_from_slice(&(value.len() as u32).to_le_bytes());
153 buf.extend_from_slice(value);
154 return buf;
155 }
156 let mut buf = Vec::with_capacity(10);
157 buf.push(VERSION);
158
159 let flags = (self.alloc_time & FLAG_MASK_ALLOC)
160 | ((self.fill_write_time & FLAG_MASK_FILL) << FLAG_SHIFT_FILL);
161
162 if self.fill_defined == 0 {
163 buf.push(flags | FLAG_UNDEFINED);
165 } else if let Some(data) = self.fill_value.as_ref().filter(|d| !d.is_empty()) {
166 buf.push(flags | FLAG_HAVE_VALUE);
168 buf.extend_from_slice(&(data.len() as u32).to_le_bytes());
169 buf.extend_from_slice(data);
170 } else {
171 buf.push(flags);
173 }
174
175 buf
176 }
177
178 pub fn decode(buf: &[u8]) -> FormatResult<(Self, usize)> {
182 if buf.is_empty() {
183 return Err(FormatError::BufferTooShort {
184 needed: 1,
185 available: 0,
186 });
187 }
188 match buf[0] {
189 1 | 2 => Self::decode_v1v2(buf),
190 3 => Self::decode_v3(buf),
191 other => Err(FormatError::InvalidVersion(other)),
192 }
193 }
194
195 fn decode_v1v2(buf: &[u8]) -> FormatResult<(Self, usize)> {
197 if buf.len() < 4 {
198 return Err(FormatError::BufferTooShort {
199 needed: 4,
200 available: buf.len(),
201 });
202 }
203 let alloc_time = buf[1];
204 let fill_write_time = buf[2];
205 let defined_byte = buf[3];
206
207 let mut pos = 4;
208 let mut fill_value = None;
209 if defined_byte != 0 {
210 if buf.len() < pos + 4 {
211 return Err(FormatError::BufferTooShort {
212 needed: pos + 4,
213 available: buf.len(),
214 });
215 }
216 let size =
217 u32::from_le_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) as usize;
218 pos += 4;
219 if size > 0 {
220 if buf.len() < pos + size {
221 return Err(FormatError::BufferTooShort {
222 needed: pos + size,
223 available: buf.len(),
224 });
225 }
226 fill_value = Some(buf[pos..pos + size].to_vec());
227 pos += size;
228 }
229 }
230
231 let fill_defined = if fill_value.is_some() {
235 2
236 } else if defined_byte != 0 {
237 1
238 } else {
239 0
240 };
241
242 Ok((
243 Self {
244 alloc_time,
245 fill_write_time,
246 fill_defined,
247 fill_value,
248 },
249 pos,
250 ))
251 }
252
253 fn decode_v3(buf: &[u8]) -> FormatResult<(Self, usize)> {
255 if buf.len() < 2 {
256 return Err(FormatError::BufferTooShort {
257 needed: 2,
258 available: buf.len(),
259 });
260 }
261 let flags = buf[1];
262 if flags & !FLAGS_ALL != 0 {
263 return Err(FormatError::InvalidData(format!(
264 "unknown flags 0x{flags:02x} in version-3 fill-value message"
265 )));
266 }
267 let alloc_time = flags & FLAG_MASK_ALLOC;
268 let fill_write_time = (flags >> FLAG_SHIFT_FILL) & FLAG_MASK_FILL;
269
270 let mut pos = 2;
271 let (fill_defined, fill_value) = if flags & FLAG_UNDEFINED != 0 {
272 if flags & FLAG_HAVE_VALUE != 0 {
273 return Err(FormatError::InvalidData(
274 "fill-value message sets both the undefined and have-value flags".into(),
275 ));
276 }
277 (0, None)
278 } else if flags & FLAG_HAVE_VALUE != 0 {
279 if buf.len() < pos + 4 {
280 return Err(FormatError::BufferTooShort {
281 needed: pos + 4,
282 available: buf.len(),
283 });
284 }
285 let size =
286 u32::from_le_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) as usize;
287 pos += 4;
288 if buf.len() < pos + size {
289 return Err(FormatError::BufferTooShort {
290 needed: pos + size,
291 available: buf.len(),
292 });
293 }
294 let data = buf[pos..pos + size].to_vec();
295 pos += size;
296 (2, Some(data))
297 } else {
298 (1, None)
299 };
300
301 Ok((
302 Self {
303 alloc_time,
304 fill_write_time,
305 fill_defined,
306 fill_value,
307 },
308 pos,
309 ))
310 }
311}
312
313pub(crate) fn tiled_fill(total: usize, fill_value: Option<&[u8]>) -> Vec<u8> {
323 match fill_value {
324 Some(fv) if !fv.is_empty() && total > 0 => {
325 let mut buf = vec![0u8; total];
326 for slot in buf.chunks_mut(fv.len()) {
327 let n = slot.len().min(fv.len());
328 slot[..n].copy_from_slice(&fv[..n]);
329 }
330 buf
331 }
332 _ => vec![0u8; total],
333 }
334}
335
336pub(crate) fn try_tiled_fill(
344 total: usize,
345 fill_value: Option<&[u8]>,
346) -> Result<Vec<u8>, std::collections::TryReserveError> {
347 let mut buf: Vec<u8> = Vec::new();
348 buf.try_reserve_exact(total)?;
349 buf.resize(total, 0);
350 if let Some(fv) = fill_value {
351 if !fv.is_empty() && total > 0 {
352 for slot in buf.chunks_mut(fv.len()) {
353 let n = slot.len().min(fv.len());
354 slot[..n].copy_from_slice(&fv[..n]);
355 }
356 }
357 }
358 Ok(buf)
359}
360
361#[cfg(test)]
364mod tests {
365 use super::*;
366
367 #[test]
368 fn roundtrip_default() {
369 let msg = FillValueMessage::default();
370 let encoded = msg.encode();
371 assert_eq!(encoded.len(), 2);
373 let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
374 assert_eq!(consumed, 2);
375 assert_eq!(decoded, msg);
376 }
377
378 #[test]
379 fn roundtrip_user_defined() {
380 let msg = FillValueMessage::with_value(vec![0xDE, 0xAD, 0xBE, 0xEF]);
381 let encoded = msg.encode();
382 assert_eq!(encoded.len(), 10);
384 let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
385 assert_eq!(consumed, 10);
386 assert_eq!(decoded, msg);
387 assert_eq!(
388 decoded.fill_value.as_ref().unwrap(),
389 &vec![0xDE, 0xAD, 0xBE, 0xEF]
390 );
391 }
392
393 #[test]
394 fn roundtrip_undefined() {
395 let msg = FillValueMessage::undefined();
396 let encoded = msg.encode();
397 assert_eq!(encoded.len(), 2);
398 let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
399 assert_eq!(consumed, 2);
400 assert_eq!(decoded, msg);
401 }
402
403 #[test]
404 fn version_3_flags_byte_layout() {
405 let msg = FillValueMessage {
408 alloc_time: 3,
409 fill_write_time: 2,
410 fill_defined: 2,
411 fill_value: Some(vec![0x01, 0x02]),
412 };
413 let encoded = msg.encode();
414 assert_eq!(encoded[0], 3);
415 assert_eq!(encoded[1], 0x03 | (0x02 << 2) | FLAG_HAVE_VALUE);
416 assert_eq!(&encoded[2..6], &2u32.to_le_bytes());
417 assert_eq!(&encoded[6..8], &[0x01, 0x02]);
418 assert_eq!(encoded.len(), 8);
419 }
420
421 #[test]
422 fn version_3_undefined_flag() {
423 let encoded = FillValueMessage::undefined().encode();
424 assert_eq!(encoded[1] & FLAG_UNDEFINED, FLAG_UNDEFINED);
425 assert_eq!(encoded[1] & FLAG_HAVE_VALUE, 0);
426 }
427
428 #[test]
429 fn empty_user_data_normalizes_to_default() {
430 let msg = FillValueMessage {
433 alloc_time: 1,
434 fill_write_time: 2,
435 fill_defined: 2,
436 fill_value: Some(vec![]),
437 };
438 let encoded = msg.encode();
439 assert_eq!(encoded.len(), 2);
440 let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
441 assert_eq!(consumed, 2);
442 assert_eq!(decoded.alloc_time, 1);
443 assert_eq!(decoded.fill_write_time, 2);
444 assert_eq!(decoded.fill_defined, 1);
445 assert_eq!(decoded.fill_value, None);
446 }
447
448 #[test]
449 fn decode_version_1_message() {
450 let buf = [1u8, 2, 0, 1, 4, 0, 0, 0, 0xAA, 0xBB, 0xCC, 0xDD];
452 let (decoded, consumed) = FillValueMessage::decode(&buf).unwrap();
453 assert_eq!(consumed, 12);
454 assert_eq!(decoded.alloc_time, 2);
455 assert_eq!(decoded.fill_defined, 2);
456 assert_eq!(
457 decoded.fill_value.as_ref().unwrap(),
458 &vec![0xAA, 0xBB, 0xCC, 0xDD]
459 );
460 }
461
462 #[test]
463 fn decode_version_2_message_libhdf5_default() {
464 let buf = [2u8, 2, 2, 1, 4, 0, 0, 0, 0x00, 0x00, 0x80, 0xBF];
467 let (decoded, consumed) = FillValueMessage::decode(&buf).unwrap();
468 assert_eq!(consumed, 12);
469 assert_eq!(decoded.alloc_time, 2);
470 assert_eq!(decoded.fill_write_time, 2);
471 assert_eq!(decoded.fill_defined, 2);
472 assert_eq!(
473 decoded.fill_value.as_ref().unwrap(),
474 &vec![0x00, 0x00, 0x80, 0xBF]
475 );
476 }
477
478 #[test]
479 fn decode_version_2_defined_without_value() {
480 let buf = [2u8, 2, 0, 1, 0, 0, 0, 0];
482 let (decoded, consumed) = FillValueMessage::decode(&buf).unwrap();
483 assert_eq!(consumed, 8);
484 assert_eq!(decoded.fill_defined, 1);
485 assert_eq!(decoded.fill_value, None);
486 }
487
488 #[test]
489 fn decode_bad_version() {
490 for bad in [0u8, 4, 9] {
491 let buf = [bad, 0, 0, 0];
492 match FillValueMessage::decode(&buf).unwrap_err() {
493 FormatError::InvalidVersion(v) if v == bad => {}
494 other => panic!("unexpected error for version {bad}: {other:?}"),
495 }
496 }
497 }
498
499 #[test]
500 fn decode_buffer_too_short() {
501 let buf = [3u8];
503 match FillValueMessage::decode(&buf).unwrap_err() {
504 FormatError::BufferTooShort { .. } => {}
505 other => panic!("unexpected error: {other:?}"),
506 }
507 }
508
509 #[test]
510 fn decode_v3_unknown_flag_rejected() {
511 let buf = [3u8, 0x40];
513 match FillValueMessage::decode(&buf).unwrap_err() {
514 FormatError::InvalidData(_) => {}
515 other => panic!("unexpected error: {other:?}"),
516 }
517 }
518
519 #[test]
520 fn decode_v3_truncated_size() {
521 let buf = [3u8, FLAG_HAVE_VALUE, 0xFF];
523 match FillValueMessage::decode(&buf).unwrap_err() {
524 FormatError::BufferTooShort { .. } => {}
525 other => panic!("unexpected error: {other:?}"),
526 }
527 }
528
529 #[test]
530 fn decode_v3_truncated_data() {
531 let buf = [3u8, FLAG_HAVE_VALUE, 4, 0, 0, 0, 0xAA, 0xBB];
533 match FillValueMessage::decode(&buf).unwrap_err() {
534 FormatError::BufferTooShort {
535 needed: 10,
536 available: 8,
537 } => {}
538 other => panic!("unexpected error: {other:?}"),
539 }
540 }
541
542 #[test]
543 fn version_byte() {
544 let encoded = FillValueMessage::default().encode();
545 assert_eq!(encoded[0], 3);
546 }
547
548 #[test]
549 fn tiled_fill_repeats_pattern() {
550 assert_eq!(tiled_fill(0, Some(&[1, 2])), Vec::<u8>::new());
551 assert_eq!(tiled_fill(6, None), vec![0u8; 6]);
552 assert_eq!(tiled_fill(6, Some(&[])), vec![0u8; 6]);
553 assert_eq!(
554 tiled_fill(6, Some(&[0xAB, 0xCD])),
555 vec![0xAB, 0xCD, 0xAB, 0xCD, 0xAB, 0xCD]
556 );
557 assert_eq!(tiled_fill(5, Some(&[1, 2])), vec![1, 2, 1, 2, 1]);
559 }
560
561 #[test]
565 fn a_legacy_fill_value_matches_the_bytes_libhdf5_wrote() {
566 let fv = FillValueMessage {
567 alloc_time: 2,
568 fill_write_time: 2,
569 fill_defined: 1,
570 fill_value: None,
571 };
572 let buf = fv.encode_for(crate::format::ObjectFormat::Legacy);
573 assert_eq!(buf, vec![0x02, 0x02, 0x02, 0x01, 0, 0, 0, 0]);
574 let (back, consumed) = FillValueMessage::decode(&buf).unwrap();
575 assert_eq!(consumed, buf.len());
576 assert_eq!(back, fv);
577 }
578
579 #[test]
580 fn a_legacy_user_fill_value_round_trips() {
581 let fv = FillValueMessage::with_value(vec![7, 0, 0, 0]);
582 let buf = fv.encode_for(crate::format::ObjectFormat::Legacy);
583 assert_eq!(&buf[..4], &[0x02, 0x02, 0x02, 0x01]);
584 let (back, _) = FillValueMessage::decode(&buf).unwrap();
585 assert_eq!(back, fv);
586 }
587
588 #[test]
589 fn a_legacy_undefined_fill_value_writes_no_size() {
590 let buf = FillValueMessage::undefined().encode_for(crate::format::ObjectFormat::Legacy);
591 assert_eq!(buf, vec![0x02, 0x02, 0x01, 0x00]);
592 let (back, _) = FillValueMessage::decode(&buf).unwrap();
593 assert_eq!(back, FillValueMessage::undefined());
594 }
595}