commands: handle some more response parsing
This commit is contained in:
parent
184f9fc215
commit
4fada75fe9
@ -36,15 +36,12 @@ pub trait Command {
|
||||
Self::parse_request(parts).map(|(req, _)| (req, rest))
|
||||
}
|
||||
|
||||
// TODO: Replace the HashMap datastructure with something that allows keeping
|
||||
// duplicate keys and order of insertion
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>>;
|
||||
|
||||
fn parse_raw_response(raw: &str) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
// TODO: Fix the implementation to use ResponseAttributes natively
|
||||
let mut parts = HashMap::new();
|
||||
let mut parts = Vec::new();
|
||||
let mut lines = raw.lines();
|
||||
loop {
|
||||
let line = lines.next().ok_or(ResponseParserError::UnexpectedEOF)?;
|
||||
@ -61,11 +58,13 @@ pub trait Command {
|
||||
let key = keyval
|
||||
.next()
|
||||
.ok_or(ResponseParserError::SyntaxError(0, line))?;
|
||||
|
||||
// TODO: handle binary data
|
||||
let value = keyval
|
||||
.next()
|
||||
.ok_or(ResponseParserError::SyntaxError(0, line))?;
|
||||
|
||||
parts.insert(key, GenericResponseValue::Text(value));
|
||||
parts.push((key, GenericResponseValue::Text(value)));
|
||||
}
|
||||
|
||||
Self::parse_response(parts.into())
|
||||
@ -98,7 +97,7 @@ pub type GenericResponseResult<'a> = Result<GenericResponse<'a>, &'a str>;
|
||||
|
||||
pub type GenericResponse<'a> = HashMap<&'a str, GenericResponseValue<'a>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum GenericResponseValue<'a> {
|
||||
Text(&'a str),
|
||||
Binary(&'a [u8]),
|
||||
@ -132,6 +131,18 @@ impl<'a> From<ResponseAttributes<'a>> for HashMap<&'a str, GenericResponseValue<
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ResponseAttributes<'a>> for Vec<(&'a str, GenericResponseValue<'a>)> {
|
||||
fn from(val: ResponseAttributes<'a>) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Vec<(&'a str, GenericResponseValue<'a>)>> for ResponseAttributes<'a> {
|
||||
fn from(val: Vec<(&'a str, GenericResponseValue<'a>)>) -> Self {
|
||||
Self(val)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/* Parsing Helpers */
|
||||
/*******************/
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::commands::{
|
||||
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
pub struct Channels;
|
||||
@ -22,17 +23,47 @@ impl Command for Channels {
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError> {
|
||||
todo!()
|
||||
// let channels = parts
|
||||
// .get("channels")
|
||||
// .ok_or(ResponseParserError::MissingField("channels"))?
|
||||
// .as_list()
|
||||
// .ok_or(ResponseParserError::UnexpectedType("channels", "list"))?
|
||||
// .iter()
|
||||
// .map(|v| v.as_text().map(ToOwned::to_owned))
|
||||
// .collect::<Option<Vec<_>>>()
|
||||
// .ok_or(ResponseParserError::UnexpectedType("channels", "text"))?;
|
||||
let parts: Vec<_> = parts.into();
|
||||
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",
|
||||
));
|
||||
}
|
||||
};
|
||||
channel_names.push(channel_name.to_string());
|
||||
}
|
||||
|
||||
// Ok(ChannelsResponse { channels })
|
||||
Ok(ChannelsResponse {
|
||||
channels: channel_names,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
fn test_parse_response() {
|
||||
let response = indoc! {"
|
||||
channels: foo
|
||||
channels: bar
|
||||
channels: baz
|
||||
OK
|
||||
"};
|
||||
let response = Channels::parse_raw_response(response).unwrap();
|
||||
assert_eq!(
|
||||
response,
|
||||
ChannelsResponse {
|
||||
channels: vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::commands::{
|
||||
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||
ResponseParserError,
|
||||
};
|
||||
|
||||
pub struct ReadMessages;
|
||||
@ -22,6 +23,66 @@ impl Command for ReadMessages {
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError> {
|
||||
todo!()
|
||||
let parts: Vec<_> = parts.into();
|
||||
debug_assert!(parts.len() % 2 == 0);
|
||||
|
||||
let mut messages = Vec::with_capacity(parts.len() / 2);
|
||||
|
||||
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",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
messages.push((channel, message));
|
||||
}
|
||||
|
||||
Ok(ReadMessagesResponse { messages })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use indoc::indoc;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_response() {
|
||||
let input = indoc! {"
|
||||
channel: channel1
|
||||
message: message1
|
||||
channel: channel2
|
||||
message: message2
|
||||
OK
|
||||
"};
|
||||
let result = ReadMessages::parse_raw_response(input);
|
||||
assert_eq!(
|
||||
result,
|
||||
Ok(ReadMessagesResponse {
|
||||
messages: vec![
|
||||
("channel1".to_string(), "message1".to_string()),
|
||||
("channel2".to_string(), "message2".to_string()),
|
||||
]
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user