Skip to main content

hdf5_reader/messages/
link_info.rs

1//! HDF5 Link Info message (type 0x002A / 0x000A depending on spec version).
2//!
3//! Provides information about how links within a group are stored:
4//! compactly (inline in the object header) or densely (in a fractal heap
5//! indexed by a v2 B-tree).
6
7use crate::error::{Error, Result};
8use crate::io::Cursor;
9
10/// Parsed link info message.
11#[derive(Debug, Clone)]
12pub struct LinkInfoMessage {
13    /// Whether link creation order is tracked.
14    pub creation_order_tracked: bool,
15    /// Whether a creation-order B-tree index exists.
16    pub creation_order_indexed: bool,
17    /// Maximum creation order index value, if tracked.
18    pub max_creation_index: Option<u64>,
19    /// Address of the fractal heap for link names.
20    pub fractal_heap_address: u64,
21    /// Address of the v2 B-tree for name-indexed lookups.
22    pub btree_name_index_address: u64,
23    /// Address of the v2 B-tree for creation-order lookups, if indexed.
24    pub btree_creation_order_address: Option<u64>,
25}
26
27/// Parse a link info message.
28pub fn parse(
29    cursor: &mut Cursor<'_>,
30    offset_size: u8,
31    _length_size: u8,
32    msg_size: usize,
33) -> Result<LinkInfoMessage> {
34    let start = cursor.position();
35    let version = cursor.read_u8()?;
36
37    if version != 0 {
38        return Err(Error::InvalidData(format!(
39            "unsupported link info version: {}",
40            version
41        )));
42    }
43
44    let flags = cursor.read_u8()?;
45    let creation_order_tracked = (flags & 0x01) != 0;
46    let creation_order_indexed = (flags & 0x02) != 0;
47
48    let max_creation_index = if creation_order_tracked {
49        Some(cursor.read_u64_le()?)
50    } else {
51        None
52    };
53
54    let fractal_heap_address = cursor.read_offset(offset_size)?;
55    let btree_name_index_address = cursor.read_offset(offset_size)?;
56
57    let btree_creation_order_address = if creation_order_indexed {
58        Some(cursor.read_offset(offset_size)?)
59    } else {
60        None
61    };
62
63    let consumed = (cursor.position() - start) as usize;
64    if consumed < msg_size {
65        cursor.skip(msg_size - consumed)?;
66    }
67
68    Ok(LinkInfoMessage {
69        creation_order_tracked,
70        creation_order_indexed,
71        max_creation_index,
72        fractal_heap_address,
73        btree_name_index_address,
74        btree_creation_order_address,
75    })
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_parse_link_info_no_order() {
84        let mut data = vec![
85            0x00, // version
86            0x00, // flags: no creation order
87        ];
88        // fractal heap address
89        data.extend_from_slice(&0xA000u64.to_le_bytes());
90        // btree name index address
91        data.extend_from_slice(&0xB000u64.to_le_bytes());
92
93        let mut cursor = Cursor::new(&data);
94        let msg = parse(&mut cursor, 8, 8, data.len()).unwrap();
95        assert!(!msg.creation_order_tracked);
96        assert!(!msg.creation_order_indexed);
97        assert!(msg.max_creation_index.is_none());
98        assert_eq!(msg.fractal_heap_address, 0xA000);
99        assert_eq!(msg.btree_name_index_address, 0xB000);
100        assert!(msg.btree_creation_order_address.is_none());
101    }
102
103    #[test]
104    fn test_parse_link_info_with_order() {
105        let mut data = vec![
106            0x00, // version
107            0x03, // flags: creation order tracked + indexed
108        ];
109        // max creation index
110        data.extend_from_slice(&99u64.to_le_bytes());
111        // fractal heap address
112        data.extend_from_slice(&0xC000u64.to_le_bytes());
113        // btree name index
114        data.extend_from_slice(&0xD000u64.to_le_bytes());
115        // btree creation order
116        data.extend_from_slice(&0xE000u64.to_le_bytes());
117
118        let mut cursor = Cursor::new(&data);
119        let msg = parse(&mut cursor, 8, 8, data.len()).unwrap();
120        assert!(msg.creation_order_tracked);
121        assert!(msg.creation_order_indexed);
122        assert_eq!(msg.max_creation_index, Some(99));
123        assert_eq!(msg.fractal_heap_address, 0xC000);
124        assert_eq!(msg.btree_name_index_address, 0xD000);
125        assert_eq!(msg.btree_creation_order_address, Some(0xE000));
126    }
127}