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; #[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}