ci: wire up CI, fix no_std build, fix stale package names in scripts
CI / test (push) Failing after 15s

- Add .gitea/workflows/ci.yml running scripts/ci-test.sh (fmt, clippy,
  test, no_std check) on push/PR to main.
- Fix stale rustyhdf5-py/rustyhdf5-format package names in
  ci-test.sh/check-nostd.sh, which had been silently no-op'ing those
  checks (cargo warns but doesn't fail on an unknown --exclude/-p
  target).
- With those checks actually running, fix the real issues they surface:
  - clippy: useless_conversion in chunked_write.rs, byte_char_slices in
    global_heap.rs/object_header.rs.
  - cargo fmt: apply formatting across the workspace (whitespace only).
  - no_std (thumbv7em-none-eabihf) build errors in clawhdf5-format:
    core::sync::atomic::AtomicU64 doesn't exist on that target (no
    native 64-bit atomics) — switch profiling.rs's counters to
    portable-atomic, which falls back to a CAS-based emulation there
    and is a no-op wrapper elsewhere. Add missing alloc imports for
    Box (filters.rs), Vec (filters_szip.rs), and format! (dict_encoding.rs)
    on no_std paths. Replace f64::powi (std/libm-only) with a small
    local exponentiation-by-squaring helper in the scale-offset filter.
