1use std::str::FromStr;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Section {
5 FunctionsTiming,
6 FunctionsAlloc,
7 Channels,
8 Streams,
9 Futures,
10 Threads,
11}
12
13impl Section {
14 pub fn all() -> Vec<Section> {
15 vec![
16 Section::FunctionsTiming,
17 Section::FunctionsAlloc,
18 Section::Channels,
19 Section::Streams,
20 Section::Futures,
21 Section::Threads,
22 ]
23 }
24
25 pub fn short_name(&self) -> &'static str {
26 match self {
27 Section::FunctionsTiming => "timing",
28 Section::FunctionsAlloc => "alloc",
29 Section::Channels => "channels",
30 Section::Streams => "streams",
31 Section::Futures => "futures",
32 Section::Threads => "threads",
33 }
34 }
35
36 pub fn from_name(s: &str) -> Option<Section> {
37 match s.trim() {
38 "functions-timing" => Some(Section::FunctionsTiming),
39 "functions-alloc" => Some(Section::FunctionsAlloc),
40 "channels" => Some(Section::Channels),
41 "streams" => Some(Section::Streams),
42 "futures" => Some(Section::Futures),
43 "threads" => Some(Section::Threads),
44 _ => None,
45 }
46 }
47
48 pub fn from_env() -> Option<Vec<Section>> {
49 std::env::var("HOTPATH_META_REPORT").ok().map(|val| {
50 let mut sections = Vec::new();
51 for part in val.split(',') {
52 match part.trim() {
53 "all" => return Section::all(),
54 other => {
55 if let Some(s) = Section::from_name(other) {
56 if !sections.contains(&s) {
57 sections.push(s);
58 }
59 } else {
60 eprintln!("[hotpath-meta] Unknown report section: '{}'", other);
61 }
62 }
63 }
64 }
65 sections
66 })
67 }
68}
69
70#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
89pub enum Format {
90 #[default]
91 Table,
92 Json,
93 JsonPretty,
94 None,
95}
96
97impl FromStr for Format {
98 type Err = String;
99
100 fn from_str(s: &str) -> Result<Self, Self::Err> {
101 match s.to_lowercase().as_str() {
102 "table" => Ok(Format::Table),
103 "json" => Ok(Format::Json),
104 "json-pretty" | "jsonpretty" => Ok(Format::JsonPretty),
105 "none" => Ok(Format::None),
106 _ => Err(format!(
107 "unknown format '{}', expected: table, json, json-pretty, none",
108 s
109 )),
110 }
111 }
112}
113
114impl Format {
115 pub fn from_env() -> Self {
118 match std::env::var("HOTPATH_META_OUTPUT_FORMAT") {
119 Ok(v) => v
120 .parse()
121 .unwrap_or_else(|e| panic!("HOTPATH_META_OUTPUT_FORMAT: {}", e)),
122 Err(_) => Format::default(),
123 }
124 }
125}
126
127pub trait IntoF64 {
128 fn into_f64(self) -> f64;
129}
130
131impl IntoF64 for f64 {
132 fn into_f64(self) -> f64 {
133 self
134 }
135}
136
137impl IntoF64 for f32 {
138 fn into_f64(self) -> f64 {
139 self as f64
140 }
141}
142
143impl IntoF64 for i8 {
144 fn into_f64(self) -> f64 {
145 self as f64
146 }
147}
148
149impl IntoF64 for i16 {
150 fn into_f64(self) -> f64 {
151 self as f64
152 }
153}
154
155impl IntoF64 for i32 {
156 fn into_f64(self) -> f64 {
157 self as f64
158 }
159}
160
161impl IntoF64 for i64 {
162 fn into_f64(self) -> f64 {
163 self as f64
164 }
165}
166
167impl IntoF64 for u8 {
168 fn into_f64(self) -> f64 {
169 self as f64
170 }
171}
172
173impl IntoF64 for u16 {
174 fn into_f64(self) -> f64 {
175 self as f64
176 }
177}
178
179impl IntoF64 for u32 {
180 fn into_f64(self) -> f64 {
181 self as f64
182 }
183}
184
185impl IntoF64 for u64 {
186 fn into_f64(self) -> f64 {
187 self as f64
188 }
189}
190
191impl IntoF64 for isize {
192 fn into_f64(self) -> f64 {
193 self as f64
194 }
195}
196
197impl IntoF64 for usize {
198 fn into_f64(self) -> f64 {
199 self as f64
200 }
201}
202
203#[cfg(feature = "hotpath-meta")]
204pub(crate) fn resolve_timeout_duration(
205 default_duration: std::time::Duration,
206 env_var: &str,
207) -> Option<std::time::Duration> {
208 let effective_duration = std::env::var(env_var)
209 .ok()
210 .and_then(|value| value.parse::<u64>().ok())
211 .map(std::time::Duration::from_millis)
212 .unwrap_or(default_duration);
213
214 if effective_duration.is_zero() {
215 None
216 } else {
217 Some(effective_duration)
218 }
219}