1use bytes::BytesMut;
3use tokio_util::codec::{Decoder, Encoder};
4
5use crate::error;
6use crate::line::LineCodec;
7use crate::message::Message;
8
9pub struct IrcCodec {
11 inner: LineCodec,
12}
13
14impl IrcCodec {
15 pub fn new(label: &str) -> error::Result<IrcCodec> {
17 LineCodec::new(label).map(|codec| IrcCodec { inner: codec })
18 }
19
20 pub fn sanitize(mut data: String) -> String {
24 if let Some((pos, len)) = ["\r\n", "\r", "\n"]
26 .iter()
27 .flat_map(|needle| data.find(needle).map(|pos| (pos, needle.len())))
28 .min_by_key(|&(pos, _)| pos)
29 {
30 data.truncate(pos + len);
31 }
32 data
33 }
34}
35
36impl Decoder for IrcCodec {
37 type Item = Message;
38 type Error = error::ProtocolError;
39
40 fn decode(&mut self, src: &mut BytesMut) -> error::Result<Option<Message>> {
41 self.inner
42 .decode(src)
43 .and_then(|res| res.map_or(Ok(None), |msg| msg.parse::<Message>().map(Some)))
44 }
45}
46
47impl Encoder<Message> for IrcCodec {
48 type Error = error::ProtocolError;
49
50 fn encode(&mut self, msg: Message, dst: &mut BytesMut) -> error::Result<()> {
51 self.inner.encode(IrcCodec::sanitize(msg.to_string()), dst)
52 }
53}