1use core::fmt;
4
5#[cfg(feature = "musli")]
6use musli_core::{Decode, Encode};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate as rune;
11use crate::alloc::prelude::*;
12use crate::alloc::{Box, HashMap, Vec};
13use crate::ast::Span;
14use crate::runtime::DebugLabel;
15use crate::{Hash, ItemBuf, SourceId};
16
17#[derive(Debug, TryClone, Default)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
21#[non_exhaustive]
22pub struct DebugInfo {
23 pub instructions: HashMap<usize, DebugInst>,
25 pub functions: HashMap<Hash, DebugSignature>,
27 pub functions_rev: HashMap<usize, Hash>,
29 pub hash_to_ident: HashMap<Hash, Box<str>>,
31 pub globals: Vec<DebugGlobal>,
36}
37
38impl DebugInfo {
39 pub fn instruction_at(&self, ip: usize) -> Option<&DebugInst> {
41 self.instructions.get(&ip)
42 }
43
44 pub fn function_at(&self, ip: usize) -> Option<(Hash, &DebugSignature)> {
46 let hash = *self.functions_rev.get(&ip)?;
47 let signature = self.functions.get(&hash)?;
48 Some((hash, signature))
49 }
50
51 pub fn ident_for_hash(&self, hash: Hash) -> Option<&str> {
53 Some(self.hash_to_ident.get(&hash)?)
54 }
55
56 pub fn global(&self, slot: usize) -> Option<&DebugGlobal> {
58 self.globals.get(slot)
59 }
60}
61
62#[derive(Debug, TryClone)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
66#[non_exhaustive]
67pub struct DebugGlobal {
68 pub path: ItemBuf,
70}
71
72impl DebugGlobal {
73 #[inline]
75 pub fn new(path: ItemBuf) -> Self {
76 Self { path }
77 }
78}
79
80impl fmt::Display for DebugGlobal {
81 #[inline]
82 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(fmt, "{}", self.path)
84 }
85}
86
87#[derive(Debug, TryClone)]
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
91#[non_exhaustive]
92pub struct DebugInst {
93 pub source_id: SourceId,
95 pub span: Span,
97 pub comment: Option<Box<str>>,
99 pub labels: Vec<DebugLabel>,
101}
102
103impl DebugInst {
104 pub fn new(
106 source_id: SourceId,
107 span: Span,
108 comment: Option<Box<str>>,
109 labels: Vec<DebugLabel>,
110 ) -> Self {
111 Self {
112 source_id,
113 span,
114 comment,
115 labels,
116 }
117 }
118}
119
120#[derive(Debug, TryClone)]
122#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
123#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
124#[non_exhaustive]
125pub enum DebugArgs {
126 EmptyArgs,
128 TupleArgs(usize),
130 Named(Box<[Box<str>]>),
132}
133
134#[derive(Debug, TryClone)]
136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
138#[non_exhaustive]
139pub struct DebugSignature {
140 pub path: ItemBuf,
142 pub args: DebugArgs,
144}
145
146impl DebugSignature {
147 #[inline]
149 pub fn new(path: ItemBuf, args: DebugArgs) -> Self {
150 Self { path, args }
151 }
152}
153
154impl fmt::Display for DebugSignature {
155 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
156 match &self.args {
157 DebugArgs::EmptyArgs => {
158 write!(fmt, "{}", self.path)?;
159 }
160 DebugArgs::TupleArgs(args) if *args > 0 => {
161 write!(fmt, "{}(", self.path)?;
162
163 let mut it = 0..*args;
164 let last = it.next_back();
165
166 for arg in it {
167 write!(fmt, "{arg}, ")?;
168 }
169
170 if let Some(arg) = last {
171 write!(fmt, "{arg}")?;
172 }
173
174 write!(fmt, ")")?;
175 }
176 DebugArgs::Named(args) => {
177 write!(fmt, "{}(", self.path)?;
178
179 let mut it = args.iter();
180 let last = it.next_back();
181
182 for arg in it {
183 write!(fmt, "{arg}, ")?;
184 }
185
186 if let Some(arg) = last {
187 write!(fmt, "{arg}")?;
188 }
189
190 write!(fmt, ")")?;
191 }
192 _ => (),
193 }
194
195 Ok(())
196 }
197}