use serde_json::{Map, Value, json};
use crate::boundary::Action;
use crate::fork::Attempt;
use super::start::encode_path;
use super::{path_of, str_of};
pub(super) fn encode(
workspace: &std::path::Path,
parent: &str,
attempt: &Attempt,
goal: &str,
) -> Value {
json!({ "op": "fork", "workspace": encode_path(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: path_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()
}