use serde_json::{Map, Value, json};
use crate::boundary::Action;
use crate::fan::{Obligation, Verb};
use super::start::encode_prepared;
use super::{decode_prepared, opt_field, opt_str_of, str_of, usize_of};
pub(super) const FAN: &str = "fan";
pub(super) const RETIRE: &str = "retire";
pub(super) const DELIVER: &str = "deliver";
pub(super) fn encode_verb(verb: &Verb) -> Value {
match verb {
Verb::Spread {
prepared,
obligation,
n,
} => encode(prepared, obligation, *n),
Verb::Retire { obligation, handle } => encode_retire(obligation, handle),
Verb::Deliver {
obligation,
handle,
summary,
} => encode_deliver(obligation, handle, summary),
}
}
pub(super) fn encode(
prepared: &crate::start::Prepared,
obligation: &Obligation,
n: usize,
) -> Value {
let mut map = obligation_map(FAN, obligation);
map.insert("prepared".to_owned(), encode_prepared(prepared));
map.insert("n".to_owned(), json!(n));
Value::Object(map)
}
pub(super) fn encode_retire(obligation: &Obligation, handle: &str) -> Value {
let mut map = obligation_map(RETIRE, obligation);
map.insert("handle".to_owned(), json!(handle));
Value::Object(map)
}
pub(super) fn encode_deliver(obligation: &Obligation, handle: &str, summary: &str) -> Value {
let mut map = obligation_map(DELIVER, obligation);
map.insert("handle".to_owned(), json!(handle));
map.insert("summary".to_owned(), json!(summary));
Value::Object(map)
}
fn obligation_map(op: &str, obligation: &Obligation) -> Map<String, Value> {
let mut map = Map::new();
map.insert("op".to_owned(), json!(op));
map.insert(
"project".to_owned(),
Value::String(obligation.project.clone()),
);
opt_field(&mut map, "ball", obligation.ball.as_ref());
map
}
pub(super) fn decode(op: &str, o: &Map<String, Value>) -> Result<Action, String> {
let obligation = Obligation {
project: str_of(o, "project")?,
ball: opt_str_of(o, "ball")?,
};
if op == RETIRE {
return Ok(Action::Fan(Verb::Retire {
obligation,
handle: str_of(o, "handle")?,
}));
}
if op == DELIVER {
return Ok(Action::Fan(Verb::Deliver {
obligation,
handle: str_of(o, "handle")?,
summary: str_of(o, "summary")?,
}));
}
Ok(Action::Fan(Verb::Spread {
prepared: decode_prepared(o.get("prepared").ok_or("fan: missing prepared")?)?,
obligation,
n: usize_of(o, "n")?,
}))
}