mirror of
https://github.com/arampoire/nut-rs.git
synced 2025-12-01 00:30:23 -05:00
WIP
This commit is contained in:
parent
92779d7a33
commit
28f1fcab31
1 changed files with 102 additions and 19 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
///! NUT protocol implementation (v1.2).
|
///! NUT protocol implementation (v1.2).
|
||||||
///! Documentation: https://networkupstools.org/docs/developer-guide.chunked/ar01s09.html
|
///! Reference: https://networkupstools.org/docs/developer-guide.chunked/ar01s09.html
|
||||||
|
|
||||||
macro_rules! impl_words {
|
macro_rules! impl_words {
|
||||||
(
|
(
|
||||||
|
|
@ -8,7 +8,10 @@ macro_rules! impl_words {
|
||||||
$name:ident($word:tt),
|
$name:ident($word:tt),
|
||||||
)*
|
)*
|
||||||
) => {
|
) => {
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub(crate) enum Word {
|
pub(crate) enum Word {
|
||||||
|
/// A string argument.
|
||||||
|
Arg,
|
||||||
/// End-of-line.
|
/// End-of-line.
|
||||||
EOL,
|
EOL,
|
||||||
$(
|
$(
|
||||||
|
|
@ -37,10 +40,10 @@ macro_rules! impl_words {
|
||||||
/// Decodes a sequence of words.
|
/// Decodes a sequence of words.
|
||||||
/// Unrecognized words will be `None`
|
/// Unrecognized words will be `None`
|
||||||
/// Returns a `Vec` of the same length as the given slice.
|
/// Returns a `Vec` of the same length as the given slice.
|
||||||
pub(crate) fn decode_words(raw: &[&str]) -> Vec<Option<Self>> {
|
pub(crate) fn decode_words<T: AsRef<str>>(raw: &[T]) -> Vec<Option<Self>> {
|
||||||
let mut words = Vec::new();
|
let mut words = Vec::new();
|
||||||
for r in raw.iter() {
|
for r in raw.iter() {
|
||||||
words.push(Self::decode(Some(r)));
|
words.push(Self::decode(Some(r.as_ref())));
|
||||||
}
|
}
|
||||||
words.push(Some(Self::EOL));
|
words.push(Some(Self::EOL));
|
||||||
words
|
words
|
||||||
|
|
@ -50,10 +53,24 @@ macro_rules! impl_words {
|
||||||
/// This function cannot encode `Arg` or `EOL` (either returns `None`).
|
/// This function cannot encode `Arg` or `EOL` (either returns `None`).
|
||||||
pub(crate) fn encode(&self) -> Option<&str> {
|
pub(crate) fn encode(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::EOL => None,
|
Self::Arg | Self::EOL => None,
|
||||||
$(Self::$name => Some($word),)*
|
$(Self::$name => Some($word),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn matches(&self, other: Option<&Option<Self>>) -> bool {
|
||||||
|
if let Some(other) = other {
|
||||||
|
if self == &Word::Arg {
|
||||||
|
true
|
||||||
|
} else if let Some(other) = other {
|
||||||
|
self == other
|
||||||
|
} else {
|
||||||
|
self == &Word::EOL
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -121,20 +138,86 @@ impl_words! {
|
||||||
Version("VERSION"),
|
Version("VERSION"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl_serverbound! {
|
/// Messages decoded by the server.
|
||||||
// QueryVersion(Version, EOL),
|
pub mod server_bound {
|
||||||
// QueryNetworkVersion(NetworkVersion, EOL),
|
impl_sentences! {
|
||||||
// QueryHelp(Help, EOL),
|
QueryVersion (
|
||||||
// QueryListUps(List, Ups, EOL),
|
{
|
||||||
// QueryListVar(List, Var, Arg(ups_name), EOL),
|
0: Version,
|
||||||
// QueryListRw(List, Rw, Arg(ups_name), EOL),
|
1: EOL,
|
||||||
// }
|
},
|
||||||
|
{}
|
||||||
|
),
|
||||||
|
QueryListVar (
|
||||||
|
{
|
||||||
|
0: List,
|
||||||
|
1: Var,
|
||||||
|
2: Arg,
|
||||||
|
3: EOL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2: (ups_name: String),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) enum ServerboundSentence {
|
// TODO: Macro
|
||||||
QueryVersion,
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
QueryNetworkVersion,
|
pub enum Sentences {
|
||||||
QueryHelp,
|
QueryVersion {},
|
||||||
QueryListUps,
|
QueryNetworkVersion {},
|
||||||
QueryListVar { ups_name: String },
|
QueryHelp {},
|
||||||
QueryListRw { ups_name: String },
|
QueryListUps {},
|
||||||
|
QueryListVar { ups_name: String },
|
||||||
|
QueryListRw { ups_name: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Macro
|
||||||
|
impl Sentences {
|
||||||
|
pub(crate) fn decode(raw: Vec<String>) -> Option<Sentences> {
|
||||||
|
use super::{Word::*, *};
|
||||||
|
use Sentences::*;
|
||||||
|
let words = Word::decode_words(raw.as_slice());
|
||||||
|
|
||||||
|
if Version.matches(words.get(0)) && EOL.matches(words.get(1)) {
|
||||||
|
return Some(QueryVersion {});
|
||||||
|
}
|
||||||
|
if List.matches(words.get(0))
|
||||||
|
&& Var.matches(words.get(1))
|
||||||
|
&& Arg.matches(words.get(2))
|
||||||
|
&& EOL.matches(words.get(3))
|
||||||
|
{
|
||||||
|
return Some(QueryListVar {
|
||||||
|
ups_name: raw[2].to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Macro
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_serverbound_decode() {
|
||||||
|
assert_eq!(
|
||||||
|
server_bound::Sentences::decode(vec!["VERSION".into()]),
|
||||||
|
Some(server_bound::Sentences::QueryVersion {})
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
server_bound::Sentences::decode(vec!["LIST".into(), "VAR".into(), "nutdev".into()]),
|
||||||
|
Some(server_bound::Sentences::QueryListVar {
|
||||||
|
ups_name: "nutdev".into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
server_bound::Sentences::decode(vec!["LIST".into(), "RW".into(), "nutdev".into()]),
|
||||||
|
Some(server_bound::Sentences::QueryListRw {
|
||||||
|
ups_name: "nutdev".into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue