1use crate::status::{ParseStatusError, Status};
2use std::io::BufRead;
3use std::str::FromStr;
4use std::string::ToString;
5
6use std::error::Error;
7use std::fmt::Display;
8
9#[derive(Debug)]
10pub enum ParseReplyError {
11 Status(ParseStatusError),
12 FailedToRead,
13}
14
15impl Display for ParseReplyError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(f, "{:?}", self)
18 }
19}
20
21impl Error for ParseReplyError {
22 fn description(&self) -> &str {
23 match self {
24 Self::Status(_) => "An error when parsing status",
25 Self::FailedToRead => "Impossible to read",
26 }
27 }
28
29 fn cause(&self) -> Option<&dyn Error> {
30 if let Self::Status(inner) = self {
31 Some(inner)
32 } else {
33 None
34 }
35 }
36}
37
38#[derive(Clone, Debug)]
39pub struct Reply {
40 pub status: Status,
41 pub text: String,
42}
43
44impl Reply {
45 pub fn from_reader<T>(r: &mut T) -> Result<Self, ParseReplyError>
46 where
47 T: BufRead,
48 {
49 let mut iter = r.lines().filter_map(|l| l.ok());
51
52 let firstline = iter.next().ok_or(ParseReplyError::FailedToRead)?;
53
54 Self::from_line(firstline)
55 }
56
57 pub fn from_line(line: String) -> Result<Self, ParseReplyError> {
58 if line.len() < 3 {
59 return Err(ParseReplyError::FailedToRead);
60 }
61 let (statustxt, text) = line.split_at(3);
62
63 let status = Status::from_str(statustxt).map_err(|e| ParseReplyError::Status(e))?;
64
65 Ok(Reply {
66 status,
67 text: String::from(text.trim()),
68 })
69 }
70}
71
72impl ToString for Reply {
73 fn to_string(&self) -> String {
74 String::from(format!("{} {}", self.status, self.text))
75 }
76}