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                    if let Ok(config) = Self::load(&candidate) {
34                        return config;
35                    }
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)
47            .map_err(|e| format!("invalid config in {}: {e}", path.display()))
48    }
49
50    pub fn apply_env(&self) {
51        if let Some(secs) = self.timeout {
52            if std::env::var("RUN_TIMEOUT_SECS").is_err() {
53                // SAFETY: called once at startup before any threads are spawned.
54                unsafe { std::env::set_var("RUN_TIMEOUT_SECS", secs.to_string()); }
55            }
56        }
57        if let Some(true) = self.timing {
58            if std::env::var("RUN_TIMING").is_err() {
59                // SAFETY: called once at startup before any threads are spawned.
60                unsafe { std::env::set_var("RUN_TIMING", "1"); }
61            }
62        }
63    }
64
65    pub fn find_config_path() -> Option<PathBuf> {
66        let cwd = std::env::current_dir().ok()?;
67        for dir in cwd.ancestors() {
68            for name in &["run.toml", ".runrc"] {
69                let candidate = dir.join(name);
70                if candidate.is_file() {
71                    return Some(candidate);
72                }
73            }
74        }
75        None
76    }
77}