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