1use std::path::{Path, PathBuf};
2
3use serde::Deserialize;
4
5#[derive(Debug, Default, Deserialize)]
7#[serde(default)]
8pub struct RunConfig {
9 pub language: Option<String>,
11 pub timeout: Option<u64>,
13 pub timing: Option<bool>,
15 pub bench_iterations: Option<u32>,
17}
18
19impl RunConfig {
20 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 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 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}