use serde_json::{Map, Value, json};
use super::LoginView;
use crate::boundary::codec::fields::{i64_of, list_of, opt, opt_str_of, str_of};
use crate::cli_outbound::StreamedLine;
pub(crate) fn body(view: &LoginView) -> Map<String, Value> {
let mut map = Map::new();
map.insert(
"lines".to_owned(),
json!(
view.lines
.iter()
.map(|line| json!({ "text": line.text, "err": line.err }))
.collect::<Vec<Value>>()
),
);
if let Some(exit) = view.outcome {
map.insert("outcome".to_owned(), json!(exit));
}
if let Some(command) = &view.fallback {
map.insert("fallback".to_owned(), json!(command));
}
map
}
pub(crate) fn view_of(o: &Map<String, Value>) -> Result<LoginView, String> {
Ok(LoginView {
lines: list_of(o, "lines", line_of)?,
outcome: opt(o, "outcome", exit_of)?,
fallback: opt_str_of(o, "fallback")?,
})
}
fn line_of(v: &Value) -> Result<StreamedLine, String> {
let o = v.as_object().ok_or("login: line is not an object")?;
Ok(StreamedLine {
text: str_of(o, "text")?,
err: o
.get("err")
.and_then(Value::as_bool)
.ok_or("login: missing or non-boolean field \"err\"")?,
})
}
fn exit_of(o: &Map<String, Value>, key: &str) -> Result<i32, String> {
i32::try_from(i64_of(o, key)?).map_err(|_| format!("field {key:?} out of range"))
}