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))
|
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(
|
fn parse_response(
|
||||||
parts: ResponseAttributes<'_>,
|
parts: ResponseAttributes<'_>,
|
||||||
) -> Result<Self::Response, ResponseParserError<'_>>;
|
) -> Result<Self::Response, ResponseParserError<'_>>;
|
||||||
|
|
||||||
fn parse_raw_response(raw: &str) -> 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 = Vec::new();
|
||||||
let mut parts = HashMap::new();
|
|
||||||
let mut lines = raw.lines();
|
let mut lines = raw.lines();
|
||||||
loop {
|
loop {
|
||||||
let line = lines.next().ok_or(ResponseParserError::UnexpectedEOF)?;
|
let line = lines.next().ok_or(ResponseParserError::UnexpectedEOF)?;
|
||||||
@ -61,11 +58,13 @@ pub trait Command {
|
|||||||
let key = keyval
|
let key = keyval
|
||||||
.next()
|
.next()
|
||||||
.ok_or(ResponseParserError::SyntaxError(0, line))?;
|
.ok_or(ResponseParserError::SyntaxError(0, line))?;
|
||||||
|
|
||||||
|
// TODO: handle binary data
|
||||||
let value = keyval
|
let value = keyval
|
||||||
.next()
|
.next()
|
||||||
.ok_or(ResponseParserError::SyntaxError(0, line))?;
|
.ok_or(ResponseParserError::SyntaxError(0, line))?;
|
||||||
|
|
||||||
parts.insert(key, GenericResponseValue::Text(value));
|
parts.push((key, GenericResponseValue::Text(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::parse_response(parts.into())
|
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>>;
|
pub type GenericResponse<'a> = HashMap<&'a str, GenericResponseValue<'a>>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum GenericResponseValue<'a> {
|
pub enum GenericResponseValue<'a> {
|
||||||
Text(&'a str),
|
Text(&'a str),
|
||||||
Binary(&'a [u8]),
|
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 */
|
/* Parsing Helpers */
|
||||||
/*******************/
|
/*******************/
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::commands::{
|
use crate::commands::{
|
||||||
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||||
|
ResponseParserError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Channels;
|
pub struct Channels;
|
||||||
@ -22,17 +23,47 @@ impl Command for Channels {
|
|||||||
fn parse_response(
|
fn parse_response(
|
||||||
parts: ResponseAttributes<'_>,
|
parts: ResponseAttributes<'_>,
|
||||||
) -> Result<Self::Response, ResponseParserError> {
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
todo!()
|
let parts: Vec<_> = parts.into();
|
||||||
// let channels = parts
|
let mut channel_names = Vec::with_capacity(parts.len());
|
||||||
// .get("channels")
|
for (key, value) in parts {
|
||||||
// .ok_or(ResponseParserError::MissingField("channels"))?
|
debug_assert!(key == "channels");
|
||||||
// .as_list()
|
let channel_name = match value {
|
||||||
// .ok_or(ResponseParserError::UnexpectedType("channels", "list"))?
|
GenericResponseValue::Text(s) => s,
|
||||||
// .iter()
|
GenericResponseValue::Binary(_) => {
|
||||||
// .map(|v| v.as_text().map(ToOwned::to_owned))
|
return Err(ResponseParserError::UnexpectedPropertyType(
|
||||||
// .collect::<Option<Vec<_>>>()
|
"channels", "Binary",
|
||||||
// .ok_or(ResponseParserError::UnexpectedType("channels", "text"))?;
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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::{
|
use crate::commands::{
|
||||||
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
Command, GenericResponseValue, Request, RequestParserResult, ResponseAttributes,
|
||||||
|
ResponseParserError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ReadMessages;
|
pub struct ReadMessages;
|
||||||
@ -22,6 +23,66 @@ impl Command for ReadMessages {
|
|||||||
fn parse_response(
|
fn parse_response(
|
||||||
parts: ResponseAttributes<'_>,
|
parts: ResponseAttributes<'_>,
|
||||||
) -> Result<Self::Response, ResponseParserError> {
|
) -> 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