Skip to main content

harness_context/
runtime.rs

1//! Concrete `World` runtime impls.
2
3use async_trait::async_trait;
4use harness_core::{Clock, KvStore, ProcessOutput, ProcessRunner};
5use std::collections::HashMap;
6use std::path::Path;
7use std::sync::Mutex;
8
9/// Real-time system clock.
10pub struct SystemClock;
11
12impl Clock for SystemClock {
13    fn now_ms(&self) -> i64 {
14        std::time::SystemTime::now()
15            .duration_since(std::time::UNIX_EPOCH)
16            .map(|d| d.as_millis() as i64)
17            .unwrap_or(0)
18    }
19}
20
21/// Subprocess runner backed by `tokio::process::Command`.
22pub struct TokioRunner;
23
24#[async_trait]
25impl ProcessRunner for TokioRunner {
26    async fn exec(
27        &self,
28        program: &str,
29        args: &[&str],
30        cwd: Option<&Path>,
31    ) -> std::io::Result<ProcessOutput> {
32        let mut cmd = tokio::process::Command::new(program);
33        cmd.args(args);
34        if let Some(c) = cwd {
35            cmd.current_dir(c);
36        }
37        let out = cmd.output().await?;
38        Ok(ProcessOutput {
39            status: out.status.code().unwrap_or(-1),
40            stdout: String::from_utf8_lossy(&out.stdout).to_string(),
41            stderr: String::from_utf8_lossy(&out.stderr).to_string(),
42        })
43    }
44}
45
46/// Thread-safe in-memory key-value store.
47pub struct InMemoryKv {
48    inner: Mutex<HashMap<String, Vec<u8>>>,
49}
50
51impl InMemoryKv {
52    pub fn new() -> Self {
53        Self {
54            inner: Mutex::new(HashMap::new()),
55        }
56    }
57}
58
59impl Default for InMemoryKv {
60    fn default() -> Self {
61        Self::new()
62    }
63}
64
65#[async_trait]
66impl KvStore for InMemoryKv {
67    async fn get(&self, key: &str) -> Option<Vec<u8>> {
68        self.inner.lock().ok()?.get(key).cloned()
69    }
70    async fn set(&self, key: &str, value: Vec<u8>) {
71        if let Ok(mut g) = self.inner.lock() {
72            g.insert(key.to_string(), value);
73        }
74    }
75    async fn delete(&self, key: &str) {
76        if let Ok(mut g) = self.inner.lock() {
77            g.remove(key);
78        }
79    }
80}