1use std::str::FromStr;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Section {
5 FunctionsTiming,
6 FunctionsAlloc,
7 FunctionsCpu,
8 Channels,
9 Streams,
10 Futures,
11 RwLocks,
12 Mutexes,
13 Sql,
14 Http,
15 Io,
16 Threads,
17 Debug,
18}
19
20impl Section {
21 pub fn all() -> Vec<Section> {
22 vec![
23 Section::FunctionsTiming,
24 Section::FunctionsAlloc,
25 Section::FunctionsCpu,
26 Section::Channels,
27 Section::Streams,
28 Section::Futures,
29 Section::RwLocks,
30 Section::Mutexes,
31 Section::Sql,
32 Section::Http,
33 Section::Io,
34 Section::Threads,
35 Section::Debug,
36 ]
37 }
38
39 pub fn short_name(&self) -> &'static str {
40 match self {
41 Section::FunctionsTiming => "timing",
42 Section::FunctionsAlloc => "alloc",
43 Section::FunctionsCpu => "cpu",
44 Section::Channels => "channels",
45 Section::Streams => "streams",
46 Section::Futures => "futures",
47 Section::RwLocks => "rw_locks",
48 Section::Mutexes => "mutexes",
49 Section::Sql => "sql",
50 Section::Http => "http",
51 Section::Io => "io",
52 Section::Threads => "threads",
53 Section::Debug => "debug",
54 }
55 }
56
57 pub fn from_name(s: &str) -> Option<Section> {
58 match s.trim() {
59 "functions-timing" => Some(Section::FunctionsTiming),
60 "functions-alloc" => Some(Section::FunctionsAlloc),
61 "functions-cpu" => Some(Section::FunctionsCpu),
62 "channels" => Some(Section::Channels),
63 "streams" => Some(Section::Streams),
64 "futures" => Some(Section::Futures),
65 "rw_locks" => Some(Section::RwLocks),
66 "mutexes" => Some(Section::Mutexes),
67 "sql" => Some(Section::Sql),
68 "http" => Some(Section::Http),
69 "io" => Some(Section::Io),
70 "threads" => Some(Section::Threads),
71 "debug" => Some(Section::Debug),
72 _ => None,
73 }
74 }
75}
76
77#[cfg(feature = "hotpath-meta")]
79#[derive(Clone, Debug, PartialEq, Eq)]
80pub enum SectionsMode {
81 Auto {
86 include: Vec<Section>,
87 exclude: Vec<Section>,
88 },
89 Explicit(Vec<Section>),
91}
92
93#[cfg(feature = "hotpath-meta")]
94impl Default for SectionsMode {
95 fn default() -> Self {
96 SectionsMode::Auto {
97 include: Vec::new(),
98 exclude: Vec::new(),
99 }
100 }
101}
102
103#[cfg(feature = "hotpath-meta")]
104impl SectionsMode {
105 pub fn parse(spec: &str) -> SectionsMode {
110 let mut auto = false;
111 let mut all = false;
112 let mut include = Vec::new();
113 let mut exclude = Vec::new();
114
115 for part in spec.split(',') {
116 let part = part.trim();
117 match part {
118 "all" => all = true,
119 "auto" => auto = true,
120 _ => {
121 let (target, name) = match part.strip_prefix('-') {
122 Some(rest) => (&mut exclude, rest.trim()),
123 None => (&mut include, part),
124 };
125 if let Some(s) = Section::from_name(name) {
126 if !target.contains(&s) {
127 target.push(s);
128 }
129 } else {
130 eprintln!("[hotpath-meta] Unknown report section: '{}'", part);
131 }
132 }
133 }
134 }
135
136 if all {
137 SectionsMode::Explicit(
138 Section::all()
139 .into_iter()
140 .filter(|s| !exclude.contains(s))
141 .collect(),
142 )
143 } else if auto || !exclude.is_empty() {
144 SectionsMode::Auto { include, exclude }
145 } else {
146 SectionsMode::Explicit(include)
147 }
148 }
149
150 pub fn from_env() -> Option<SectionsMode> {
151 std::env::var("HOTPATH_META_REPORT")
152 .ok()
153 .map(|val| SectionsMode::parse(&val))
154 }
155
156 pub fn explicitly_contains(&self, section: Section) -> bool {
160 match self {
161 SectionsMode::Explicit(list) => list.contains(§ion),
162 SectionsMode::Auto { include, .. } => include.contains(§ion),
163 }
164 }
165
166 #[cfg(feature = "hotpath-cpu-meta")]
169 pub fn contains_or_auto(&self, section: Section) -> bool {
170 match self {
171 SectionsMode::Explicit(list) => list.contains(§ion),
172 SectionsMode::Auto { include, exclude } => {
173 include.contains(§ion) || !exclude.contains(§ion)
174 }
175 }
176 }
177}
178
179#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
198pub enum Format {
199 #[default]
200 Table,
201 Json,
202 JsonPretty,
203 None,
204}
205
206impl FromStr for Format {
207 type Err = String;
208
209 fn from_str(s: &str) -> Result<Self, Self::Err> {
210 match s.to_lowercase().as_str() {
211 "table" => Ok(Format::Table),
212 "json" => Ok(Format::Json),
213 "json-pretty" | "jsonpretty" => Ok(Format::JsonPretty),
214 "none" => Ok(Format::None),
215 _ => Err(format!(
216 "unknown format '{}', expected: table, json, json-pretty, none",
217 s
218 )),
219 }
220 }
221}
222
223impl Format {
224 pub fn from_env() -> Self {
227 match std::env::var("HOTPATH_META_OUTPUT_FORMAT") {
228 Ok(v) => v
229 .parse()
230 .unwrap_or_else(|e| panic!("HOTPATH_META_OUTPUT_FORMAT: {}", e)),
231 Err(_) => Format::default(),
232 }
233 }
234}
235
236pub trait IntoF64 {
237 fn into_f64(self) -> f64;
238}
239
240impl IntoF64 for f64 {
241 fn into_f64(self) -> f64 {
242 self
243 }
244}
245
246impl IntoF64 for f32 {
247 fn into_f64(self) -> f64 {
248 self as f64
249 }
250}
251
252impl IntoF64 for i8 {
253 fn into_f64(self) -> f64 {
254 self as f64
255 }
256}
257
258impl IntoF64 for i16 {
259 fn into_f64(self) -> f64 {
260 self as f64
261 }
262}
263
264impl IntoF64 for i32 {
265 fn into_f64(self) -> f64 {
266 self as f64
267 }
268}
269
270impl IntoF64 for i64 {
271 fn into_f64(self) -> f64 {
272 self as f64
273 }
274}
275
276impl IntoF64 for u8 {
277 fn into_f64(self) -> f64 {
278 self as f64
279 }
280}
281
282impl IntoF64 for u16 {
283 fn into_f64(self) -> f64 {
284 self as f64
285 }
286}
287
288impl IntoF64 for u32 {
289 fn into_f64(self) -> f64 {
290 self as f64
291 }
292}
293
294impl IntoF64 for u64 {
295 fn into_f64(self) -> f64 {
296 self as f64
297 }
298}
299
300impl IntoF64 for isize {
301 fn into_f64(self) -> f64 {
302 self as f64
303 }
304}
305
306impl IntoF64 for usize {
307 fn into_f64(self) -> f64 {
308 self as f64
309 }
310}
311
312#[doc(hidden)]
313pub fn env_flag(name: &str) -> bool {
314 std::env::var(name)
315 .map(|v| v.eq_ignore_ascii_case("true") || v == "1")
316 .unwrap_or(false)
317}
318
319#[cfg(feature = "hotpath-meta")]
320pub(crate) fn resolve_timeout_duration(
321 default_duration: std::time::Duration,
322 env_var: &str,
323) -> Option<std::time::Duration> {
324 let effective_duration = std::env::var(env_var)
325 .ok()
326 .and_then(|value| value.parse::<u64>().ok())
327 .map(std::time::Duration::from_millis)
328 .unwrap_or(default_duration);
329
330 if effective_duration.is_zero() {
331 None
332 } else {
333 Some(effective_duration)
334 }
335}