use anyhow::Result;
use rudy_types::{BTreeNodeLayout, BTreeRootLayout, MapLayout, MapVariant};
use super::{primitives::entry_type, Parser};
use crate::{
parser::{
children::parse_children,
option::parse_option_entry,
pointers::nonnull,
primitives::{data_offset, is_member, member, resolved_generic},
},
Die, DwarfDb,
};
pub fn btree_map() -> BTreeMapParser {
BTreeMapParser
}
pub struct BTreeMapParser;
impl<'db> Parser<'db, MapLayout<Die<'db>>> for BTreeMapParser {
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<MapLayout<Die<'db>>> {
tracing::debug!("resolving btree map type: {}", entry.print(db));
let (key_type, value_type, (root_offset, root_option_type), length_offset) =
parse_children((
resolved_generic("K"),
resolved_generic("V"),
is_member("root").then(data_offset().and(entry_type())),
is_member("length").then(data_offset()),
))
.parse(db, entry)?;
tracing::debug!("resolving root field: {}", root_option_type.print(db));
let (_, _, _, some_variant) = parse_option_entry().parse(db, root_option_type)?;
let node_ref_type = some_variant.layout;
tracing::debug!("resolving node ref field: {}", node_ref_type.print(db));
let (height_offset, (node_offset, node_ptr_type)) = parse_children((
is_member("height").then(data_offset()),
is_member("node").then(data_offset().and(entry_type())),
))
.parse(db, node_ref_type)?;
let root_layout = BTreeRootLayout {
node_offset,
height_offset,
};
let leaf_node_type = nonnull().parse(db, node_ptr_type)?;
tracing::debug!("resolving leaf node type: {}", leaf_node_type.print(db));
let (len_offset, keys_offset, vals_offset) = parse_children((
is_member("len").then(data_offset()),
is_member("keys").then(data_offset()),
is_member("vals").then(data_offset()),
))
.parse(db, leaf_node_type)?;
let parent_option_type = member("parent")
.then(entry_type())
.parse(db, leaf_node_type)?;
let (_, _, _, parent_some_variant) = parse_option_entry().parse(db, parent_option_type)?;
let internal_node_type = nonnull().parse(db, parent_some_variant.layout)?;
let edges_offset = member("edges")
.then(data_offset())
.parse(db, internal_node_type)?;
let node_layout = BTreeNodeLayout {
keys_offset,
vals_offset,
len_offset,
edges_offset,
};
Ok(MapLayout {
key_type,
value_type,
variant: MapVariant::BTreeMap {
length_offset,
root_offset,
root_layout,
node_layout,
},
})
}
}