ruka_mir/browser_graph/
formatting.rs

1use cranelift_entity::EntityRef;
2
3use crate::naming::FunctionNames;
4use crate::{
5    LocalKind, MirAggregateArg, MirArgMode, MirBlock, MirFunction, MirLocalId, MirLocalRepr,
6    MirOwnershipMode, MirTerminator,
7};
8
9/// Render a compact block summary for the graph node label.
10pub(super) fn format_block_summary(
11    function: &MirFunction,
12    block_index: usize,
13    block: &MirBlock,
14    function_names: &FunctionNames,
15) -> String {
16    let mut parts = Vec::new();
17    if function.entry.index() == block_index {
18        parts.push("entry".to_owned());
19    }
20    if !block.params.is_empty() {
21        parts.push(format!(
22            "params {}",
23            format_local_list(&block.params, function_names)
24        ));
25    }
26    parts.push(format!("{} instr", block.instrs.len()));
27    parts.push(format_terminator_kind(&block.terminator));
28    parts.join(" | ")
29}
30
31/// Render the short terminator kind used in block summaries.
32pub(super) fn format_terminator_kind(term: &MirTerminator) -> String {
33    match term {
34        MirTerminator::Jump { target, .. } => format!("jump -> b{}", target.index()),
35        MirTerminator::Branch {
36            then_target,
37            else_target,
38            ..
39        } => format!(
40            "branch -> b{}/b{}",
41            then_target.index(),
42            else_target.index()
43        ),
44        MirTerminator::Return { .. } => "return".to_owned(),
45    }
46}
47
48/// Render a jump edge label only when block arguments are present.
49pub(super) fn format_jump_edge_label(
50    args: &[MirLocalId],
51    function_names: &FunctionNames,
52) -> Option<String> {
53    if args.is_empty() {
54        None
55    } else {
56        Some(format!(
57            "jump [{}]",
58            format_local_list(args, function_names)
59        ))
60    }
61}
62
63/// Render one MIR terminator into a compact viewer-facing line.
64pub(super) fn format_terminator(term: &MirTerminator, function_names: &FunctionNames) -> String {
65    match term {
66        MirTerminator::Jump { target, args } => {
67            format!(
68                "jump b{}({})",
69                target.index(),
70                format_local_list(args, function_names)
71            )
72        }
73        MirTerminator::Branch {
74            cond,
75            then_target,
76            else_target,
77            ..
78        } => format!(
79            "branch {} ? b{} : b{}",
80            format_local(*cond, function_names),
81            then_target.index(),
82            else_target.index()
83        ),
84        MirTerminator::Return { value } => {
85            format!("return {}", format_local(*value, function_names))
86        }
87    }
88}
89
90/// Render one MIR local into its stable viewer-facing identifier.
91pub(super) fn format_local(local: MirLocalId, function_names: &FunctionNames) -> String {
92    function_names.local_ident(local).to_owned()
93}
94
95/// Render a list of MIR locals into a compact label.
96pub(super) fn format_local_list(locals: &[MirLocalId], function_names: &FunctionNames) -> String {
97    if locals.is_empty() {
98        "-".to_string()
99    } else {
100        locals
101            .iter()
102            .map(|local| format_local(*local, function_names))
103            .collect::<Vec<_>>()
104            .join(", ")
105    }
106}
107
108/// Render one MIR control-flow edge label.
109pub(super) fn format_edge_label(
110    prefix: &str,
111    args: &[MirLocalId],
112    function_names: &FunctionNames,
113) -> String {
114    if args.is_empty() {
115        prefix.to_string()
116    } else {
117        format!("{prefix} [{}]", format_local_list(args, function_names))
118    }
119}
120
121/// Render function parameters into a compact viewer-facing label.
122pub(super) fn format_function_params(
123    function: &MirFunction,
124    function_names: &FunctionNames,
125) -> String {
126    if function.params.is_empty() {
127        return "-".to_owned();
128    }
129
130    function
131        .params
132        .iter()
133        .zip(function.param_modes.iter())
134        .map(|(local, mode)| {
135            format!(
136                "{}:{}:{}",
137                function_names.local_ident(*local),
138                format_param_mode(*mode),
139                format_local_repr(function.locals[*local].repr),
140            )
141        })
142        .collect::<Vec<_>>()
143        .join(", ")
144}
145
146/// Render a MIR parameter ownership mode into a compact label.
147pub(super) fn format_param_mode(mode: MirOwnershipMode) -> &'static str {
148    match mode {
149        MirOwnershipMode::View => "view",
150        MirOwnershipMode::MutBorrow => "mut-borrow",
151        MirOwnershipMode::Owned => "owned",
152    }
153}
154
155/// Render a MIR local provenance kind into a compact label.
156pub(super) fn format_local_kind(kind: LocalKind) -> &'static str {
157    match kind {
158        LocalKind::Param => "param",
159        LocalKind::Binding => "binding",
160        LocalKind::Temp => "temp",
161    }
162}
163
164/// Render a MIR local storage/runtime representation into a compact label.
165pub(super) fn format_local_repr(repr: MirLocalRepr) -> &'static str {
166    match repr {
167        MirLocalRepr::Value => "value",
168        MirLocalRepr::SharedPlace => "shared-place",
169        MirLocalRepr::MutablePlace => "mutable-place",
170    }
171}
172
173/// Render one MIR aggregate argument into a compact label.
174pub(super) fn format_aggregate_arg(
175    arg: &MirAggregateArg,
176    function_names: &FunctionNames,
177) -> String {
178    format!(
179        "{} {}",
180        format_call_arg_mode(arg.mode),
181        format_local(arg.local, function_names)
182    )
183}
184
185/// Render a MIR argument mode into a compact label.
186pub(super) fn format_call_arg_mode(mode: MirArgMode) -> &'static str {
187    match mode {
188        MirArgMode::Borrowed => "borrowed",
189        MirArgMode::MutableBorrow => "mutable-borrow",
190        MirArgMode::OwnedMove => "owned-move",
191        MirArgMode::OwnedCopy => "owned-copy",
192    }
193}