format: resolve virtual dataset mappings over Storage
DataLayout::resolve_vds_mappings_in reads the global heap collection holding a virtual dataset's mappings through GlobalHeapCollection:: parse_in; resolve_vds_mappings is a wrapper. The rest of the data layout module parses message payloads and does not read the file. New test: the virtual dataset of vds_same_file.h5 resolves to the same mappings through a read_at-only CountingStorage, in two reads. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
@@ -7,6 +7,7 @@ use alloc::{format, string::String, vec::Vec};
|
|||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
use crate::error::FormatError;
|
use crate::error::FormatError;
|
||||||
|
use crate::storage::Storage;
|
||||||
|
|
||||||
/// A single VDS (Virtual Dataset) source mapping.
|
/// A single VDS (Virtual Dataset) source mapping.
|
||||||
///
|
///
|
||||||
@@ -309,6 +310,16 @@ impl DataLayout {
|
|||||||
&mut self,
|
&mut self,
|
||||||
file_data: &[u8],
|
file_data: &[u8],
|
||||||
length_size: 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(
|
||||||
|
&mut self,
|
||||||
|
file_data: &dyn Storage,
|
||||||
|
length_size: u8,
|
||||||
) -> Result<(), FormatError> {
|
) -> Result<(), FormatError> {
|
||||||
if let DataLayout::Virtual {
|
if let DataLayout::Virtual {
|
||||||
global_heap_address,
|
global_heap_address,
|
||||||
@@ -318,11 +329,8 @@ impl DataLayout {
|
|||||||
} = self
|
} = self
|
||||||
&& let Some(addr) = *global_heap_address
|
&& let Some(addr) = *global_heap_address
|
||||||
{
|
{
|
||||||
let coll = crate::global_heap::GlobalHeapCollection::parse(
|
let coll =
|
||||||
file_data,
|
crate::global_heap::GlobalHeapCollection::parse_in(file_data, addr, length_size)?;
|
||||||
addr as usize,
|
|
||||||
length_size,
|
|
||||||
)?;
|
|
||||||
let obj = coll.get_object(*global_heap_index as u16).ok_or(
|
let obj = coll.get_object(*global_heap_index as u16).ok_or(
|
||||||
FormatError::GlobalHeapObjectNotFound {
|
FormatError::GlobalHeapObjectNotFound {
|
||||||
collection_address: addr,
|
collection_address: addr,
|
||||||
@@ -1305,4 +1313,44 @@ mod tests {
|
|||||||
let blob = [0x01u8, 0, 0, 0, 0, 0, 0, 0, 0];
|
let blob = [0x01u8, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
assert!(parse_vds_mappings(&blob, 8).unwrap().is_empty());
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user