From: Ian Jackson Date: Wed, 19 May 2021 21:01:11 +0000 (+0100) Subject: otter(1): Generalise alter-game-json ad-hoc subcommand (1) X-Git-Tag: otter-0.6.0~147 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=46d5e4c658ce878f4dd04ed3aad5b1069fa0d7c8;p=otter.git otter(1): Generalise alter-game-json ad-hoc subcommand (1) Signed-off-by: Ian Jackson --- diff --git a/src/bin/otter.rs b/src/bin/otter.rs index 596505bd..7bc4128b 100644 --- a/src/bin/otter.rs +++ b/src/bin/otter.rs @@ -108,9 +108,9 @@ impl From<&anyhow::Error> for ArgumentParseError { } } -fn parse_args( +fn parse_args<'apm,T:Default,U>( args: Vec, - apmaker: &dyn Fn(&mut T) -> ArgumentParser, + apmaker: &'apm dyn for <'a> Fn(&'a mut T) -> ArgumentParser<'a>, completer: &dyn Fn(T) -> Result, extra_help: Option<&dyn Fn(&mut dyn Write) -> Result<(), io::Error>>, ) -> U { @@ -242,6 +242,12 @@ pub fn in_basedir(verbose: bool, } } +// argparse is pretty insistent about references and they are awkward +#[ext] +impl String { + fn leak(self) -> &'static str { Box::::leak(self.into()) } +} + fn main() { #[derive(Default,Debug)] struct RawMainArgs { @@ -1358,34 +1364,44 @@ mod list_pieces { //---------- alter game json ---------- -mod alter_game_json { +mod alter_game_adhoc { use super::*; #[derive(Default,Debug)] struct Args { table_name: String, - json: Vec, + insns: Vec, } - fn subargs(sa: &mut Args) -> ArgumentParser { + fn subargs<'ap,'a:'ap,'m:'ap>( + sa: &'a mut Args, + fmtname: &'_ str, + ) -> ArgumentParser<'ap> { use argparse::*; + let ufmtname = fmtname.to_uppercase(); let mut ap = ArgumentParser::new(); ap.refer(&mut sa.table_name).required() .add_argument("TABLE-NAME",Store,"table name"); - ap.refer(&mut sa.json).required() - .add_argument("JSON-INSN",Collect,"JSON-encoded MgmtGameInstruction"); + ap.refer(&mut sa.insns).required() + .add_argument(format!("{}-INSN", &ufmtname).leak(), + Collect, + format!("{}-encoded MgmtGameInstruction", &ufmtname) + .leak()); ap } - #[throws(AE)] - fn call(_sc: &Subcommand, ma: MainOpts, args: Vec) { - let args = parse_args::(args, &subargs, &ok_id, None); + fn call(sc: &Subcommand, ma: MainOpts, args: Vec) -> Result<(),AE> { + let fmtname = sc.0.rsplitn(2,'-').next().unwrap(); + + let subargs: &dyn for<'a> Fn(&'a mut Args) -> ArgumentParser<'a> + = &|sa| subargs(sa,fmtname); + let args = parse_args::(args, subargs, &ok_id, None); let mut chan = access_game(&ma, &args.table_name)?; - let insns = args.json.iter().enumerate().map(|(i,s)|{ + let insns = args.insns.iter().enumerate().map(|(i,s)|{ serde_json::from_str(&s) .with_context(|| s.clone()) - .with_context(|| format!("parse json insn (#{})", i)) + .with_context(|| format!("parse insn (#{})", i)) }).collect::,AE>>()?; let resps = chan.alter_game(insns,None)?; @@ -1393,8 +1409,9 @@ mod alter_game_json { for resp in resps { println!("{}", serde_json::to_string(&resp) - .context("re-format json")?); + .context("re-format response")?); } + Ok(()) } inventory::submit!{Subcommand(