use serde_json::{Map, Value, json};
use crate::boundary::Action;
use crate::fork::Attempt;
use super::str_of;
pub(super) fn encode(workspace: &str, parent: &str, attempt: &Attempt, goal: &str) -> Value {
json!({ "op": "fork", "workspace": workspace, "parent": parent,
"from": attempt.from, "role": attempt.role, "skills": attempt.skills,
"goal": goal })
}
pub(super) fn decode(o: &Map<String, Value>) -> Result<Action, String> {
Ok(Action::Fork {
workspace: str_of(o, "workspace")?,
parent: str_of(o, "parent")?,
attempt: Attempt {
from: str_of(o, "from")?,
role: str_of(o, "role")?,
skills: words_of(o, "skills")?,
},
goal: str_of(o, "goal")?,
})
}
fn words_of(obj: &Map<String, Value>, key: &str) -> Result<Vec<String>, String> {
let Some(value) = obj.get(key) else {
return Ok(Vec::new());
};
let wrong = || format!("field {key:?} must be an array of strings");
value
.as_array()
.ok_or_else(wrong)?
.iter()
.map(|item| item.as_str().map(str::to_owned).ok_or_else(wrong))
.collect()
}