1use crate::{BitDecode, BitEncode, BitReader, BitWriter, ErrorKind};
34use bytes::{Buf, BytesMut};
35use core::marker::PhantomData;
36use std::io;
37use tokio_util::codec::{Decoder, Encoder};
38
39pub struct BinCodec<T>(PhantomData<T>);
42
43impl<T> BinCodec<T> {
44 #[must_use]
46 pub fn new() -> Self {
47 Self(PhantomData)
48 }
49}
50
51impl<T> Default for BinCodec<T> {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57impl<T: BitDecode + BitEncode> Decoder for BinCodec<T> {
62 type Item = T;
63 type Error = io::Error;
64
65 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<T>, io::Error> {
66 if src.is_empty() {
67 return Ok(None);
68 }
69 let mut reader = BitReader::with_layout(&src[..], <T as BitEncode>::LAYOUT);
70 match <T as BitDecode>::bit_decode(&mut reader) {
71 Ok(item) => {
72 let consumed = reader.bit_pos() / 8;
74 src.advance(consumed);
75 Ok(Some(item))
76 }
77 Err(e)
79 if matches!(
80 e.kind,
81 ErrorKind::UnexpectedEof { .. } | ErrorKind::Incomplete { .. }
82 ) =>
83 {
84 Ok(None)
85 }
86 Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e.to_string())),
88 }
89 }
90}
91
92impl<T: BitEncode> Encoder<T> for BinCodec<T> {
93 type Error = io::Error;
94
95 fn encode(&mut self, item: T, dst: &mut BytesMut) -> Result<(), io::Error> {
96 let mut w = BitWriter::with_layout(<T as BitEncode>::LAYOUT);
97 item.bit_encode(&mut w)
98 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?;
99 dst.extend_from_slice(&w.into_bytes());
100 Ok(())
101 }
102}
103
104#[cfg(test)]
105mod component {
106 use super::BinCodec;
109 use bnb::bin;
110 use bytes::BytesMut;
111 use tokio_util::codec::{Decoder, Encoder};
112
113 #[bin(big)]
115 #[derive(Debug, Clone, PartialEq, Eq)]
116 struct Msg {
117 a: u16,
118 b: u16,
119 }
120
121 #[bin(big, magic = 0xCAFEu16)]
123 #[derive(Debug, Clone, PartialEq, Eq)]
124 struct Magic {
125 v: u8,
126 }
127
128 #[bin(little)]
131 #[derive(Debug, Clone, PartialEq, Eq)]
132 struct LeMsg {
133 a: u16,
134 b: u32,
135 }
136
137 #[test]
138 fn little_endian_message_round_trips() {
139 let mut codec = BinCodec::<LeMsg>::new();
140 let mut buf = BytesMut::new();
141 let m = LeMsg {
142 a: 0x1234,
143 b: 0xAABB_CCDD,
144 };
145 codec.encode(m.clone(), &mut buf).unwrap();
146 assert_eq!(&buf[..], &[0x34, 0x12, 0xDD, 0xCC, 0xBB, 0xAA]);
148 assert_eq!(codec.decode(&mut buf).unwrap(), Some(m));
150 assert!(buf.is_empty());
151 }
152
153 #[test]
154 fn encoder_writes_exact_message_bytes() {
155 let mut codec = BinCodec::<Msg>::new();
156 let mut buf = BytesMut::new();
157 codec
158 .encode(
159 Msg {
160 a: 0x0102,
161 b: 0x0304,
162 },
163 &mut buf,
164 )
165 .unwrap();
166 assert_eq!(&buf[..], &[0x01, 0x02, 0x03, 0x04]);
167 }
168
169 #[test]
170 fn encode_then_decode_round_trips_and_drains() {
171 let mut codec = BinCodec::<Msg>::new();
172 let mut buf = BytesMut::new();
173 let m = Msg {
174 a: 0xAABB,
175 b: 0xCCDD,
176 };
177 codec.encode(m.clone(), &mut buf).unwrap();
178 assert_eq!(codec.decode(&mut buf).unwrap(), Some(m));
179 assert!(buf.is_empty(), "decode consumed exactly the one frame");
180 }
181
182 #[test]
183 fn decode_empty_buffer_is_none() {
184 let mut codec = BinCodec::<Msg>::new();
185 let mut buf = BytesMut::new();
186 assert_eq!(codec.decode(&mut buf).unwrap(), None);
187 }
188
189 #[test]
190 fn decode_partial_frame_is_none_and_keeps_bytes() {
191 let mut codec = BinCodec::<Msg>::new();
192 let mut buf = BytesMut::from(&[0x01, 0x02][..]); assert_eq!(codec.decode(&mut buf).unwrap(), None);
194 assert_eq!(
195 &buf[..],
196 &[0x01, 0x02],
197 "a partial frame is left for the next read"
198 );
199 }
200
201 #[test]
202 fn decode_consumes_one_message_and_leaves_the_tail() {
203 let mut codec = BinCodec::<Msg>::new();
204 let mut buf = BytesMut::from(&[0x01, 0x02, 0x03, 0x04, 0xEE, 0xFF][..]);
205 assert_eq!(
206 codec.decode(&mut buf).unwrap(),
207 Some(Msg {
208 a: 0x0102,
209 b: 0x0304
210 })
211 );
212 assert_eq!(
213 &buf[..],
214 &[0xEE, 0xFF],
215 "trailing bytes remain for the next frame"
216 );
217 }
218
219 #[test]
220 fn decode_walks_back_to_back_messages() {
221 let mut codec = BinCodec::<Msg>::new();
222 let mut buf = BytesMut::from(&[0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04][..]);
223 assert_eq!(codec.decode(&mut buf).unwrap(), Some(Msg { a: 1, b: 2 }));
224 assert_eq!(codec.decode(&mut buf).unwrap(), Some(Msg { a: 3, b: 4 }));
225 assert_eq!(codec.decode(&mut buf).unwrap(), None);
226 }
227
228 #[test]
229 fn decode_bad_magic_is_an_invalid_data_error() {
230 let mut codec = BinCodec::<Magic>::new();
231 let mut buf = BytesMut::from(&[0x00, 0x00, 0x07][..]); let err = codec.decode(&mut buf).unwrap_err();
233 assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
234 }
235
236 #[test]
237 fn default_constructs_a_codec() {
238 let _c: BinCodec<Msg> = BinCodec::default();
239 }
240}