From 8e0badc9988775b1b0340db5b2cb975c3ecf407d Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Mon, 14 Jan 2019 16:27:21 -0800 Subject: Auto-generate execute methods for generated command enums Not too long ago we added a macro to auto generate the command enums and the required trait implementations from a concise declarative representation. This change extends this mechanism to the execute method implementation that some of those enums provide. When a tuple is specified as the "destination", e.g., here: > Enum! {ConfigCommand, [ > Get => ("get", config_get), > Set => ("set", config_set) > ]} the second component of this tuple will be interpreted as the function to invoke when this variant used in the newly generated execute method. --- nitrocli/src/arg_util.rs | 23 +++++++++- nitrocli/src/args.rs | 112 ++++++++++------------------------------------- 2 files changed, 44 insertions(+), 91 deletions(-) diff --git a/nitrocli/src/arg_util.rs b/nitrocli/src/arg_util.rs index 6dd14ed..b188085 100644 --- a/nitrocli/src/arg_util.rs +++ b/nitrocli/src/arg_util.rs @@ -22,9 +22,28 @@ // TODO: Right now we hard code the derives we create. We may want to // make this set configurable. macro_rules! Enum { + ( $name:ident, [ $( $var:ident => ($str:expr, $exec:expr) ), *] ) => { + Enum! {$name, [ + $( $var => $str ),* + ]} + + #[allow(unused_qualifications)] + impl $name { + fn execute( + self, + ctx: &mut crate::args::ExecCtx<'_>, + args: ::std::vec::Vec<::std::string::String>, + ) -> crate::Result<()> { + match self { + $( + $name::$var => $exec(ctx, args), + )* + } + } + } + }; ( $name:ident, [ $( $var:ident => $str:expr ), *] ) => { #[derive(Clone, Copy, Debug, PartialEq)] - #[allow(unused)] pub enum $name { $( $var, @@ -59,7 +78,7 @@ macro_rules! Enum { } } } - } + }; } #[cfg(test)] diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index 789001e..915186d 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -75,44 +75,20 @@ impl From for nitrokey::Model { /// A top-level command for nitrocli. Enum! {Command, [ - Config => "config", - Lock => "lock", - Otp => "otp", - Pin => "pin", - Pws => "pws", - Status => "status", - Storage => "storage" + Config => ("config", config), + Lock => ("lock", lock), + Otp => ("otp", otp), + Pin => ("pin", pin), + Pws => ("pws", pws), + Status => ("status", status), + Storage => ("storage", storage) ]} -impl Command { - /// Execute this command with the given arguments. - pub fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - match self { - Command::Config => config(ctx, args), - Command::Lock => lock(ctx, args), - Command::Otp => otp(ctx, args), - Command::Pin => pin(ctx, args), - Command::Pws => pws(ctx, args), - Command::Status => status(ctx, args), - Command::Storage => storage(ctx, args), - } - } -} - Enum! {ConfigCommand, [ - Get => "get", - Set => "set" + Get => ("get", config_get), + Set => ("set", config_set) ]} -impl ConfigCommand { - fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - match self { - ConfigCommand::Get => config_get(ctx, args), - ConfigCommand::Set => config_set(ctx, args), - } - } -} - #[derive(Clone, Copy, Debug)] pub enum ConfigOption { Enable(T), @@ -149,23 +125,12 @@ impl ConfigOption { } Enum! {OtpCommand, [ - Clear => "clear", - Get => "get", - Set => "set", - Status => "status" + Clear => ("clear", otp_clear), + Get => ("get", otp_get), + Set => ("set", otp_set), + Status => ("status", otp_status) ]} -impl OtpCommand { - fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - match self { - OtpCommand::Clear => otp_clear(ctx, args), - OtpCommand::Get => otp_get(ctx, args), - OtpCommand::Set => otp_set(ctx, args), - OtpCommand::Status => otp_status(ctx, args), - } - } -} - Enum! {OtpAlgorithm, [ Hotp => "hotp", Totp => "totp" @@ -192,39 +157,18 @@ Enum! {OtpSecretFormat, [ ]} Enum! {PinCommand, [ - Clear => "clear", - Set => "set", - Unblock => "unblock" + Clear => ("clear", pin_clear), + Set => ("set", pin_set), + Unblock => ("unblock", pin_unblock) ]} -impl PinCommand { - fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - match self { - PinCommand::Clear => pin_clear(ctx, args), - PinCommand::Set => pin_set(ctx, args), - PinCommand::Unblock => pin_unblock(ctx, args), - } - } -} - Enum! {PwsCommand, [ - Clear => "clear", - Get => "get", - Set => "set", - Status => "status" + Clear => ("clear", pws_clear), + Get => ("get", pws_get), + Set => ("set", pws_set), + Status => ("status", pws_status) ]} -impl PwsCommand { - fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - match self { - PwsCommand::Clear => pws_clear(ctx, args), - PwsCommand::Get => pws_get(ctx, args), - PwsCommand::Set => pws_set(ctx, args), - PwsCommand::Status => pws_status(ctx, args), - } - } -} - fn parse( ctx: &mut impl Stdio, parser: &argparse::ArgumentParser<'_>, @@ -248,21 +192,11 @@ fn status(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { } Enum! {StorageCommand, [ - Close => "close", - Open => "open", - Status => "status" + Close => ("close", storage_close), + Open => ("open", storage_open), + Status => ("status", storage_status) ]} -impl StorageCommand { - fn execute(self, ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { - match self { - StorageCommand::Close => storage_close(ctx, args), - StorageCommand::Open => storage_open(ctx, args), - StorageCommand::Status => storage_status(ctx, args), - } - } -} - /// Execute a storage subcommand. fn storage(ctx: &mut ExecCtx<'_>, args: Vec) -> Result<()> { let mut subcommand = StorageCommand::Open; -- cgit v1.2.3