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