Skip to main content

oxiphysics_io/hdf5_io/
encoding.rs

1// Copyright 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3
4//! Byte-layout simulation for object headers and superblock encoding.
5
6#![allow(dead_code)]
7
8use super::file::{Hdf5ObjectHeader, Hdf5Superblock};
9use super::types::{Hdf5Error, Hdf5Result};
10
11// ---------------------------------------------------------------------------
12// Object header encoding
13// ---------------------------------------------------------------------------
14
15/// Simulate encoding an object header into a byte vector.
16///
17/// Real HDF5 uses a complex binary format; here we produce a human-readable
18/// ASCII summary padded to a fixed size for unit-testing purposes.
19pub fn encode_object_header(header: &Hdf5ObjectHeader) -> Vec<u8> {
20    let raw = format!(
21        "OBJ|type={}|addr={}|msgs={}|size={}",
22        header.object_type, header.address, header.n_messages, header.header_size
23    );
24    let mut out = raw.into_bytes();
25    out.resize(64, 0);
26    out
27}
28
29/// Decode an object header from bytes (inverse of `encode_object_header`).
30pub fn decode_object_header(bytes: &[u8]) -> Hdf5Result<Hdf5ObjectHeader> {
31    let s = std::str::from_utf8(bytes)
32        .map_err(|_| Hdf5Error::Generic("header bytes are not valid UTF-8".to_string()))?
33        .trim_end_matches('\0');
34    let parts: Vec<&str> = s.split('|').collect();
35    if parts.len() < 5 || parts[0] != "OBJ" {
36        return Err(Hdf5Error::Generic(format!("invalid header: {s}")));
37    }
38    let parse_kv =
39        |kv: &str| -> Option<String> { kv.split_once('=').map(|x| x.1).map(|v| v.to_string()) };
40    let object_type = parse_kv(parts[1]).unwrap_or_default();
41    let address: u64 = parse_kv(parts[2]).and_then(|v| v.parse().ok()).unwrap_or(0);
42    let n_messages: u32 = parse_kv(parts[3]).and_then(|v| v.parse().ok()).unwrap_or(0);
43    let header_size: u32 = parse_kv(parts[4].trim_end_matches('\0'))
44        .and_then(|v| v.parse().ok())
45        .unwrap_or(0);
46    Ok(Hdf5ObjectHeader {
47        object_type,
48        address,
49        n_messages,
50        header_size,
51    })
52}
53
54// ---------------------------------------------------------------------------
55// Superblock encoding
56// ---------------------------------------------------------------------------
57
58/// Encode a superblock as a fixed 64-byte byte vector (mock layout).
59pub fn encode_superblock(sb: &Hdf5Superblock) -> Vec<u8> {
60    let raw = format!(
61        "SB|v={}|fs={}|roff={}|eof={}|sl={}|so={}",
62        sb.version,
63        sb.file_size,
64        sb.root_obj_header_offset,
65        sb.eof_address,
66        sb.size_of_lengths,
67        sb.size_of_offsets
68    );
69    let mut out = raw.into_bytes();
70    out.resize(128, 0);
71    out
72}
73
74/// Decode a superblock from bytes.
75pub fn decode_superblock(bytes: &[u8]) -> Hdf5Result<Hdf5Superblock> {
76    let s = std::str::from_utf8(bytes)
77        .map_err(|_| Hdf5Error::Generic("superblock bytes are not valid UTF-8".to_string()))?
78        .trim_end_matches('\0');
79    let parts: Vec<&str> = s.split('|').collect();
80    if parts.len() < 7 || parts[0] != "SB" {
81        return Err(Hdf5Error::Generic(format!("invalid superblock: {s}")));
82    }
83    let parse_u8 = |kv: &str| -> u8 {
84        kv.split_once('=')
85            .map(|x| x.1)
86            .and_then(|v| v.parse().ok())
87            .unwrap_or(0)
88    };
89    let parse_u64 = |kv: &str| -> u64 {
90        kv.split_once('=')
91            .map(|x| x.1)
92            .and_then(|v| v.parse().ok())
93            .unwrap_or(0)
94    };
95    Ok(Hdf5Superblock {
96        version: parse_u8(parts[1]),
97        file_size: parse_u64(parts[2]),
98        root_obj_header_offset: parse_u64(parts[3]),
99        eof_address: parse_u64(parts[4]),
100        size_of_lengths: parse_u8(parts[5]),
101        size_of_offsets: parse_u8(parts[6].trim_end_matches('\0')),
102    })
103}