1use alloc::{
43 collections::BTreeMap,
44 string::{String, ToString},
45 sync::Arc,
46 vec::Vec,
47};
48
49#[cfg(feature = "serde")]
50use serde::{Deserialize, Serialize};
51
52use super::{AsmOpId, Decorator, DecoratorId, MastForestError, MastNodeId};
53use crate::{
54 LexicographicWord, Word,
55 mast::serialization::{
56 StringTable,
57 asm_op::{AsmOpDataBuilder, AsmOpInfo},
58 decorator::{DecoratorDataBuilder, DecoratorInfo},
59 },
60 operations::{AssemblyOp, DebugVarInfo},
61 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
62 utils::{Idx, IndexVec},
63};
64
65mod asm_op_storage;
66pub use asm_op_storage::{AsmOpIndexError, OpToAsmOpId};
67
68mod decorator_storage;
69pub use decorator_storage::{
70 DecoratedLinks, DecoratedLinksIter, DecoratorIndexError, OpToDecoratorIds,
71};
72
73mod debug_var_storage;
74pub use debug_var_storage::{DebugVarId, OpToDebugVarIds};
75
76mod node_decorator_storage;
77pub use node_decorator_storage::NodeToDecoratorIds;
78
79#[derive(Debug, Clone, PartialEq, Eq)]
84#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
85pub struct DebugInfo {
86 decorators: IndexVec<DecoratorId, Decorator>,
88
89 op_decorator_storage: OpToDecoratorIds,
91
92 node_decorator_storage: NodeToDecoratorIds,
94
95 asm_ops: IndexVec<AsmOpId, AssemblyOp>,
97
98 asm_op_storage: OpToAsmOpId,
100
101 debug_vars: IndexVec<DebugVarId, DebugVarInfo>,
103
104 op_debug_var_storage: OpToDebugVarIds,
106
107 error_codes: BTreeMap<u64, Arc<str>>,
109
110 #[cfg_attr(feature = "serde", serde(skip))]
112 procedure_names: BTreeMap<LexicographicWord, Arc<str>>,
113}
114
115impl DebugInfo {
116 pub fn new() -> Self {
121 Self {
122 decorators: IndexVec::new(),
123 op_decorator_storage: OpToDecoratorIds::new(),
124 node_decorator_storage: NodeToDecoratorIds::new(),
125 asm_ops: IndexVec::new(),
126 asm_op_storage: OpToAsmOpId::new(),
127 debug_vars: IndexVec::new(),
128 op_debug_var_storage: OpToDebugVarIds::new(),
129 error_codes: BTreeMap::new(),
130 procedure_names: BTreeMap::new(),
131 }
132 }
133
134 pub fn with_capacity(
136 decorators_capacity: usize,
137 nodes_capacity: usize,
138 operations_capacity: usize,
139 decorator_ids_capacity: usize,
140 ) -> Self {
141 Self {
142 decorators: IndexVec::with_capacity(decorators_capacity),
143 op_decorator_storage: OpToDecoratorIds::with_capacity(
144 nodes_capacity,
145 operations_capacity,
146 decorator_ids_capacity,
147 ),
148 node_decorator_storage: NodeToDecoratorIds::with_capacity(nodes_capacity, 0, 0),
149 asm_ops: IndexVec::new(),
150 asm_op_storage: OpToAsmOpId::new(),
151 debug_vars: IndexVec::new(),
152 op_debug_var_storage: OpToDebugVarIds::new(),
153 error_codes: BTreeMap::new(),
154 procedure_names: BTreeMap::new(),
155 }
156 }
157
158 pub fn empty_for_nodes(num_nodes: usize) -> Self {
160 let node_indptr_for_op_idx = IndexVec::try_from(vec![0; num_nodes + 1])
161 .expect("num_nodes should not exceed u32::MAX");
162
163 let op_decorator_storage =
164 OpToDecoratorIds::from_components(Vec::new(), Vec::new(), node_indptr_for_op_idx)
165 .expect("Empty CSR structure should be valid");
166
167 Self {
168 decorators: IndexVec::new(),
169 op_decorator_storage,
170 node_decorator_storage: NodeToDecoratorIds::new(),
171 asm_ops: IndexVec::new(),
172 asm_op_storage: OpToAsmOpId::new(),
173 debug_vars: IndexVec::new(),
174 op_debug_var_storage: OpToDebugVarIds::new(),
175 error_codes: BTreeMap::new(),
176 procedure_names: BTreeMap::new(),
177 }
178 }
179
180 pub fn is_empty(&self) -> bool {
186 self.decorators.is_empty()
187 && self.asm_ops.is_empty()
188 && self.debug_vars.is_empty()
189 && self.error_codes.is_empty()
190 && self.procedure_names.is_empty()
191 }
192
193 pub fn clear(&mut self) {
199 self.clear_mappings();
200 self.decorators = IndexVec::new();
201 self.asm_ops = IndexVec::new();
202 self.asm_op_storage = OpToAsmOpId::new();
203 self.debug_vars = IndexVec::new();
204 self.op_debug_var_storage.clear();
205 self.error_codes.clear();
206 self.procedure_names.clear();
207 }
208
209 pub fn num_decorators(&self) -> usize {
214 self.decorators.len()
215 }
216
217 pub fn decorators(&self) -> &[Decorator] {
219 self.decorators.as_slice()
220 }
221
222 pub fn decorator(&self, decorator_id: DecoratorId) -> Option<&Decorator> {
224 self.decorators.get(decorator_id)
225 }
226
227 pub fn before_enter_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
229 self.node_decorator_storage.get_before_decorators(node_id)
230 }
231
232 pub fn after_exit_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
234 self.node_decorator_storage.get_after_decorators(node_id)
235 }
236
237 pub fn decorators_for_operation(
239 &self,
240 node_id: MastNodeId,
241 local_op_idx: usize,
242 ) -> &[DecoratorId] {
243 self.op_decorator_storage
244 .decorator_ids_for_operation(node_id, local_op_idx)
245 .unwrap_or(&[])
246 }
247
248 pub(super) fn decorator_links_for_node(
250 &self,
251 node_id: MastNodeId,
252 ) -> Result<DecoratedLinks<'_>, DecoratorIndexError> {
253 self.op_decorator_storage.decorator_links_for_node(node_id)
254 }
255
256 pub fn num_debug_vars(&self) -> usize {
261 self.debug_vars.len()
262 }
263
264 pub fn debug_vars(&self) -> &[DebugVarInfo] {
266 self.debug_vars.as_slice()
267 }
268
269 pub fn debug_var(&self, debug_var_id: DebugVarId) -> Option<&DebugVarInfo> {
271 self.debug_vars.get(debug_var_id)
272 }
273
274 pub fn debug_vars_for_operation(
276 &self,
277 node_id: MastNodeId,
278 local_op_idx: usize,
279 ) -> &[DebugVarId] {
280 self.op_debug_var_storage
281 .debug_var_ids_for_operation(node_id, local_op_idx)
282 .unwrap_or(&[])
283 }
284
285 pub fn add_decorator(&mut self, decorator: Decorator) -> Result<DecoratorId, MastForestError> {
290 self.decorators.push(decorator).map_err(|_| MastForestError::TooManyDecorators)
291 }
292
293 pub(super) fn decorator_mut(&mut self, decorator_id: DecoratorId) -> Option<&mut Decorator> {
295 if decorator_id.to_usize() < self.decorators.len() {
296 Some(&mut self.decorators[decorator_id])
297 } else {
298 None
299 }
300 }
301
302 pub(super) fn register_node_decorators(
308 &mut self,
309 node_id: MastNodeId,
310 before_enter: &[DecoratorId],
311 after_exit: &[DecoratorId],
312 ) {
313 self.node_decorator_storage
314 .add_node_decorators(node_id, before_enter, after_exit);
315 }
316
317 pub(crate) fn register_op_indexed_decorators(
321 &mut self,
322 node_id: MastNodeId,
323 decorators_info: Vec<(usize, DecoratorId)>,
324 ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> {
325 self.op_decorator_storage.add_decorator_info_for_node(node_id, decorators_info)
326 }
327
328 pub fn clear_mappings(&mut self) {
332 self.op_decorator_storage = OpToDecoratorIds::new();
333 self.node_decorator_storage.clear();
334 }
335
336 pub fn num_asm_ops(&self) -> usize {
341 self.asm_ops.len()
342 }
343
344 pub fn asm_ops(&self) -> &[AssemblyOp] {
346 self.asm_ops.as_slice()
347 }
348
349 pub fn asm_op(&self, asm_op_id: AsmOpId) -> Option<&AssemblyOp> {
351 self.asm_ops.get(asm_op_id)
352 }
353
354 pub fn asm_op_for_operation(&self, node_id: MastNodeId, op_idx: usize) -> Option<&AssemblyOp> {
356 let asm_op_id = self.asm_op_storage.asm_op_id_for_operation(node_id, op_idx)?;
357 self.asm_ops.get(asm_op_id)
358 }
359
360 pub fn first_asm_op_for_node(&self, node_id: MastNodeId) -> Option<&AssemblyOp> {
362 let asm_op_id = self.asm_op_storage.first_asm_op_for_node(node_id)?;
363 self.asm_ops.get(asm_op_id)
364 }
365
366 pub fn add_asm_op(&mut self, asm_op: AssemblyOp) -> Result<AsmOpId, MastForestError> {
371 self.asm_ops.push(asm_op).map_err(|_| MastForestError::TooManyDecorators)
372 }
373
374 pub fn register_asm_ops(
380 &mut self,
381 node_id: MastNodeId,
382 num_operations: usize,
383 asm_ops: Vec<(usize, AsmOpId)>,
384 ) -> Result<(), AsmOpIndexError> {
385 self.asm_op_storage.add_asm_ops_for_node(node_id, num_operations, asm_ops)
386 }
387
388 pub(super) fn remap_asm_op_storage(&mut self, remapping: &BTreeMap<MastNodeId, MastNodeId>) {
393 self.asm_op_storage = self.asm_op_storage.remap_nodes(remapping);
394 }
395
396 pub fn add_debug_var(
401 &mut self,
402 debug_var: DebugVarInfo,
403 ) -> Result<DebugVarId, MastForestError> {
404 self.debug_vars.push(debug_var).map_err(|_| MastForestError::TooManyDecorators)
405 }
406
407 pub fn register_op_indexed_debug_vars(
411 &mut self,
412 node_id: MastNodeId,
413 debug_vars_info: Vec<(usize, DebugVarId)>,
414 ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> {
415 self.op_debug_var_storage.add_debug_var_info_for_node(node_id, debug_vars_info)
416 }
417
418 pub fn error_message(&self, code: u64) -> Option<Arc<str>> {
423 self.error_codes.get(&code).cloned()
424 }
425
426 pub fn error_codes(&self) -> impl Iterator<Item = (&u64, &Arc<str>)> {
428 self.error_codes.iter()
429 }
430
431 pub fn insert_error_code(&mut self, code: u64, msg: Arc<str>) {
433 self.error_codes.insert(code, msg);
434 }
435
436 pub fn extend_error_codes<I>(&mut self, error_codes: I)
440 where
441 I: IntoIterator<Item = (u64, Arc<str>)>,
442 {
443 self.error_codes.extend(error_codes);
444 }
445
446 pub fn clear_error_codes(&mut self) {
450 self.error_codes.clear();
451 }
452
453 pub fn procedure_name(&self, digest: &Word) -> Option<&str> {
458 self.procedure_names.get(&LexicographicWord::from(*digest)).map(|s| s.as_ref())
459 }
460
461 pub fn procedure_names(&self) -> impl Iterator<Item = (Word, &Arc<str>)> {
463 self.procedure_names.iter().map(|(key, name)| (key.into_inner(), name))
464 }
465
466 pub fn num_procedure_names(&self) -> usize {
468 self.procedure_names.len()
469 }
470
471 pub fn insert_procedure_name(&mut self, digest: Word, name: Arc<str>) {
473 self.procedure_names.insert(LexicographicWord::from(digest), name);
474 }
475
476 pub fn extend_procedure_names<I>(&mut self, names: I)
478 where
479 I: IntoIterator<Item = (Word, Arc<str>)>,
480 {
481 self.procedure_names
482 .extend(names.into_iter().map(|(d, n)| (LexicographicWord::from(d), n)));
483 }
484
485 pub fn clear_procedure_names(&mut self) {
487 self.procedure_names.clear();
488 }
489
490 pub(super) fn validate(&self) -> Result<(), String> {
504 let decorator_count = self.decorators.len();
505 let asm_op_count = self.asm_ops.len();
506
507 self.op_decorator_storage.validate_csr(decorator_count)?;
509
510 self.node_decorator_storage.validate_csr(decorator_count)?;
512
513 self.asm_op_storage.validate_csr(asm_op_count)?;
515
516 let debug_var_count = self.debug_vars.len();
518 self.op_debug_var_storage.validate_csr(debug_var_count)?;
519
520 Ok(())
521 }
522
523 #[cfg(test)]
528 pub(crate) fn op_decorator_storage(&self) -> &OpToDecoratorIds {
529 &self.op_decorator_storage
530 }
531}
532
533impl Serializable for DebugInfo {
534 fn write_into<W: ByteWriter>(&self, target: &mut W) {
535 let mut decorator_data_builder = DecoratorDataBuilder::new();
537 for decorator in self.decorators.iter() {
538 decorator_data_builder.add_decorator(decorator);
539 }
540 let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
541
542 decorator_data.write_into(target);
543 string_table.write_into(target);
544 decorator_infos.write_into(target);
545
546 let error_codes: BTreeMap<u64, String> =
548 self.error_codes.iter().map(|(k, v)| (*k, v.to_string())).collect();
549 error_codes.write_into(target);
550
551 self.op_decorator_storage.write_into(target);
556
557 self.node_decorator_storage.write_into(target);
559
560 let procedure_names: BTreeMap<Word, String> =
562 self.procedure_names().map(|(k, v)| (k, v.to_string())).collect();
563 procedure_names.write_into(target);
564
565 let mut asm_op_data_builder = AsmOpDataBuilder::new();
567 for asm_op in self.asm_ops.iter() {
568 asm_op_data_builder.add_asm_op(asm_op);
569 }
570 let (asm_op_data, asm_op_infos, asm_op_string_table) = asm_op_data_builder.finalize();
571
572 asm_op_data.write_into(target);
573 asm_op_string_table.write_into(target);
574 asm_op_infos.write_into(target);
575
576 self.asm_op_storage.write_into(target);
578
579 self.debug_vars.write_into(target);
581
582 self.op_debug_var_storage.write_into(target);
584 }
585}
586
587impl Deserializable for DebugInfo {
588 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
589 let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
591 let string_table: StringTable = Deserializable::read_from(source)?;
592 let decorator_infos: Vec<DecoratorInfo> = Deserializable::read_from(source)?;
593
594 let mut decorators = IndexVec::new();
596 for decorator_info in decorator_infos {
597 let decorator = decorator_info.try_into_decorator(&string_table, &decorator_data)?;
598 decorators.push(decorator).map_err(|_| {
599 DeserializationError::InvalidValue(
600 "Failed to add decorator to IndexVec".to_string(),
601 )
602 })?;
603 }
604
605 let error_codes_raw: BTreeMap<u64, String> = Deserializable::read_from(source)?;
607 let error_codes: BTreeMap<u64, Arc<str>> =
608 error_codes_raw.into_iter().map(|(k, v)| (k, Arc::from(v.as_str()))).collect();
609
610 let op_decorator_storage = OpToDecoratorIds::read_from(source, decorators.len())?;
612
613 let node_decorator_storage = NodeToDecoratorIds::read_from(source, decorators.len())?;
615
616 let procedure_names_raw: BTreeMap<Word, String> = Deserializable::read_from(source)?;
620 let procedure_names: BTreeMap<LexicographicWord, Arc<str>> = procedure_names_raw
621 .into_iter()
622 .map(|(k, v)| (LexicographicWord::from(k), Arc::from(v.as_str())))
623 .collect();
624
625 let asm_op_data: Vec<u8> = Deserializable::read_from(source)?;
627 let asm_op_string_table: StringTable = Deserializable::read_from(source)?;
628 let asm_op_infos: Vec<AsmOpInfo> = Deserializable::read_from(source)?;
629
630 let mut asm_ops = IndexVec::new();
632 for asm_op_info in asm_op_infos {
633 let asm_op = asm_op_info.try_into_asm_op(&asm_op_string_table, &asm_op_data)?;
634 asm_ops.push(asm_op).map_err(|_| {
635 DeserializationError::InvalidValue(
636 "Failed to add AssemblyOp to IndexVec".to_string(),
637 )
638 })?;
639 }
640
641 let asm_op_storage = OpToAsmOpId::read_from(source, asm_ops.len())?;
643
644 let debug_vars: IndexVec<DebugVarId, DebugVarInfo> = Deserializable::read_from(source)?;
646
647 let op_debug_var_storage = OpToDebugVarIds::read_from(source, debug_vars.len())?;
649
650 let debug_info = DebugInfo {
652 decorators,
653 op_decorator_storage,
654 node_decorator_storage,
655 asm_ops,
656 asm_op_storage,
657 debug_vars,
658 op_debug_var_storage,
659 error_codes,
660 procedure_names,
661 };
662
663 debug_info.validate().map_err(|e| {
664 DeserializationError::InvalidValue(format!("DebugInfo validation failed: {}", e))
665 })?;
666
667 Ok(debug_info)
668 }
669}
670
671impl Default for DebugInfo {
672 fn default() -> Self {
673 Self::new()
674 }
675}