This commit is contained in:
Omar Sobh
2026-08-05 10:50:13 -07:00
parent b70d594c4f
commit 55959b4920
34 changed files with 590 additions and 365 deletions
+56 -34
View File
@@ -375,7 +375,8 @@ fn build_multiblock_fractal_heap(
let table_width: u16 = 4;
let starting_block_size: u64 = 512;
let dblock_header_size = 4 + 1 + os + block_offset_bytes + 4;
let block_capacity = |row: usize| block_size_for_row(starting_block_size, row) - dblock_header_size as u64;
let block_capacity =
|row: usize| block_size_for_row(starting_block_size, row) - dblock_header_size as u64;
// ---- Pack objects into direct blocks (row-major over the doubling table) ----
struct Blk {
@@ -542,7 +543,26 @@ fn block_size_for_row(starting_block_size: u64, row: usize) -> u64 {
/// Size in bytes of the FRHP header for the given offset/length sizes.
fn frhp_header_size(os: usize, ls: usize) -> usize {
4 + 1 + 2 + 2 + 1 + 4 + ls + os + ls + os + ls + ls + ls + ls + ls + ls + ls + ls + 2 + ls + ls
4 + 1
+ 2
+ 2
+ 1
+ 4
+ ls
+ os
+ ls
+ os
+ ls
+ ls
+ ls
+ ls
+ ls
+ ls
+ ls
+ ls
+ 2
+ ls
+ ls
+ 2
+ 2
+ os
@@ -670,8 +690,7 @@ pub(crate) fn build_dense_attrs(attrs: &[AttributeMessage], base_address: u64) -
// Pad to node_size
btlf.resize(node_size as usize, 0);
let mut blob =
Vec::with_capacity(heap.blob.len() + bthd.len() + btlf.len());
let mut blob = Vec::with_capacity(heap.blob.len() + bthd.len() + btlf.len());
blob.extend_from_slice(&heap.blob);
blob.extend_from_slice(&bthd);
blob.extend_from_slice(&btlf);
@@ -762,8 +781,7 @@ pub(crate) fn build_dense_links(links: &[LinkMessage], base_address: u64) -> Den
btlf.extend_from_slice(&btlf_checksum.to_le_bytes());
btlf.resize(node_size as usize, 0);
let mut blob =
Vec::with_capacity(heap.blob.len() + bthd.len() + btlf.len());
let mut blob = Vec::with_capacity(heap.blob.len() + bthd.len() + btlf.len());
blob.extend_from_slice(&heap.blob);
blob.extend_from_slice(&bthd);
blob.extend_from_slice(&btlf);
@@ -1096,10 +1114,7 @@ impl FileWriter {
root_attrs.push(build_attr_message(n, v));
}
let is_vds: Vec<bool> = all_ds
.iter()
.map(|d| d.virtual_sources.is_some())
.collect();
let is_vds: Vec<bool> = all_ds.iter().map(|d| d.virtual_sources.is_some()).collect();
let is_chunked: Vec<bool> = all_ds
.iter()
.enumerate()
@@ -1198,7 +1213,8 @@ impl FileWriter {
// Global heap blob size is address-independent; compute it now
// so pass 2 can place it correctly.
let vds_mappings = d.virtual_sources.as_deref().unwrap_or(&[]);
let gcol_bytes = build_global_heap_collection(&serialize_vds_mappings(vds_mappings));
let gcol_bytes =
build_global_heap_collection(&serialize_vds_mappings(vds_mappings));
dummy_blobs.push(DataBlob {
data: gcol_bytes, // store heap blob here temporarily
oh_bytes: oh,
@@ -1216,8 +1232,11 @@ impl FileWriter {
elem_size,
&d.chunk_options,
)?;
let result =
build_chunked_data_from_precompressed(&pre, dummy_cursor, d.maxshape.as_deref());
let result = build_chunked_data_from_precompressed(
&pre,
dummy_cursor,
d.maxshape.as_deref(),
);
dummy_cursor += result.data_bytes.len() as u64;
let dense_blob = if ds_dense[i] {
Some(build_dense_attrs(&d.attrs, 0))
@@ -1391,7 +1410,10 @@ impl FileWriter {
// Reuse precompressed chunks from Pass 1 — avoids re-compressing
// the same data a second time.
let result = build_chunked_data_from_precompressed(
dummy_blobs[i].precompressed.as_ref().expect("chunked dataset missing precompressed cache"),
dummy_blobs[i]
.precompressed
.as_ref()
.expect("chunked dataset missing precompressed cache"),
base_address,
d.maxshape.as_deref(),
);
@@ -1492,7 +1514,9 @@ impl FileWriter {
// Rebuild the root link blob with real target addresses (same size as
// the dummy used for layout); its LinkInfo goes in the OH.
let root_link_blob = root_link_blob_addr.map(|addr| build_dense_links(&root_links, addr));
let root_dl = root_link_blob.as_ref().map(|b| b.link_info_message.as_slice());
let root_dl = root_link_blob
.as_ref()
.map(|b| b.link_info_message.as_slice());
buf.extend_from_slice(&build_group_oh(
&root_links,
root_dl,
@@ -1903,14 +1927,14 @@ mod tests {
fn sel_hyper_1d(start: u16, block: u16) -> Vec<u8> {
let mut v = vec![
2, 0, 0, 0, // type = HYPER
3, 0, 0, 0, // version 3
0x01, // flags = regular
0x02, // enc_size = 2 (u16 per coordinate)
3, 0, 0, 0, // version 3
0x01, // flags = regular
0x02, // enc_size = 2 (u16 per coordinate)
1, 0, 0, 0, // rank = 1
];
v.extend_from_slice(&start.to_le_bytes()); // start
v.extend_from_slice(&1u16.to_le_bytes()); // stride
v.extend_from_slice(&1u16.to_le_bytes()); // count
v.extend_from_slice(&1u16.to_le_bytes()); // stride
v.extend_from_slice(&1u16.to_le_bytes()); // count
v.extend_from_slice(&block.to_le_bytes()); // block
v
}
@@ -1936,8 +1960,10 @@ mod tests {
let mut fw = FileWriter::new();
// Source datasets (real data in this file)
fw.create_dataset("src_a").with_f64_data(&[1.0, 2.0, 3.0, 4.0]);
fw.create_dataset("src_b").with_f64_data(&[5.0, 6.0, 7.0, 8.0]);
fw.create_dataset("src_a")
.with_f64_data(&[1.0, 2.0, 3.0, 4.0]);
fw.create_dataset("src_b")
.with_f64_data(&[5.0, 6.0, 7.0, 8.0]);
// Virtual dataset
fw.create_dataset("vds")
.with_shape(&[8])
@@ -1950,13 +1976,8 @@ mod tests {
let sig = signature::find_signature(&bytes).unwrap();
let sb = Superblock::parse(&bytes, sig).unwrap();
let vds_addr = resolve_path_any(&bytes, &sb, "vds").unwrap();
let hdr = ObjectHeader::parse(
&bytes,
vds_addr as usize,
sb.offset_size,
sb.length_size,
)
.unwrap();
let hdr =
ObjectHeader::parse(&bytes, vds_addr as usize, sb.offset_size, sb.length_size).unwrap();
let dl_data = &hdr
.messages
@@ -1965,8 +1986,7 @@ mod tests {
.unwrap()
.data;
let mut layout =
DataLayout::parse(dl_data, sb.offset_size, sb.length_size).unwrap();
let mut layout = DataLayout::parse(dl_data, sb.offset_size, sb.length_size).unwrap();
// Before resolution, mappings field is empty.
assert!(
@@ -2033,8 +2053,7 @@ mod tests {
.find(|m| m.msg_type == MessageType::DataLayout)
.unwrap()
.data;
let mut layout =
DataLayout::parse(dl_data, sb.offset_size, sb.length_size).unwrap();
let mut layout = DataLayout::parse(dl_data, sb.offset_size, sb.length_size).unwrap();
layout.resolve_vds_mappings(&bytes, sb.length_size).unwrap();
match &layout {
@@ -2112,7 +2131,10 @@ mod tests {
.expect("external link 'remote_temp' not found in group OH");
match &ext_link.link_target {
crate::link_message::LinkTarget::External { filename, object_path } => {
crate::link_message::LinkTarget::External {
filename,
object_path,
} => {
assert_eq!(filename, "other_file.h5");
assert_eq!(object_path, "/temperature");
}