1use std::io;
2
3use bytes::{
4 BufMut,
5 BytesMut,
6};
7use either::Either;
8use thiserror::Error;
9use tokio_util::codec::{
10 Decoder,
11 Encoder,
12};
13
14use crate::{
15 event::Event,
16 op::Cmd,
17 parser::{
18 self,
19 Parser,
20 },
21 util::Escape,
22};
23
24#[derive(Debug, Error)]
26pub enum Error {
27 #[error("parse error: {0}")]
29 Parse(#[from] parser::Error),
30 #[error("io error: {0}")]
32 Io(#[from] io::Error),
33}
34
35impl Decoder for Parser {
36 type Error = Error;
37 type Item = Event;
38
39 fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
40 Ok(loop {
41 if buf.is_empty() {
42 break None;
43 }
44 match self.parse(buf)? {
45 Either::Left(true) => continue,
46 Either::Left(false) => break None,
47 Either::Right(item) => break item.into(),
48 }
49 })
50 }
51}
52
53impl Encoder<Event> for Parser {
54 type Error = io::Error;
55
56 fn encode(&mut self, item: Event, dst: &mut BytesMut) -> Result<(), Self::Error> {
57 match item {
58 Event::Data(bytes) => {
59 bytes.escape_to(dst);
60 }
61 Event::Cmd(cmd) => {
62 dst.put_u8(Cmd::IAC.into());
63 dst.put_u8(cmd.into());
64 }
65 Event::Negotiation(cmd, opt) => {
66 dst.put_u8(Cmd::IAC.into());
67 dst.put_u8(cmd.into());
68 dst.put_u8(opt.into());
69 }
70 Event::Subnegotiation(opt, params) => {
71 dst.put_u8(Cmd::IAC.into());
72 dst.put_u8(Cmd::SB.into());
73 dst.put_u8(opt.into());
74 params.escape_to(dst);
75 dst.put_u8(Cmd::IAC.into());
76 dst.put_u8(Cmd::SE.into());
77 }
78 }
79
80 Ok(())
81 }
82}