diff --git a/src/command/bc125at/firmware_version.rs b/src/command/bc125at/firmware_version.rs index 2507378..a4f27d9 100644 --- a/src/command/bc125at/firmware_version.rs +++ b/src/command/bc125at/firmware_version.rs @@ -1,26 +1,5 @@ -use std::str::Utf8Error; +use crate::command::{command, macros::string_response}; -use tokio_util::bytes::Bytes; - -use crate::command::{Response, command}; - -#[derive(Debug, thiserror::Error)] -#[error("invalid UTF-8 bytes")] -pub struct FirmwareVersionError(#[from] pub Utf8Error); - -#[derive(Debug)] -pub struct FirmwareVersion(pub String); - -impl Response for FirmwareVersion { - type Error = FirmwareVersionError; - fn deserialize(raw_values: &[Bytes]) -> Result { - let version = str::from_utf8(&raw_values[0])?.to_string(); - Ok(Self(version)) - } - - fn expected_field_count() -> usize { - 1 - } -} +string_response!(FirmwareVersion => FirmwareVersionError); command!(b"VER": GetFirmwareVersion => FirmwareVersion); diff --git a/src/command/macros/mod.rs b/src/command/macros/mod.rs index d57a1e6..85403e1 100644 --- a/src/command/macros/mod.rs +++ b/src/command/macros/mod.rs @@ -1,7 +1,9 @@ mod command; mod range_param; mod range_response; +mod string_response; pub(crate) use command::command; pub(crate) use range_param::range_param; pub(crate) use range_response::range_response; +pub(crate) use string_response::string_response; diff --git a/src/command/macros/string_response.rs b/src/command/macros/string_response.rs new file mode 100644 index 0000000..ec4c5dd --- /dev/null +++ b/src/command/macros/string_response.rs @@ -0,0 +1,56 @@ +macro_rules! string_response { + ($name:ident => $error:ident) => { + #[derive(::core::fmt::Debug, ::thiserror::Error)] + #[error("invalid UTF-8 bytes")] + pub struct $error(#[from] pub ::core::str::Utf8Error); + + #[derive( + ::core::clone::Clone, ::core::fmt::Debug, ::core::cmp::PartialEq, ::core::cmp::Eq, + )] + pub struct $name(pub ::std::string::String); + + impl crate::command::Response for $name { + type Error = $error; + + fn deserialize( + raw_values: &[::tokio_util::bytes::Bytes], + ) -> ::core::result::Result { + let val = ::core::str::from_utf8(&raw_values[0])?.to_string(); + Ok(Self(val)) + } + + fn expected_field_count() -> usize { + 1 + } + } + }; +} + +pub(crate) use string_response; + +#[cfg(test)] +mod tests { + use claims::assert_matches; + + use crate::command::{Response, test::deserialize}; + + string_response!(StringResponse => StringResponseError); + + #[test] + fn expected_field_count() { + assert_eq!(StringResponse::expected_field_count(), 1); + } + + #[test] + fn deserializes_valid_response() { + let response = deserialize::(b"hello, world!").unwrap(); + assert_eq!(response, StringResponse("hello, world!".to_string())); + } + + #[test] + fn invalid_utf8() { + let err = deserialize::(&[0, 159]).unwrap_err(); + assert_matches!(err, StringResponseError(_)); + } +} +