Merge branch 'feat/p3-storage-trait' into feat/p3-range-zfp-edit

# Conflicts:
#	CHANGELOG.md
#	crates/clawhdf5-format/src/attribute.rs
#	crates/clawhdf5-format/src/btree_v1.rs
#	crates/clawhdf5-format/src/data_layout.rs
#	crates/clawhdf5-format/src/extensible_array.rs
#	crates/clawhdf5-format/src/fixed_array.rs
#	crates/clawhdf5-format/src/fractal_heap.rs
#	crates/clawhdf5-format/src/local_heap.rs
#	crates/clawhdf5-format/src/shared_message.rs
This commit is contained in:
osobh
2026-09-26 14:51:51 -05:00
26 changed files with 3480 additions and 497 deletions
+53 -5
View File
@@ -8,6 +8,7 @@ use std::string::String;
use crate::addr::to_usize;
use crate::error::FormatError;
use crate::storage::Storage;
/// A single VDS (Virtual Dataset) source mapping.
///
@@ -310,6 +311,16 @@ impl DataLayout {
&mut self,
file_data: &[u8],
length_size: u8,
) -> Result<(), FormatError> {
self.resolve_vds_mappings_in(file_data, length_size)
}
/// [`Self::resolve_vds_mappings`] over any [`Storage`]: one read of the
/// global heap collection holding the mappings.
pub fn resolve_vds_mappings_in<S: Storage + ?Sized>(
&mut self,
file_data: &S,
length_size: u8,
) -> Result<(), FormatError> {
if let DataLayout::Virtual {
global_heap_address,
@@ -319,11 +330,8 @@ impl DataLayout {
} = self
&& let Some(addr) = *global_heap_address
{
let coll = crate::global_heap::GlobalHeapCollection::parse(
file_data,
to_usize(addr)?,
length_size,
)?;
let coll =
crate::global_heap::GlobalHeapCollection::parse_in(file_data, addr, length_size)?;
let obj = coll.get_object(*global_heap_index as u16).ok_or(
FormatError::GlobalHeapObjectNotFound {
collection_address: addr,
@@ -1306,4 +1314,44 @@ mod tests {
let blob = [0x01u8, 0, 0, 0, 0, 0, 0, 0, 0];
assert!(parse_vds_mappings(&blob, 8).unwrap().is_empty());
}
/// A virtual dataset's mappings resolve identically through a
/// read_at-only CountingStorage, in two reads of the global heap.
#[test]
fn vds_mappings_through_storage_match_slice() {
use crate::message_type::MessageType;
use crate::object_header::ObjectHeader;
use crate::storage::CountingStorage;
let file: &[u8] = include_bytes!("../tests/fixtures/vds_same_file.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 virtuals = 0;
for child in
crate::group_v2::resolve_group_children(file, &sb, sb.root_group_address).unwrap()
{
let h =
ObjectHeader::parse(file, child.object_header_address as usize, os, ls).unwrap();
let Some(msg) = h
.messages
.iter()
.find(|m| m.msg_type == MessageType::DataLayout)
else {
continue;
};
let mut want = DataLayout::parse(&msg.data, os, ls).unwrap();
if !matches!(want, DataLayout::Virtual { .. }) {
continue;
}
let mut got = want.clone();
want.resolve_vds_mappings(file, ls).unwrap();
storage.reset();
got.resolve_vds_mappings_in(&storage, ls).unwrap();
assert_eq!(format!("{got:?}"), format!("{want:?}"));
assert!(matches!(&got, DataLayout::Virtual { mappings, .. } if !mappings.is_empty()));
assert_eq!(storage.reads(), 2);
virtuals += 1;
}
assert!(virtuals >= 1);
}
}