use std::error::Error; use std::fmt; #[derive(PartialEq, Debug)] pub enum MessageError { EmptyResponse, HeaderMissingValueCount, HeaderValueCountIncorrectFormat(String), MalformedValueReceived(String), ValueNotFound(String, Vec), } impl fmt::Display for MessageError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let message = match *self { Self::EmptyResponse => "Got an empty response".to_string(), Self::HeaderMissingValueCount => "Value count not found in the header".to_string(), Self::HeaderValueCountIncorrectFormat(ref val) => { format!("String could not be parsed as value count: {}", val) } Self::MalformedValueReceived(ref val) => { format!("Could not parse value as float: {}", val) } Self::ValueNotFound(ref name, ref values) => format!( "Value not found in the received values: {} in [{}]", name, values.join(", ") ), }; f.write_str(&message) } } impl Error for MessageError {} pub fn create_request_message(value: String) -> String { format!("GETVAL {}", value) } pub fn parse_response_message(resp: String, name: String) -> Result { let mut lines = resp.split_terminator("\n"); let header = lines.next().ok_or(MessageError::EmptyResponse)?; let num_values_raw = header .split(" ") .next() .ok_or(MessageError::HeaderMissingValueCount)?; let num_values = num_values_raw .parse::() .map_err(|_| MessageError::HeaderValueCountIncorrectFormat(num_values_raw.to_string()))?; if num_values < 0 { Err(MessageError::ValueNotFound(name, vec![])) } else { let mut values: Vec = vec![]; for line in lines { let mut line_segment = line.split("="); if let Some(val_name) = line_segment.next() { if val_name == name && let Some(val_raw) = line_segment.next() { return val_raw.parse::().map_err(|_| { MessageError::MalformedValueReceived(num_values_raw.to_string()) }); } values.push(val_name.to_string()); } } Err(MessageError::ValueNotFound(name, values)) } } #[cfg(test)] mod tests { use super::*; macro_rules! assert_almost_equal { ($a:expr, $b:expr, $eps:expr) => { assert!(($a - $b).abs() < $eps); }; } #[test] fn test_create_request() { assert_eq!( create_request_message("some/value".to_string()), "GETVAL some/value", ); } #[test] fn test_parse_response_message_simple() { let resp = vec!["1 Value found", "value=4.5"].join("\n"); let result = parse_response_message(resp, "value".to_string()); assert_almost_equal!(result.unwrap(), 4.5, 0.1); } #[test] fn test_parse_response_message_exponential() { let resp = vec!["1 Value found", "value=4.514824e+02"].join("\n"); let result = parse_response_message(resp, "value".to_string()); assert_almost_equal!(result.unwrap(), 451.4824, 0.1); } #[test] fn test_parse_response_message_multiple_values() { let resp = vec!["3 Values found", "v1=4.514824e+09", "v2=1.234", "v3=0.1"].join("\n"); let result = parse_response_message(resp, "v2".to_string()); assert_almost_equal!(result.unwrap(), 1.234, 0.1); } #[test] fn test_parse_response_message_multiple_values_not_found() { let resp = vec!["3 Values found", "v1=4.514824e+09", "v2=1.234", "v3=0.1"].join("\n"); let result = parse_response_message(resp, "v10".to_string()); assert!(result.is_err()); assert_eq!( result, Err(MessageError::ValueNotFound( "v10".to_string(), vec!["v1".to_string(), "v2".to_string(), "v3".to_string()] )) ); } #[test] fn test_parse_response_message_no_values() { let resp = "0 Values found".to_string(); let result = parse_response_message(resp, "value".to_string()); assert!(result.is_err()); assert_eq!( result, Err(MessageError::ValueNotFound("value".to_string(), vec![])) ); } #[test] fn test_parse_response_message_field_not_found() { let resp = "-1 Type `loadx' is unknown.".to_string(); let result = parse_response_message(resp, "value".to_string()); assert!(result.is_err()); assert_eq!( result, Err(MessageError::ValueNotFound("value".to_string(), vec![])) ); } }