1use std::error::Error;
2use std::iter;
3use std::sync::atomic::AtomicBool;
4use std::sync::{LazyLock, Mutex};
5
6#[doc(hidden)]
8pub use anstream;
9#[doc(hidden)]
10pub use owo_colors;
11use owo_colors::{DynColor, OwoColorize};
12use rustc_hash::FxHashSet;
13
14pub static ENABLED: AtomicBool = AtomicBool::new(false);
16
17pub fn enable() {
19 ENABLED.store(true, std::sync::atomic::Ordering::Relaxed);
20}
21
22pub fn disable() {
24 ENABLED.store(false, std::sync::atomic::Ordering::Relaxed);
25}
26
27#[macro_export]
29macro_rules! warn_user {
30 ($($arg:tt)*) => {{
31 use $crate::anstream::eprintln;
32 use $crate::owo_colors::OwoColorize;
33
34 if $crate::ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
35 let message = format!("{}", format_args!($($arg)*));
36 let formatted = message.bold();
37 eprintln!("{}{} {formatted}", "warning".yellow().bold(), ":".bold());
38 }
39 }};
40}
41
42pub static WARNINGS: LazyLock<Mutex<FxHashSet<String>>> = LazyLock::new(Mutex::default);
43
44#[macro_export]
47macro_rules! warn_user_once {
48 ($($arg:tt)*) => {{
49 use $crate::anstream::eprintln;
50 use $crate::owo_colors::OwoColorize;
51
52 if $crate::ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
53 if let Ok(mut states) = $crate::WARNINGS.lock() {
54 let message = format!("{}", format_args!($($arg)*));
55 if states.insert(message.clone()) {
56 eprintln!("{}{} {}", "warning".yellow().bold(), ":".bold(), message.bold());
57 }
58 }
59 }
60 }};
61}
62
63pub fn write_error_chain(
78 err: &dyn Error,
79 mut stream: impl std::fmt::Write,
80 level: impl AsRef<str>,
81 color: impl DynColor + Copy,
82) -> std::fmt::Result {
83 writeln!(
84 &mut stream,
85 "{}{} {}",
86 level.as_ref().color(color).bold(),
87 ":".bold(),
88 err.to_string().trim()
89 )?;
90 for source in iter::successors(err.source(), |&err| err.source()) {
91 writeln!(
92 &mut stream,
93 " {}: {}",
94 "Caused by".color(color).bold(),
95 source.to_string().trim()
96 )?;
97 }
98 Ok(())
99}