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)]
203pub enum Format {
204 #[default]
205 Table,
206 Json,
207 JsonPretty,
208 None,
209}
210
211impl FromStr for Format {
212 type Err = String;
213
214 fn from_str(s: &str) -> Result<Self, Self::Err> {
215 match s.to_lowercase().as_str() {
216 "table" => Ok(Format::Table),
217 "json" => Ok(Format::Json),
218 "json-pretty" | "jsonpretty" => Ok(Format::JsonPretty),
219 "none" => Ok(Format::None),
220 _ => Err(format!(
221 "unknown format '{}', expected: table, json, json-pretty, none",
222 s
223 )),
224 }
225 }
226}
227
228impl Format {
229 #[cfg(feature = "hotpath-meta")]
232 pub(crate) fn from_env() -> Self {
233 match std::env::var("HOTPATH_META_OUTPUT_FORMAT") {
234 Ok(v) => v
235 .parse()
236 .unwrap_or_else(|e| panic!("HOTPATH_META_OUTPUT_FORMAT: {}", e)),
237 Err(_) => Format::default(),
238 }
239 }
240}
241
242pub trait IntoF64 {
243 fn into_f64(self) -> f64;
244}
245
246impl IntoF64 for f64 {
247 fn into_f64(self) -> f64 {
248 self
249 }
250}
251
252impl IntoF64 for f32 {
253 fn into_f64(self) -> f64 {
254 self as f64
255 }
256}
257
258impl IntoF64 for i8 {
259 fn into_f64(self) -> f64 {
260 self as f64
261 }
262}
263
264impl IntoF64 for i16 {
265 fn into_f64(self) -> f64 {
266 self as f64
267 }
268}
269
270impl IntoF64 for i32 {
271 fn into_f64(self) -> f64 {
272 self as f64
273 }
274}
275
276impl IntoF64 for i64 {
277 fn into_f64(self) -> f64 {
278 self as f64
279 }
280}
281
282impl IntoF64 for u8 {
283 fn into_f64(self) -> f64 {
284 self as f64
285 }
286}
287
288impl IntoF64 for u16 {
289 fn into_f64(self) -> f64 {
290 self as f64
291 }
292}
293
294impl IntoF64 for u32 {
295 fn into_f64(self) -> f64 {
296 self as f64
297 }
298}
299
300impl IntoF64 for u64 {
301 fn into_f64(self) -> f64 {
302 self as f64
303 }
304}
305
306impl IntoF64 for isize {
307 fn into_f64(self) -> f64 {
308 self as f64
309 }
310}
311
312impl IntoF64 for usize {
313 fn into_f64(self) -> f64 {
314 self as f64
315 }
316}
317
318#[doc(hidden)]
319pub fn env_flag(name: &str) -> bool {
320 std::env::var(name)
321 .map(|v| v.eq_ignore_ascii_case("true") || v == "1")
322 .unwrap_or(false)
323}
324
325#[cfg(feature = "hotpath-meta")]
326pub(crate) fn resolve_timeout_duration(
327 default_duration: std::time::Duration,
328 env_var: &str,
329) -> Option<std::time::Duration> {
330 let effective_duration = std::env::var(env_var)
331 .ok()
332 .and_then(|value| value.parse::<u64>().ok())
333 .map(std::time::Duration::from_millis)
334 .unwrap_or(default_duration);
335
336 if effective_duration.is_zero() {
337 None
338 } else {
339 Some(effective_duration)
340 }
341}