Skip to main content

hotpath_meta/
shared.rs

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    Threads,
15    Debug,
16}
17
18impl Section {
19    pub fn all() -> Vec<Section> {
20        vec![
21            Section::FunctionsTiming,
22            Section::FunctionsAlloc,
23            Section::FunctionsCpu,
24            Section::Channels,
25            Section::Streams,
26            Section::Futures,
27            Section::RwLocks,
28            Section::Mutexes,
29            Section::Sql,
30            Section::Threads,
31            Section::Debug,
32        ]
33    }
34
35    pub fn short_name(&self) -> &'static str {
36        match self {
37            Section::FunctionsTiming => "timing",
38            Section::FunctionsAlloc => "alloc",
39            Section::FunctionsCpu => "cpu",
40            Section::Channels => "channels",
41            Section::Streams => "streams",
42            Section::Futures => "futures",
43            Section::RwLocks => "rw_locks",
44            Section::Mutexes => "mutexes",
45            Section::Sql => "sql",
46            Section::Threads => "threads",
47            Section::Debug => "debug",
48        }
49    }
50
51    pub fn from_name(s: &str) -> Option<Section> {
52        match s.trim() {
53            "functions-timing" => Some(Section::FunctionsTiming),
54            "functions-alloc" => Some(Section::FunctionsAlloc),
55            "functions-cpu" => Some(Section::FunctionsCpu),
56            "channels" => Some(Section::Channels),
57            "streams" => Some(Section::Streams),
58            "futures" => Some(Section::Futures),
59            "rw_locks" => Some(Section::RwLocks),
60            "mutexes" => Some(Section::Mutexes),
61            "sql" => Some(Section::Sql),
62            "threads" => Some(Section::Threads),
63            "debug" => Some(Section::Debug),
64            _ => None,
65        }
66    }
67
68    pub fn from_env() -> Option<Vec<Section>> {
69        std::env::var("HOTPATH_META_REPORT").ok().map(|val| {
70            let mut sections = Vec::new();
71            for part in val.split(',') {
72                match part.trim() {
73                    "all" => return Section::all(),
74                    other => {
75                        if let Some(s) = Section::from_name(other) {
76                            if !sections.contains(&s) {
77                                sections.push(s);
78                            }
79                        } else {
80                            eprintln!("[hotpath-meta] Unknown report section: '{}'", other);
81                        }
82                    }
83                }
84            }
85            sections
86        })
87    }
88}
89
90/// Output format for profiling reports.
91///
92/// This enum specifies how profiling results should be displayed when the program exits.
93///
94/// # Variants
95///
96/// * `Table` - Human-readable table format (default)
97/// * `Json` - JSON format
98/// * `JsonPretty` - Pretty-printed JSON format
99/// * `None` - Suppress all profiling output (metrics server and MCP server still function)
100///
101/// # Parsing
102///
103/// Can be parsed from strings via `HOTPATH_META_OUTPUT_FORMAT` environment variable:
104/// - `"table"` → `Format::Table`
105/// - `"json"` → `Format::Json`
106/// - `"json-pretty"` → `Format::JsonPretty`
107/// - `"none"` → `Format::None`
108#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
109pub enum Format {
110    #[default]
111    Table,
112    Json,
113    JsonPretty,
114    None,
115}
116
117impl FromStr for Format {
118    type Err = String;
119
120    fn from_str(s: &str) -> Result<Self, Self::Err> {
121        match s.to_lowercase().as_str() {
122            "table" => Ok(Format::Table),
123            "json" => Ok(Format::Json),
124            "json-pretty" | "jsonpretty" => Ok(Format::JsonPretty),
125            "none" => Ok(Format::None),
126            _ => Err(format!(
127                "unknown format '{}', expected: table, json, json-pretty, none",
128                s
129            )),
130        }
131    }
132}
133
134impl Format {
135    /// Returns the format from `HOTPATH_META_OUTPUT_FORMAT` env var, or default if not set.
136    /// Panics if the env var contains an invalid value.
137    pub fn from_env() -> Self {
138        match std::env::var("HOTPATH_META_OUTPUT_FORMAT") {
139            Ok(v) => v
140                .parse()
141                .unwrap_or_else(|e| panic!("HOTPATH_META_OUTPUT_FORMAT: {}", e)),
142            Err(_) => Format::default(),
143        }
144    }
145}
146
147pub trait IntoF64 {
148    fn into_f64(self) -> f64;
149}
150
151impl IntoF64 for f64 {
152    fn into_f64(self) -> f64 {
153        self
154    }
155}
156
157impl IntoF64 for f32 {
158    fn into_f64(self) -> f64 {
159        self as f64
160    }
161}
162
163impl IntoF64 for i8 {
164    fn into_f64(self) -> f64 {
165        self as f64
166    }
167}
168
169impl IntoF64 for i16 {
170    fn into_f64(self) -> f64 {
171        self as f64
172    }
173}
174
175impl IntoF64 for i32 {
176    fn into_f64(self) -> f64 {
177        self as f64
178    }
179}
180
181impl IntoF64 for i64 {
182    fn into_f64(self) -> f64 {
183        self as f64
184    }
185}
186
187impl IntoF64 for u8 {
188    fn into_f64(self) -> f64 {
189        self as f64
190    }
191}
192
193impl IntoF64 for u16 {
194    fn into_f64(self) -> f64 {
195        self as f64
196    }
197}
198
199impl IntoF64 for u32 {
200    fn into_f64(self) -> f64 {
201        self as f64
202    }
203}
204
205impl IntoF64 for u64 {
206    fn into_f64(self) -> f64 {
207        self as f64
208    }
209}
210
211impl IntoF64 for isize {
212    fn into_f64(self) -> f64 {
213        self as f64
214    }
215}
216
217impl IntoF64 for usize {
218    fn into_f64(self) -> f64 {
219        self as f64
220    }
221}
222
223#[doc(hidden)]
224pub fn env_flag(name: &str) -> bool {
225    std::env::var(name)
226        .map(|v| v.eq_ignore_ascii_case("true") || v == "1")
227        .unwrap_or(false)
228}
229
230#[cfg(feature = "hotpath-meta")]
231pub(crate) fn resolve_timeout_duration(
232    default_duration: std::time::Duration,
233    env_var: &str,
234) -> Option<std::time::Duration> {
235    let effective_duration = std::env::var(env_var)
236        .ok()
237        .and_then(|value| value.parse::<u64>().ok())
238        .map(std::time::Duration::from_millis)
239        .unwrap_or(default_duration);
240
241    if effective_duration.is_zero() {
242        None
243    } else {
244        Some(effective_duration)
245    }
246}