g_err/report/
trace_report.rs1extern crate alloc;
2use alloc::format;
3use alloc::string::String;
4use alloc::vec::Vec;
5
6use super::Report;
7use crate::gerr::{Config, Source};
8use crate::gerr_view::GErrView;
9use core::fmt::{Debug, Display, Write};
10
11pub struct TraceReport;
13
14impl Report for TraceReport {
15 fn report<E, C: Config, D>(err: &E) -> String
16 where
17 for<'a> &'a E: Into<GErrView<'a, C, D>>,
18 C::Id: Display,
19 D: Debug,
20 {
21 let err = &err.into();
22 let mut out: String = String::new();
23 Self::header(err, &mut out);
24 Self::sources(err, &mut out);
25
26 out
27 }
28}
29
30impl TraceReport {
31 fn header<C: Config, D: Debug>(err: &GErrView<C, D>, out: &mut String)
32 where
33 C::Id: Display,
34 {
35 match (err.id, err.code) {
36 (Some(id), Some(code)) => {
37 let _ = writeln!(out, "[{id}][{code}] {}", err.message);
38 }
39 (Some(id), None) => {
40 let _ = writeln!(out, "[{id}][-] {}", err.message);
41 }
42 (None, Some(code)) => {
43 let _ = writeln!(out, "[-][{code}] {}", err.message);
44 }
45 (None, None) => {
46 let _ = writeln!(out, "[-][-] {}", err.message);
47 }
48 }
49 }
50
51 fn sources<C: Config, D: Debug>(err: &GErrView<C, D>, out: &mut String) {
52 if let Some(sources) = err.sources {
53 Self::write_sources(sources, out, &mut Vec::new());
54 }
55 }
56
57 fn write_sources(
58 sources: &[Source],
59 out: &mut String,
60 ancestors: &mut Vec<bool>, ) {
62 for (idx, src) in sources.iter().enumerate() {
63 let is_last = idx + 1 == sources.len();
64
65 for &ancestor_is_last in ancestors.iter() {
67 let _ = write!(out, "{}", if ancestor_is_last { " " } else { "│ " });
68 }
69
70 let branch = if is_last { "└─ " } else { "├─ " };
71
72 match src {
73 Source::Err(e) => {
74 let _ = writeln!(out, "{branch}{e}");
75 }
76
77 Source::GErr(ge) => {
78 let msg = match (ge.id.as_ref(), ge.code.as_ref()) {
79 (Some(id), Some(code)) => {
80 format!("[{id}][{code}] {}", ge.message)
81 }
82 (Some(id), None) => {
83 format!("[{id}][-] {}", ge.message)
84 }
85 (None, Some(code)) => {
86 format!("[-][{code}] {}", ge.message)
87 }
88 (None, None) => {
89 format!("[-][-] {}", ge.message)
90 }
91 };
92
93 let _ = writeln!(out, "{branch}{msg}");
94
95 if let Some(nested) = &ge.sources {
96 ancestors.push(is_last);
97 Self::write_sources(nested, out, ancestors);
98 ancestors.pop();
99 }
100 }
101 }
102 }
103 }
104}