graphviz_pure_core/
diag.rs1use std::cell::{Cell, RefCell};
9use std::collections::HashSet;
10
11thread_local! {
12 static ERRORS: Cell<usize> = const { Cell::new(0) };
13 static EMITTED: RefCell<HashSet<String>> = RefCell::new(HashSet::new());
14 static QUIET: Cell<u32> = const { Cell::new(0) };
15 static SILENT: Cell<u32> = const { Cell::new(0) };
16}
17
18fn enter(depth: &'static std::thread::LocalKey<Cell<u32>>) -> impl Drop {
20 struct Guard(&'static std::thread::LocalKey<Cell<u32>>);
21 impl Drop for Guard {
22 fn drop(&mut self) {
23 self.0.with(|q| q.set(q.get() - 1));
24 }
25 }
26 depth.with(|q| q.set(q.get() + 1));
27 Guard(depth)
28}
29
30pub fn quietly<R>(f: impl FnOnce() -> R) -> R {
37 let _guard = enter(&QUIET);
38 f()
39}
40
41pub fn silently<R>(f: impl FnOnce() -> R) -> R {
43 let _guard = enter(&SILENT);
44 f()
45}
46
47pub fn reporting() -> bool {
50 QUIET.with(|q| q.get() == 0) && reporting_ports()
51}
52
53pub fn reporting_ports() -> bool {
55 SILENT.with(|q| q.get() == 0)
56}
57
58pub fn emit_once(key: &str) -> bool {
60 EMITTED.with(|e| e.borrow_mut().insert(key.to_string()))
61}
62
63pub fn agerrorf(msg: &str) {
65 crate::charset::eprint_bytes(&format!("Error: {msg}"));
66 ERRORS.with(|c| c.set(c.get() + 1));
67}
68
69pub fn agwarningf(msg: &str) {
71 crate::charset::eprint_bytes(&format!("Warning: {msg}"));
72}
73
74pub fn agerr_prev(msg: &str) {
76 crate::charset::eprint_bytes(msg);
77}
78
79pub fn fmt_g(v: f64, prec: usize) -> String {
82 fn trim(mut s: String) -> String {
83 if s.contains('.') {
84 while s.ends_with('0') {
85 s.pop();
86 }
87 if s.ends_with('.') {
88 s.pop();
89 }
90 }
91 s
92 }
93 if v.is_nan() {
94 return "nan".to_string();
96 }
97 if v.is_infinite() {
98 return if v < 0.0 { "-inf" } else { "inf" }.to_string();
99 }
100 let p = prec.max(1);
101 if v == 0.0 {
102 return if v.is_sign_negative() { "-0" } else { "0" }.to_string();
103 }
104 let e_form = format!("{:.*e}", p - 1, v);
106 let exp: i32 = e_form
107 .rsplit_once('e')
108 .and_then(|(_, e)| e.parse().ok())
109 .unwrap_or(0);
110 if exp < -4 || exp >= p as i32 {
111 let (mant, _) = e_form.rsplit_once('e').unwrap_or((&e_form, "0"));
112 let mant = trim(mant.to_string());
113 let sign = if exp < 0 { '-' } else { '+' };
114 format!("{mant}e{sign}{:02}", exp.abs())
115 } else {
116 let decimals = (p as i32 - 1 - exp).max(0) as usize;
117 trim(format!("{v:.decimals$}"))
118 }
119}
120
121pub fn error_count() -> usize {
123 ERRORS.with(Cell::get)
124}
125
126pub fn reset_errors() {
128 ERRORS.with(|c| c.set(0));
129 EMITTED.with(|e| e.borrow_mut().clear());
130}