bolt_lite/
meta.rs

1use crate::{Error, Result};
2
3pub const MAGIC: u32 = 0xED0C_DAED;
4pub const META_PAGE_FLAG: u16 = 0x04;
5pub const BRANCH_PAGE_FLAG: u16 = 0x01;
6pub const LEAF_PAGE_FLAG: u16 = 0x02;
7pub const BUCKET_VALUE_FLAG: u32 = 0x01;
8pub const META_STRUCT_OFFSET: usize = 16; // after generic page header
9
10#[derive(Clone, Copy, Debug)]
11pub(crate) struct BucketHeader {
12    pub(crate) root: u64,
13    pub(crate) _sequence: u64,
14}
15
16#[derive(Clone, Copy, Debug)]
17pub(crate) struct Meta {
18    pub(crate) root: BucketHeader,
19    pub(crate) txid: u64,
20}
21
22pub(crate) fn parse_page_size(data: &[u8]) -> Result<u32> {
23    let meta_slice = &data[..4096];
24    let magic = u32::from_le_bytes(meta_slice[META_STRUCT_OFFSET..META_STRUCT_OFFSET + 4].try_into().unwrap());
25    if magic != MAGIC {
26        return Err(Error::InvalidMagic);
27    }
28    let page_size = u32::from_le_bytes(meta_slice[META_STRUCT_OFFSET + 8..META_STRUCT_OFFSET + 12].try_into().unwrap());
29    if page_size < 1024 || page_size > 65536 {
30        return Err(Error::InvalidPageSize(page_size));
31    }
32    Ok(page_size)
33}
34
35pub(crate) fn parse_meta_at(data: &[u8], page_size: usize, offset: usize) -> Result<Meta> {
36    let end = offset + page_size;
37    if end > data.len() {
38        return Err(Error::Corrupt("meta page truncated"));
39    }
40    let page = &data[offset..end];
41    let flags = u16::from_le_bytes(page[8..10].try_into().unwrap());
42    if flags & META_PAGE_FLAG == 0 {
43        return Err(Error::Corrupt("page 0 not meta"));
44    }
45    let magic = u32::from_le_bytes(page[META_STRUCT_OFFSET..META_STRUCT_OFFSET + 4].try_into().unwrap());
46    if magic != MAGIC {
47        return Err(Error::InvalidMagic);
48    }
49    let page_size_meta = u32::from_le_bytes(page[META_STRUCT_OFFSET + 8..META_STRUCT_OFFSET + 12].try_into().unwrap());
50    if page_size_meta as usize != page_size {
51        return Err(Error::InvalidPageSize(page_size_meta));
52    }
53
54    let root = BucketHeader {
55        root: u64::from_le_bytes(page[META_STRUCT_OFFSET + 16..META_STRUCT_OFFSET + 24].try_into().unwrap()),
56        _sequence: u64::from_le_bytes(page[META_STRUCT_OFFSET + 24..META_STRUCT_OFFSET + 32].try_into().unwrap()),
57    };
58    let txid = u64::from_le_bytes(page[META_STRUCT_OFFSET + 48..META_STRUCT_OFFSET + 56].try_into().unwrap());
59
60    Ok(Meta { root, txid })
61}