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