commands: deduplicate logic in macros, add more macros
This commit is contained in:
186
src/commands.rs
186
src/commands.rs
@@ -200,10 +200,10 @@ impl<'a> From<Vec<(&'a str, GenericResponseValue<'a>)>> for ResponseAttributes<'
|
||||
/* Parsing Helpers */
|
||||
/*******************/
|
||||
|
||||
macro_rules! get_property {
|
||||
($parts:expr, $name:literal, $variant:ident) => {
|
||||
match $parts.get($name) {
|
||||
Some(crate::commands::GenericResponseValue::$variant(value)) => *value,
|
||||
macro_rules! _expect_property_type {
|
||||
($property:expr, $name:expr, $variant:ident) => {
|
||||
match $property {
|
||||
Some(crate::commands::GenericResponseValue::$variant(value)) => Some(value),
|
||||
Some(value) => {
|
||||
let actual_type = match value {
|
||||
crate::commands::GenericResponseValue::Text(_) => "Text",
|
||||
@@ -216,82 +216,150 @@ macro_rules! get_property {
|
||||
),
|
||||
);
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! _parse_optional_property_type {
|
||||
($name:expr, $property:expr) => {
|
||||
$property
|
||||
.map(|value| {
|
||||
value.parse().map_err(|_| {
|
||||
crate::commands::ResponseParserError::InvalidProperty($name, value)
|
||||
})
|
||||
})
|
||||
.transpose()?
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! _unwrap_optional_property_type {
|
||||
($name:expr, $property:expr) => {
|
||||
match $property {
|
||||
Some(value) => value,
|
||||
None => return Err(crate::commands::ResponseParserError::MissingProperty($name)),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! expect_optional_property_type {
|
||||
($property:expr, $name:expr, $variant:ident) => {
|
||||
crate::commands::_expect_property_type!($property, $name, $variant)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! expect_property_type {
|
||||
($property:expr, $name:expr, $variant:ident) => {{
|
||||
let prop = crate::commands::_expect_property_type!($property, $name, $variant);
|
||||
crate::commands::_unwrap_optional_property_type!($name, prop)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! get_optional_property {
|
||||
($parts:expr, $name:literal, $variant:ident) => {
|
||||
match $parts.get($name) {
|
||||
Some(crate::commands::GenericResponseValue::$variant(value)) => Some(*value),
|
||||
Some(value) => {
|
||||
let actual_type = match value {
|
||||
crate::commands::GenericResponseValue::Text(_) => "Text",
|
||||
crate::commands::GenericResponseValue::Binary(_) => "Binary",
|
||||
};
|
||||
return Err(
|
||||
crate::commands::ResponseParserError::UnexpectedPropertyType(
|
||||
$name,
|
||||
actual_type,
|
||||
),
|
||||
);
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
crate::commands::_expect_property_type!({ $parts.get($name).map(|v| *v) }, $name, $variant)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_and_parse_property {
|
||||
($parts:ident, $name:literal, $variant:ident) => {
|
||||
match $parts.get($name) {
|
||||
Some(crate::commands::GenericResponseValue::$variant(value)) => (*value)
|
||||
.parse()
|
||||
.map_err(|_| crate::commands::ResponseParserError::InvalidProperty($name, value))?,
|
||||
Some(value) => {
|
||||
let actual_type = match value {
|
||||
crate::commands::GenericResponseValue::Text(_) => "Text",
|
||||
crate::commands::GenericResponseValue::Binary(_) => "Binary",
|
||||
};
|
||||
return Err(
|
||||
crate::commands::ResponseParserError::UnexpectedPropertyType(
|
||||
$name,
|
||||
actual_type,
|
||||
),
|
||||
);
|
||||
}
|
||||
None => return Err(crate::commands::ResponseParserError::MissingProperty($name)),
|
||||
}
|
||||
};
|
||||
macro_rules! get_property {
|
||||
($parts:expr, $name:literal, $variant:ident) => {{
|
||||
let prop = crate::commands::_expect_property_type!(
|
||||
{ $parts.get($name).map(|v| *v) },
|
||||
$name,
|
||||
$variant
|
||||
);
|
||||
crate::commands::_unwrap_optional_property_type!($name, prop)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! get_and_parse_optional_property {
|
||||
($parts:ident, $name:literal, $variant:ident) => {
|
||||
match $parts.get($name) {
|
||||
Some(crate::commands::GenericResponseValue::$variant(value)) => {
|
||||
Some((*value).parse().map_err(|_| {
|
||||
crate::commands::ResponseParserError::InvalidProperty($name, value)
|
||||
})?)
|
||||
}
|
||||
Some(value) => {
|
||||
let actual_type = match value {
|
||||
crate::commands::GenericResponseValue::Text(_) => "Text",
|
||||
crate::commands::GenericResponseValue::Binary(_) => "Binary",
|
||||
};
|
||||
return Err(
|
||||
crate::commands::ResponseParserError::UnexpectedPropertyType(
|
||||
$name,
|
||||
actual_type,
|
||||
),
|
||||
);
|
||||
($parts:ident, $name:literal, $variant:ident) => {{
|
||||
let prop = crate::commands::_expect_property_type!(
|
||||
{ $parts.get($name).map(|v| *v) },
|
||||
$name,
|
||||
$variant
|
||||
);
|
||||
crate::commands::_parse_optional_property_type!($name, prop)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! get_and_parse_property {
|
||||
($parts:ident, $name:literal, $variant:ident) => {{
|
||||
let prop = crate::commands::_expect_property_type!(
|
||||
{ $parts.get($name).map(|v| *v) },
|
||||
$name,
|
||||
$variant
|
||||
);
|
||||
let prop = crate::commands::_parse_optional_property_type!($name, prop);
|
||||
crate::commands::_unwrap_optional_property_type!($name, prop)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! get_next_optional_property {
|
||||
($parts:ident, $variant:ident) => {
|
||||
match $parts.next() {
|
||||
Some((name, value)) => {
|
||||
crate::commands::_expect_property_type!({ Some(value) }, name, $variant)
|
||||
.map(|value| (name, value))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_next_property {
|
||||
($parts:ident, $variant:ident) => {
|
||||
match $parts.next() {
|
||||
Some((name, value)) => (
|
||||
name,
|
||||
crate::commands::_expect_property_type!({ Some(value) }, name, $variant).unwrap(),
|
||||
),
|
||||
None => return Err(crate::commands::ResponseParserError::UnexpectedEOF),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_next_and_parse_optional_property {
|
||||
($parts:ident, $variant:ident) => {
|
||||
match $parts.next() {
|
||||
Some((name, value)) => {
|
||||
let prop = crate::commands::_expect_property_type!({ Some(value) }, name, $variant);
|
||||
prop.map(|value| {
|
||||
(
|
||||
name,
|
||||
crate::commands::_parse_optional_property_type!(name, value),
|
||||
)
|
||||
})
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_next_and_parse_property {
|
||||
($parts:ident, $variant:ident) => {
|
||||
match $parts.next() {
|
||||
Some((name, value)) => {
|
||||
let prop = crate::commands::_expect_property_type!({ Some(value) }, name, $variant);
|
||||
let prop = crate::commands::_parse_optional_property_type!(name, prop);
|
||||
(
|
||||
name,
|
||||
crate::commands::_unwrap_optional_property_type!(name, prop),
|
||||
)
|
||||
}
|
||||
None => return Err(crate::commands::ResponseParserError::UnexpectedEOF),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use _expect_property_type;
|
||||
pub(crate) use _parse_optional_property_type;
|
||||
pub(crate) use _unwrap_optional_property_type;
|
||||
pub(crate) use expect_property_type;
|
||||
pub(crate) use get_and_parse_optional_property;
|
||||
pub(crate) use get_and_parse_property;
|
||||
pub(crate) use get_next_and_parse_property;
|
||||
pub(crate) use get_next_property;
|
||||
pub(crate) use get_optional_property;
|
||||
pub(crate) use get_property;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
expect_property_type, Command, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
@@ -29,14 +29,7 @@ impl Command for Channels {
|
||||
let mut channel_names = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts {
|
||||
debug_assert!(key == "channels");
|
||||
let channel_name = match value {
|
||||
GenericResponseValue::Text(s) => s,
|
||||
GenericResponseValue::Binary(_) => {
|
||||
return Err(ResponseParserError::UnexpectedPropertyType(
|
||||
"channels", "Binary",
|
||||
));
|
||||
}
|
||||
};
|
||||
let channel_name = expect_property_type!(Some(value), "channels", Text);
|
||||
channel_names.push(channel_name.to_string());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
expect_property_type, Command, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
@@ -33,26 +33,12 @@ impl Command for ReadMessages {
|
||||
for channel_message_pair in parts.chunks_exact(2) {
|
||||
let (ckey, cvalue) = channel_message_pair[0];
|
||||
let (mkey, mvalue) = channel_message_pair[1];
|
||||
|
||||
debug_assert!(ckey == "channel");
|
||||
debug_assert!(mkey == "message");
|
||||
|
||||
let channel = match cvalue {
|
||||
GenericResponseValue::Text(s) => s.to_string(),
|
||||
GenericResponseValue::Binary(_) => {
|
||||
return Err(ResponseParserError::UnexpectedPropertyType(
|
||||
"channel", "Binary",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let message = match mvalue {
|
||||
GenericResponseValue::Text(s) => s.to_string(),
|
||||
GenericResponseValue::Binary(_) => {
|
||||
return Err(ResponseParserError::UnexpectedPropertyType(
|
||||
"message", "Binary",
|
||||
))
|
||||
}
|
||||
};
|
||||
let channel = expect_property_type!(Some(cvalue), "channel", Text).to_string();
|
||||
let message = expect_property_type!(Some(mvalue), "message", Text).to_string();
|
||||
|
||||
messages.push((channel, message));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserError, RequestParserResult,
|
||||
expect_property_type, Command, Request, RequestParserError, RequestParserResult,
|
||||
ResponseAttributes, ResponseParserError,
|
||||
},
|
||||
filter::parse_filter,
|
||||
@@ -49,13 +49,8 @@ impl Command for List {
|
||||
|
||||
let list = parts
|
||||
.0
|
||||
.iter()
|
||||
.map(|(k, v)| match v {
|
||||
GenericResponseValue::Text(value) => Ok(value.to_string()),
|
||||
GenericResponseValue::Binary(_) => {
|
||||
Err(ResponseParserError::UnexpectedPropertyType(k, "Binary"))
|
||||
}
|
||||
})
|
||||
.into_iter()
|
||||
.map(|(k, v)| Ok(expect_property_type!(Some(v), k, Text).to_string()))
|
||||
.collect::<Result<Vec<_>, ResponseParserError>>()?;
|
||||
|
||||
Ok(list)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
expect_property_type, Command, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
@@ -24,17 +24,7 @@ impl Command for ListPartitions {
|
||||
let mut partitions = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts.into_iter() {
|
||||
debug_assert_eq!(key, "partition");
|
||||
|
||||
let partition = match value {
|
||||
GenericResponseValue::Text(name) => name.to_string(),
|
||||
GenericResponseValue::Binary(_) => {
|
||||
return Err(ResponseParserError::UnexpectedPropertyType(
|
||||
"partition",
|
||||
"Binary",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let partition = expect_property_type!(Some(value), "partition", Text).to_string();
|
||||
partitions.push(partition);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserError, RequestParserResult,
|
||||
get_next_and_parse_property, Command, Request, RequestParserError, RequestParserResult,
|
||||
ResponseAttributes, ResponseParserError,
|
||||
},
|
||||
common::{SongId, SongPosition},
|
||||
@@ -39,17 +39,9 @@ impl Command for AddId {
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError> {
|
||||
let parts: Vec<_> = parts.into();
|
||||
let (key, value) = parts.first().ok_or(ResponseParserError::UnexpectedEOF)?;
|
||||
debug_assert!(key == &"Id");
|
||||
let value = match value {
|
||||
GenericResponseValue::Text(value) => value,
|
||||
GenericResponseValue::Binary(_) => {
|
||||
return Err(ResponseParserError::UnexpectedPropertyType("Id", "Binary"))
|
||||
}
|
||||
};
|
||||
let id = value
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("Id", value.to_owned()))?;
|
||||
let mut iter = parts.into_iter();
|
||||
let (key, id) = get_next_and_parse_property!(iter, Text);
|
||||
debug_assert!(key == "Id");
|
||||
Ok(AddIdResponse { id })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserError, RequestParserResult,
|
||||
get_next_property, Command, Request, RequestParserError, RequestParserResult,
|
||||
ResponseAttributes, ResponseParserError,
|
||||
};
|
||||
|
||||
@@ -36,22 +36,10 @@ impl Command for StickerGet {
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError> {
|
||||
let parts: Vec<_> = parts.into();
|
||||
let mut parts = parts.into_iter();
|
||||
let sticker = parts.next().ok_or(ResponseParserError::UnexpectedEOF)?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
debug_assert!(sticker.0 == "sticker");
|
||||
|
||||
let sticker = match sticker.1 {
|
||||
GenericResponseValue::Text(s) => s.to_string(),
|
||||
GenericResponseValue::Binary(_) => {
|
||||
return Err(ResponseParserError::UnexpectedPropertyType(
|
||||
"sticker", "Binary",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(sticker)
|
||||
let mut parts = parts.into_iter().peekable();
|
||||
let (key, sticker) = get_next_property!(parts, Text);
|
||||
debug_assert!(parts.peek().is_none());
|
||||
debug_assert!(key == "sticker");
|
||||
Ok(sticker.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
expect_property_type, Command, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
@@ -24,13 +24,8 @@ impl Command for StickerNames {
|
||||
|
||||
let list = parts
|
||||
.0
|
||||
.iter()
|
||||
.map(|(_, v)| match v {
|
||||
GenericResponseValue::Text(value) => Ok(value.to_string()),
|
||||
GenericResponseValue::Binary(_) => Err(
|
||||
ResponseParserError::UnexpectedPropertyType("name", "Binary"),
|
||||
),
|
||||
})
|
||||
.into_iter()
|
||||
.map(|(k, v)| Ok(expect_property_type!(Some(v), k, Text).to_string()))
|
||||
.collect::<Result<Vec<_>, ResponseParserError>>()?;
|
||||
|
||||
Ok(list)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::commands::{
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
expect_property_type, Command, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
@@ -24,13 +24,8 @@ impl Command for StickerTypes {
|
||||
|
||||
let list = parts
|
||||
.0
|
||||
.iter()
|
||||
.map(|(_, v)| match v {
|
||||
GenericResponseValue::Text(value) => Ok(value.to_string()),
|
||||
GenericResponseValue::Binary(_) => Err(
|
||||
ResponseParserError::UnexpectedPropertyType("stickertype", "Binary"),
|
||||
),
|
||||
})
|
||||
.into_iter()
|
||||
.map(|(k, v)| Ok(expect_property_type!(Some(v), k, Text).to_string()))
|
||||
.collect::<Result<Vec<_>, ResponseParserError>>()?;
|
||||
|
||||
Ok(list)
|
||||
|
||||
Reference in New Issue
Block a user