From a7f730c04abf806f74bc63c5ff96290c7c5633f4 Mon Sep 17 00:00:00 2001 From: Aram Peres Date: Wed, 4 Aug 2021 02:05:57 -0400 Subject: [PATCH] Implement varargs --- rups/src/proto/client.rs | 27 ++++++++++++++++++--------- rups/src/proto/mod.rs | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/rups/src/proto/client.rs b/rups/src/proto/client.rs index e1be897..87161d6 100644 --- a/rups/src/proto/client.rs +++ b/rups/src/proto/client.rs @@ -36,16 +36,18 @@ impl_sentences! { {} ), /// Server returns an error. - /// TODO: Support "extra" vararg. RespondErr ( { 0: Err, 1: Arg, - 2: EOL, }, { /// The error code. 1: message, + }, + { + /// Extra information about the error. + 2...: extras } ), /// Server responds with the number of prior logins to the given `ups_name` device. @@ -97,22 +99,21 @@ impl_sentences! { } ), /// Server responds with the type of the given `var_name` variable for the UPS device. - /// TODO: Support multiple type words (3...). RespondType ( { 0: Type, 1: Arg, 2: Arg, - 3: Arg, - 4: EOL, }, { /// The name of the UPS device. 1: ups_name, /// The name of the variable. 2: var_name, - /// The type of the variable. - 3: var_type, + }, + { + /// The variable definition (RW, ENUN, STRING...) + 3...: var_types } ), /// Server responds with the description of the given `var_name` variable for the UPS device. @@ -483,6 +484,14 @@ mod tests { ["ERR", "ACCESS-DENIED"] <=> Sentences::RespondErr { message: "ACCESS-DENIED".into(), + extras: vec![], + } + ); + test_encode_decode!( + ["ERR", "ACCESS-DENIED", "extra1", "extra2"] <=> + Sentences::RespondErr { + message: "ACCESS-DENIED".into(), + extras: vec!["extra1".into(), "extra2".into()], } ); test_encode_decode!( @@ -508,11 +517,11 @@ mod tests { } ); test_encode_decode!( - ["TYPE", "nutdev", "input.transfer.low", "ENUM"] <=> + ["TYPE", "nutdev", "input.transfer.low", "ENUM", "RW"] <=> Sentences::RespondType { ups_name: "nutdev".into(), var_name: "input.transfer.low".into(), - var_type: "ENUM".into(), + var_types: vec!["ENUM".into(), "RW".into()], } ); test_encode_decode!( diff --git a/rups/src/proto/mod.rs b/rups/src/proto/mod.rs index 72a6fb6..2de84a4 100644 --- a/rups/src/proto/mod.rs +++ b/rups/src/proto/mod.rs @@ -82,6 +82,16 @@ macro_rules! impl_words { false } } + + /// Whether the `Word` matches all words in the vec, starting at the given index. + pub(crate) fn matches_until_end(&self, start: usize, others: &[Option]) -> bool { + for i in start..others.len() { + if !self.matches(others.get(i)) { + return false; + } + } + true + } } }; } @@ -102,6 +112,12 @@ macro_rules! impl_sentences { $argidx:tt: $arg:ident, )* } + $( + ,{ + $(#[$varargattr:meta])+ + $varargidx:tt...: $vararg:ident + } + )? ), )* ) => { @@ -115,6 +131,10 @@ macro_rules! impl_sentences { $(#[$argattr])* $arg: String, )* + $( + $(#[$varargattr])* + $vararg: Vec, + )* }, )* } @@ -127,13 +147,16 @@ macro_rules! impl_sentences { let words = Word::decode_words(raw.as_slice()); $( - if true $(&& $word.matches(words.get($wordidx)))* { + if true + $(&& $word.matches(words.get($wordidx)))* + $(&& Arg.matches_until_end($varargidx, &words))* + { return Some($name { $($arg: raw[$argidx].to_owned(),)* + $($vararg: raw[$varargidx..].to_owned(),)* }) } )* - None } @@ -144,6 +167,7 @@ macro_rules! impl_sentences { $( Self::$name { $($arg,)* + $($vararg,)* } => { #[allow(unused_mut)] let mut words = vec![ @@ -156,6 +180,12 @@ macro_rules! impl_sentences { words[$argidx] = Some($arg); )* + $( + for vararg in $vararg { + words.push(Some(vararg)); + } + )* + words .into_iter() .flatten()