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    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/// Output format for profiling reports.
71///
72/// This enum specifies how profiling results should be displayed when the program exits.
73///
74/// # Variants
75///
76/// * `Table` - Human-readable table format (default)
77/// * `Json` - JSON format
78/// * `JsonPretty` - Pretty-printed JSON format
79/// * `None` - Suppress all profiling output (metrics server and MCP server still function)
80///
81/// # Parsing
82///
83/// Can be parsed from strings via `HOTPATH_META_OUTPUT_FORMAT` environment variable:
84/// - `"table"` → `Format::Table`
85/// - `"json"` → `Format::Json`
86/// - `"json-pretty"` → `Format::JsonPretty`
87/// - `"none"` → `Format::None`
88#[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    /// Returns the format from `HOTPATH_META_OUTPUT_FORMAT` env var, or default if not set.
116    /// Panics if the env var contains an invalid value.
117    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}