1
use serde::{Deserialize, Serialize};
2

            
3
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
4
pub struct FingerRequest {
5
    long: bool,
6
    name: String,
7
}
8

            
9
impl FingerRequest {
10
4
    pub fn new(long: bool, name: String) -> Self {
11
4
        Self { long, name }
12
4
    }
13

            
14
2
    pub fn to_bytes(&self) -> Vec<u8> {
15
2
        let mut result = Vec::new();
16
2
        if self.long {
17
1
            result.extend(b"/W ");
18
1
        }
19

            
20
2
        result.extend(self.name.as_bytes());
21
2
        result.extend(b"\r\n");
22

            
23
2
        result
24
2
    }
25

            
26
2
    pub fn from_bytes(bytes: &[u8]) -> Self {
27
2
        let (long, name) = if &bytes[..3] == b"/W " {
28
1
            (true, &bytes[3..])
29
        } else {
30
1
            (false, bytes)
31
        };
32

            
33
2
        let name = match name.strip_suffix(b"\r\n") {
34
2
            Some(new_name) => new_name,
35
            None => name,
36
        };
37

            
38
2
        Self::new(long, String::from_utf8_lossy(name).to_string())
39
2
    }
40
}
41

            
42
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43
pub struct FingerResponse(String);
44

            
45
impl FingerResponse {
46
2
    pub fn new(content: String) -> Self {
47
2
        Self(content)
48
2
    }
49

            
50
    pub fn get_inner(&self) -> &str {
51
        &self.0
52
    }
53

            
54
    pub fn into_inner(self) -> String {
55
        self.0
56
    }
57

            
58
2
    pub fn from_bytes(bytes: &[u8]) -> Self {
59
2
        if bytes.is_empty() {
60
            return Self(String::new());
61
2
        }
62

            
63
56
        fn normalize(c: u8) -> u8 {
64
56
            if c == (b'\r' | 0x80) || c == (b'\n' | 0x80) {
65
                c & 0x7f
66
            } else {
67
56
                c
68
            }
69
56
        }
70

            
71
2
        let normalized: Vec<u8> = bytes
72
2
            .iter()
73
2
            .copied()
74
2
            .map(normalize)
75
2
            .chain(std::iter::once(normalize(*bytes.last().unwrap())))
76
54
            .map_windows(|[a, b]| {
77
54
                if *a == b'\r' && *b == b'\n' {
78
3
                    None
79
                } else {
80
51
                    Some(*a)
81
                }
82
54
            })
83
2
            .flatten()
84
2
            .collect();
85

            
86
2
        let result = String::from_utf8_lossy(&normalized).to_string();
87

            
88
2
        Self(result)
89
2
    }
90

            
91
2
    pub fn to_bytes(&self) -> Vec<u8> {
92
2
        let mut out = Vec::with_capacity(self.0.len() + 2);
93

            
94
51
        for &b in self.0.as_bytes() {
95
51
            if b == b'\n' {
96
3
                out.extend_from_slice(b"\r\n");
97
48
            } else {
98
48
                out.push(b);
99
48
            }
100
        }
101

            
102
2
        if !self.0.ends_with('\n') {
103
            out.extend_from_slice(b"\r\n");
104
2
        }
105

            
106
2
        out
107
2
    }
108
}
109

            
110
#[cfg(test)]
111
mod tests {
112
    use super::*;
113

            
114
    #[test]
115
1
    fn test_finger_serialization_roundrip() {
116
1
        let request = FingerRequest::new(true, "alice".to_string());
117
1
        let bytes = request.to_bytes();
118
1
        let deserialized = FingerRequest::from_bytes(&bytes);
119
1
        assert_eq!(request, deserialized);
120

            
121
1
        let request2 = FingerRequest::new(false, "bob".to_string());
122
1
        let bytes2 = request2.to_bytes();
123
1
        let deserialized2 = FingerRequest::from_bytes(&bytes2);
124
1
        assert_eq!(request2, deserialized2);
125

            
126
1
        let response = FingerResponse::new("Hello, World!\nThis is a test.\n".to_string());
127
1
        let response_bytes = response.to_bytes();
128
1
        let deserialized_response = FingerResponse::from_bytes(&response_bytes);
129
1
        assert_eq!(response, deserialized_response);
130

            
131
1
        let response2 = FingerResponse::new("Single line response\n".to_string());
132
1
        let response_bytes2 = response2.to_bytes();
133
1
        let deserialized_response2 = FingerResponse::from_bytes(&response_bytes2);
134
1
        assert_eq!(response2, deserialized_response2);
135
1
    }
136
}