use serde_json::{Value, json};
use crate::json::str_of;
#[derive(Debug, Clone, PartialEq)]
pub struct Invocation {
pub id: String,
pub tool: String,
pub input: Value,
}
impl Eq for Invocation {}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Capture {
pub stdout: String,
pub stderr: String,
pub exit_code: i32,
}
pub fn invocation_value(invocation: &Invocation) -> Value {
json!({ "invocation": invocation.id, "tool": invocation.tool,
"input": invocation.input })
}
pub fn invocation_of(v: &Value) -> Result<Invocation, String> {
let o = v.as_object().ok_or("invocation: not a JSON object")?;
Ok(Invocation {
id: str_of(o, "invocation").map_err(|e| format!("invocation: {e}"))?,
tool: str_of(o, "tool").map_err(|e| format!("invocation: {e}"))?,
input: o
.get("input")
.cloned()
.ok_or("invocation: missing field \"input\"")?,
})
}
pub fn capture_value(capture: &Capture) -> Value {
json!({ "stdout": capture.stdout, "stderr": capture.stderr,
"exit_code": capture.exit_code })
}
pub fn capture_of(v: &Value) -> Result<Capture, String> {
let o = v.as_object().ok_or("capture: not a JSON object")?;
Ok(Capture {
stdout: str_of(o, "stdout").map_err(|e| format!("capture: {e}"))?,
stderr: str_of(o, "stderr").map_err(|e| format!("capture: {e}"))?,
exit_code: exit_of(o.get("exit_code"))?,
})
}
fn exit_of(field: Option<&Value>) -> Result<i32, String> {
let code = field
.and_then(Value::as_i64)
.ok_or("capture: missing or non-integer field \"exit_code\"")?;
i32::try_from(code).map_err(|_| format!("capture: exit_code {code} out of range"))
}
#[cfg(test)]
mod tests;