use super::{Context, args};
use crate::boundary::{Action, Gesture};
use crate::fan::Verb;
pub(super) fn read(verb: &str, tail: &str, ctx: &Context) -> Result<Gesture, String> {
match verb {
"fan" => fan(tail, ctx, verb),
"retire" => retire(tail, ctx, verb),
_ => deliver(tail, ctx, verb),
}
}
fn fan(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
let n = args::required(tail, verb, "how many candidates")?;
Ok(Gesture::Act(Action::Fan(Verb::Spread {
prepared: prepared(ctx, verb)?,
obligation: obligation(ctx, verb)?,
n: n.parse()
.map_err(|_| format!("/{verb}: {n:?} is not a count; usage: /fan <n>"))?,
})))
}
fn retire(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
Ok(Gesture::Act(Action::Fan(Verb::Retire {
obligation: obligation(ctx, verb)?,
handle: args::required(tail, verb, "the candidate handle")?,
})))
}
fn deliver(tail: &str, ctx: &Context, verb: &str) -> Result<Gesture, String> {
let tail = tail.trim();
let missing =
|what: &str| format!("/{verb}: {what} is required; usage: /deliver <handle> <summary…>");
if tail.is_empty() {
return Err(missing("the candidate handle"));
}
let (handle, summary) = tail
.split_once(char::is_whitespace)
.map(|(h, s)| (h, s.trim_start()))
.filter(|(_, s)| !s.is_empty())
.ok_or_else(|| missing("the delivery summary"))?;
Ok(Gesture::Act(Action::Fan(Verb::Deliver {
obligation: obligation(ctx, verb)?,
handle: handle.to_owned(),
summary: summary.to_owned(),
})))
}
fn obligation(ctx: &Context, verb: &str) -> Result<crate::fan::Obligation, String> {
Ok(crate::fan::Obligation {
project: args::project(ctx, verb)?,
ball: Some(super::balls::id("", ctx, verb)?),
})
}
fn prepared(ctx: &Context, verb: &str) -> Result<crate::start::Prepared, String> {
ctx.prepared
.clone()
.ok_or_else(|| format!("/{verb}: nothing is prepared — /prepare first"))
}