use std::collections::HashMap; /// A unique identifier for a node in the call graph. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct NodeId(pub usize); /// Represents a single parsed frame in the call stack. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Frame { pub raw: String, pub namespace: Option, pub symbol: Option, } impl Frame { pub fn new(raw: String, namespace: Option, symbol: Option) -> Self { Self { raw, namespace, symbol } } } /// A node in the source property tree (call graph). #[derive(Debug, Clone)] pub struct SourceNode { pub id: NodeId, pub parent: Option, pub children: HashMap, pub frame: Frame, pub inclusive_weight: u64, pub exclusive_weight: u64, } impl SourceNode { pub fn new(id: NodeId, parent: Option, frame: Frame) -> Self { Self { id, parent, children: HashMap::new(), frame, inclusive_weight: 0, exclusive_weight: 0, } } } /// Represents the canonical internal graph built from the profile lines. #[derive(Debug)] pub struct SourceGraph { pub nodes: Vec, pub root: NodeId, } impl SourceGraph { pub fn new() -> Self { let root_frame = Frame::new("[root]".to_string(), None, None); let root_node = SourceNode::new(NodeId(0), None, root_frame); Self { nodes: vec![root_node], root: NodeId(0), } } pub fn get_node(&self, id: NodeId) -> Option<&SourceNode> { self.nodes.get(id.0) } pub fn get_node_mut(&mut self, id: NodeId) -> Option<&mut SourceNode> { self.nodes.get_mut(id.0) } pub fn add_node(&mut self, parent: NodeId, frame: Frame) -> NodeId { let id = NodeId(self.nodes.len()); let raw_label = frame.raw.clone(); let node = SourceNode::new(id, Some(parent), frame); self.nodes.push(node); if let Some(parent_node) = self.get_node_mut(parent) { parent_node.children.insert(raw_label, id); } id } } impl Default for SourceGraph { fn default() -> Self { Self::new() } }