1use std::{fmt, sync::OnceLock};
2
3#[derive(Clone, Copy)]
5pub struct Location(&'static std::panic::Location<'static>);
6
7impl fmt::Display for Location {
8 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9 fmt::Display::fmt(self.0, f)
10 }
11}
12
13impl fmt::Debug for Location {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 fmt::Display::fmt(self.0, f)
16 }
17}
18
19#[derive(Clone)]
23pub struct Meta {
24 location: Option<Location>,
25}
26
27impl fmt::Display for Meta {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 if let Some(location) = self.location.as_ref() {
30 write!(f, "{location}")?;
31 }
32 Ok(())
33 }
34}
35
36impl fmt::Debug for Meta {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "Meta")?;
39 if let Some(location) = self.location.as_ref() {
40 write!(f, "({location})")?;
41 }
42 Ok(())
43 }
44}
45
46#[track_caller]
48pub fn meta() -> Meta {
49 Meta::default()
50}
51
52impl Default for Meta {
53 #[track_caller]
54 fn default() -> Self {
55 Self {
56 location: location(),
57 }
58 }
59}
60
61impl Meta {
62 #[track_caller]
63 pub fn new() -> Self {
65 Self::default()
66 }
67
68 pub fn location(&self) -> Option<&Location> {
70 self.location.as_ref()
71 }
72}
73
74#[cfg(test)]
75static BACKTRACE_ENABLED: OnceLock<std::sync::RwLock<bool>> = OnceLock::new();
76
77#[cfg(not(test))]
78static BACKTRACE_ENABLED: OnceLock<bool> = OnceLock::new();
79
80#[doc(hidden)]
81pub fn backtrace_enabled() -> bool {
82 let from_env = || {
83 matches!(
84 std::env::var("RUST_BACKTRACE").as_deref(),
85 Ok("1") | Ok("full")
86 ) || matches!(std::env::var("RUST_ERROR_LOCATION").as_deref(), Ok("1"))
87 };
88 #[cfg(test)]
89 return *(BACKTRACE_ENABLED
90 .get_or_init(|| std::sync::RwLock::new(from_env()))
91 .read()
92 .unwrap());
93
94 #[cfg(not(test))]
95 return *(BACKTRACE_ENABLED.get_or_init(from_env));
96}
97
98#[doc(hidden)]
99#[cfg(test)]
100pub fn set_backtrace_enabled(value: bool) {
101 let mut inner = BACKTRACE_ENABLED
102 .get_or_init(Default::default)
103 .write()
104 .unwrap();
105 *inner = value;
106}
107
108#[track_caller]
109fn location() -> Option<Location> {
110 if backtrace_enabled() {
111 Some(Location(std::panic::Location::caller()))
112 } else {
113 None
114 }
115}