Skip to main content

run/
config.rs

1use std::path::{Path, PathBuf};
2
3use serde::Deserialize;
4
5/// Project-level configuration loaded from `run.toml` or `.runrc`.
6#[derive(Debug, Default, Deserialize)]
7#[serde(default)]
8pub struct RunConfig {
9    /// Default language when none is specified.
10    pub language: Option<String>,
11    /// Execution timeout in seconds.
12    pub timeout: Option<u64>,
13    /// Always show execution timing.
14    pub timing: Option<bool>,
15    /// Default benchmark iterations.
16    pub bench_iterations: Option<u32>,
17}
18
19impl RunConfig {
20    /// Search for a config file in the current directory and ancestors.
21    /// Checks `run.toml`, then `.runrc` (TOML format).
22    pub fn discover() -> Self {
23        let cwd = std::env::current_dir().ok();
24        let cwd = match cwd {
25            Some(ref p) => p.as_path(),
26            None => return Self::default(),
27        };
28
29        for dir in cwd.ancestors() {
30            for name in &["run.toml", ".runrc"] {
31                let candidate = dir.join(name);
32                if candidate.is_file()
33                    && let Ok(config) = Self::load(&candidate)
34                {
35                    return config;
36                }
37            }
38        }
39
40        Self::default()
41    }
42
43    pub fn load(path: &Path) -> Result<Self, String> {
44        let content = std::fs::read_to_string(path)
45            .map_err(|e| format!("failed to read {}: {e}", path.display()))?;
46        toml::from_str(&content).map_err(|e| format!("invalid config in {}: {e}", path.display()))
47    }
48
49    pub fn apply_env(&self) {
50        if let Some(secs) = self.timeout
51            && std::env::var("RUN_TIMEOUT_SECS").is_err()
52        {
53            // SAFETY: called once at startup before any threads are spawned.
54            unsafe {
55                std::env::set_var("RUN_TIMEOUT_SECS", secs.to_string());
56            }
57        }
58        if let Some(true) = self.timing
59            && std::env::var("RUN_TIMING").is_err()
60        {
61            // SAFETY: called once at startup before any threads are spawned.
62            unsafe {
63                std::env::set_var("RUN_TIMING", "1");
64            }
65        }
66    }
67
68    pub fn find_config_path() -> Option<PathBuf> {
69        let cwd = std::env::current_dir().ok()?;
70        for dir in cwd.ancestors() {
71            for name in &["run.toml", ".runrc"] {
72                let candidate = dir.join(name);
73                if candidate.is_file() {
74                    return Some(candidate);
75                }
76            }
77        }
78        None
79    }
80}