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