use std::{fmt, num::ParseIntError, str::FromStr}; use crate::status::{ParseStatusError, Status}; #[derive(Clone, Debug, PartialEq)] pub struct Response { pub status: Status, pub meta: String, } impl fmt::Display for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {}\r\n", u8::from(self.status.clone()), self.meta) } } #[derive(Clone, Debug, PartialEq)] pub enum ParseResponseError { TooLong, ParseInt(ParseIntError), StatusError, Malformed, } impl fmt::Display for ParseResponseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::TooLong => write!(f, "ParseResponseError: too long"), Self::ParseInt(e) => write!(f, "ParseResponseError: {e}"), Self::StatusError => write!(f, "ParseResponseError: Invalid Status"), Self::Malformed => write!(f, "ParseResponseError: Malformed"), } } } impl std::error::Error for ParseResponseError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::ParseInt(e) => Some(e), _ => None, } } } impl From for ParseResponseError { fn from(value: ParseIntError) -> Self { Self::ParseInt(value) } } impl From for ParseResponseError { fn from(_value: ParseStatusError) -> Self { Self::StatusError } } impl FromStr for Response { type Err = ParseResponseError; fn from_str(s: &str) -> Result { if s.len() > 2048 { return Err(ParseResponseError::TooLong); } if !s.ends_with("\r\n") { return Err(ParseResponseError::Malformed); } let Some((status, meta)) = s.split_once(' ') else { return Err(ParseResponseError::Malformed); }; let status: u8 = status.parse()?; let status: Status = status.try_into()?; Ok(Self { status, meta: meta.trim_end().to_string(), }) } } #[cfg(test)] mod tests { use super::*; #[test] fn parse_success() { let response: Response = "20 message delivered\r\n".parse().unwrap(); assert_eq!(response.status, Status::Success); assert_eq!(response.meta.as_str(), "message delivered"); } #[test] fn parse_badend() { let response = "20 message delivered\n".parse::(); assert_eq!(response, Err(ParseResponseError::Malformed)); } #[test] fn parse_badint() { let response = "twenty message deliverred\r\n".parse::(); match response { Err(ParseResponseError::ParseInt(_)) => {} _ => panic!(), } } }