diff --git a/crates/clawhdf5-format/src/fill_value.rs b/crates/clawhdf5-format/src/fill_value.rs index 3b18790..88cbc3f 100644 --- a/crates/clawhdf5-format/src/fill_value.rs +++ b/crates/clawhdf5-format/src/fill_value.rs @@ -111,14 +111,19 @@ pub fn dataset_fill_value(messages: &[HeaderMessage]) -> Result>, /// fill value message to where it lives: another object header, or the /// file's shared-message (SOHM) heap, as libhdf5 writes it when the file has /// a SOHM index for fill values. -pub fn dataset_fill_value_in( - file_data: &[u8], +/// +/// `file_data` is any [`Storage`](crate::storage::Storage): the file as a +/// `&[u8]`, or a backend that serves it by range. (The trait is not +/// imported here: its `len` would shadow the slice method in this module.) +pub fn dataset_fill_value_in( + file_data: &S, messages: &[HeaderMessage], offset_size: u8, length_size: u8, ) -> Result>, FormatError> { + let file: &dyn crate::storage::Storage = &file_data; fill_value_from(messages, |msg| { - crate::shared_message::message_data_with_sohm(file_data, msg, offset_size, length_size) + crate::shared_message::message_data_with_sohm_in(file, msg, offset_size, length_size) .map(|data| data.into_owned()) }) } @@ -439,4 +444,37 @@ mod tests { .collect(); assert_eq!(filled, [2, 3, 7, 8]); } + + /// Fill values, shared ones in the SOHM heap included, resolve + /// identically through a read_at-only CountingStorage. + #[test] + fn storage_reads_match_slice_reads() { + use crate::object_header::ObjectHeader; + use crate::storage::CountingStorage; + let file: &[u8] = include_bytes!("../tests/fixtures/shared_fill_value.h5"); + let sb = crate::superblock::Superblock::parse(file, 0).unwrap(); + let (os, ls) = (sb.offset_size, sb.length_size); + let storage = CountingStorage::new(file.to_vec()); + let mut shared = 0; + let children = + crate::group_v2::resolve_group_children(file, &sb, sb.root_group_address).unwrap(); + assert!(children.len() >= 3); + for child in children { + let h = + ObjectHeader::parse(file, child.object_header_address as usize, os, ls).unwrap(); + shared += h + .messages + .iter() + .filter(|m| { + m.msg_type == MessageType::FillValue + && crate::shared_message::is_shared(m.flags) + }) + .count(); + let want = dataset_fill_value_in(file, &h.messages, os, ls); + assert_eq!(want, Ok(Some((-7i32).to_le_bytes().to_vec()))); + let got = dataset_fill_value_in(&storage, &h.messages, os, ls); + assert_eq!(got, want, "{}", child.name); + } + assert!(shared >= 2); + } }