async_byteorder/
lib.rs

1//! Async encoders and decoders for the primitive number types, both big-endian and little-endian.
2#![deny(missing_docs)]
3
4extern crate async_codec;
5extern crate async_codec_util;
6extern crate atm_io_utils;
7extern crate futures_core;
8extern crate futures_io;
9
10
11#[cfg(test)]
12#[macro_use(quickcheck)]
13extern crate quickcheck;
14#[cfg(test)]
15extern crate async_ringbuffer;
16
17macro_rules! gen_byte_module {
18    ($num:ty, $name:tt) => (
19        use async_codec::{AsyncDecode, AsyncEncode, AsyncEncodeLen, PollEnc, PollDec};
20        use futures_core::Never;
21        use futures_core::Async::{Ready, Pending};
22        use futures_core::task::Context;
23        use futures_io::{AsyncRead, AsyncWrite, Error as FutIoErr, ErrorKind};
24
25        #[doc = "Create a decoder for a `"]
26        #[doc = $name]
27        #[doc = "`."]
28        pub fn decode_byte() -> DecodeByte {
29            DecodeByte
30        }
31
32        #[doc = "Decode a `"]
33        #[doc = $name]
34        #[doc = "`."]
35        pub struct DecodeByte;
36
37        impl AsyncDecode for DecodeByte {
38            type Item = $num;
39            type Error = Never;
40
41            fn poll_decode<R: AsyncRead>(
42                self,
43                cx: &mut Context,
44                reader: &mut R
45            ) -> PollDec<Self::Item, Self,Self::Error> {
46                let mut byte = [0];
47
48                match reader.poll_read(cx, &mut byte) {
49                    Ok(Ready(0)) => PollDec::Errored(FutIoErr::new(ErrorKind::UnexpectedEof, $name).into()),
50                    Ok(Ready(_)) => PollDec::Done(byte[0] as $num, 1),
51                    Ok(Pending) => PollDec::Pending(self),
52                    Err(err) => PollDec::Errored(err.into())
53                }
54            }
55        }
56
57        #[doc = "Create an encoder for a `"]
58        #[doc = $name]
59        #[doc = "`."]
60        pub fn encode_byte(num: $num) -> EncodeByte {
61            EncodeByte {num: [num as u8]}
62        }
63
64        #[doc = "Encode a `"]
65        #[doc = $name]
66        #[doc = "`."]
67        pub struct EncodeByte {
68            num: [u8; 1]
69        }
70
71        impl AsyncEncode for EncodeByte {
72            fn poll_encode<W: AsyncWrite>(
73                self,
74                cx: &mut Context,
75                writer: &mut W
76            ) -> PollEnc<Self> {
77                match writer.poll_write(cx, &self.num[..]) {
78                    Ok(Ready(0)) => PollEnc::Errored(FutIoErr::new(ErrorKind::WriteZero, $name).into()),
79                    Ok(Ready(_)) => PollEnc::Done(1),
80                    Ok(Pending) => PollEnc::Pending(self),
81                    Err(err) => PollEnc::Errored(err)
82                }
83            }
84        }
85
86        impl AsyncEncodeLen for EncodeByte {
87            fn remaining_bytes(&self) -> usize {
88                1
89            }
90        }
91    )
92}
93
94macro_rules! gen_module {
95    ($num:ty, $name:tt,  $bytes:expr, $from_be:path, $from_le:path) => (
96        use std::mem::transmute;
97
98        use async_codec::{AsyncDecode, AsyncEncode, AsyncEncodeLen, PollEnc, PollDec};
99        use futures_core::Never;
100        use futures_core::Async::{Ready, Pending};
101        use futures_core::task::Context;
102        use futures_io::{AsyncRead, AsyncWrite, Error as FutIoErr, ErrorKind};
103
104        #[doc = "Create a decoder for a `"]
105        #[doc = $name]
106        #[doc = "` in native byte order."]
107        pub fn decode_native() -> DecodeNative {
108            DecodeNative {
109                bytes: [0; $bytes],
110                offset: 0,
111            }
112        }
113
114        #[doc = "Decode a `"]
115        #[doc = $name]
116        #[doc = "` in native byte order."]
117        pub struct DecodeNative {
118            bytes: [u8; $bytes],
119            offset: u8,
120        }
121
122        impl AsyncDecode for DecodeNative {
123            type Item = $num;
124            type Error = Never;
125
126            fn poll_decode<R: AsyncRead>(
127                mut self,
128                cx: &mut Context,
129                reader: &mut R
130            ) -> PollDec<Self::Item, Self, Self::Error> {
131                match reader.poll_read(cx, &mut self.bytes[self.offset as usize..]) {
132                    Ok(Ready(0)) => PollDec::Errored(FutIoErr::new(ErrorKind::UnexpectedEof, $name).into()),
133                    Ok(Ready(read)) => {
134                        self.offset += read as u8;
135
136                        if self.offset < $bytes {
137                            PollDec::Progress(self, read)
138                        } else {
139                            PollDec::Done(unsafe { transmute::<[u8; $bytes], $num>(self.bytes) }, read)
140                        }
141                    }
142                    Ok(Pending) => PollDec::Pending(self),
143                    Err(err) => PollDec::Errored(err.into())
144                }
145            }
146        }
147
148        #[doc = "Create a decoder for a `"]
149        #[doc = $name]
150        #[doc = "` in big-endian byte order."]
151        pub fn decode_be() -> DecodeBE {
152            DecodeBE(decode_native())
153        }
154
155        #[doc = "Decode a `"]
156        #[doc = $name]
157        #[doc = "` in big-endian byte order."]
158        pub struct DecodeBE(DecodeNative);
159
160        impl AsyncDecode for DecodeBE {
161            type Item = $num;
162            type Error = Never;
163
164            fn poll_decode<R: AsyncRead>(
165                self,
166                cx: &mut Context,
167                reader: &mut R
168            ) -> PollDec<Self::Item, Self, Self::Error> {
169                match self.0.poll_decode(cx, reader) {
170                    PollDec::Done(item, read) => PollDec::Done($from_be(item), read),
171                    PollDec::Progress(inner, read) => {
172                        PollDec::Progress(DecodeBE(inner), read)
173                    }
174                    PollDec::Pending(inner) => {
175                        PollDec::Pending(DecodeBE(inner))
176                    }
177                    PollDec::Errored(err) => PollDec::Errored(err),
178                }
179            }
180        }
181
182        #[doc = "Create a decoder for a `"]
183        #[doc = $name]
184        #[doc = "` in little-endian byte order."]
185        pub fn decode_le() -> DecodeLE {
186            DecodeLE(decode_native())
187        }
188
189        #[doc = "Decode a `"]
190        #[doc = $name]
191        #[doc = "` in little-endian byte order."]
192        pub struct DecodeLE(DecodeNative);
193
194        impl AsyncDecode for DecodeLE {
195            type Item = $num;
196            type Error = Never;
197
198            fn poll_decode<R: AsyncRead>(
199                self,
200                cx: &mut Context,
201                reader: &mut R
202            ) -> PollDec<Self::Item, Self, Self::Error> {
203                match self.0.poll_decode(cx, reader) {
204                    PollDec::Done(item, read) => PollDec::Done($from_le(item), read),
205                    PollDec::Progress(inner, read) => {
206                        PollDec::Progress(DecodeLE(inner), read)
207                    }
208                    PollDec::Pending(inner) => {
209                        PollDec::Pending(DecodeLE(inner))
210                    }
211                    PollDec::Errored(err) => PollDec::Errored(err),
212                }
213            }
214        }
215
216        #[doc = "Create an encoder for a `"]
217        #[doc = $name]
218        #[doc = "` in native byte order."]
219        pub fn encode_native(num: $num) -> EncodeNative {
220            EncodeNative {
221                bytes: unsafe { transmute::<$num, [u8; $bytes]>(num) },
222                offset: 0,
223            }
224        }
225
226        #[doc = "Encode a `"]
227        #[doc = $name]
228        #[doc = "` in native byte order."]
229        pub struct EncodeNative {
230            bytes: [u8; $bytes],
231            offset: u8,
232        }
233
234        impl AsyncEncode for EncodeNative {
235            fn poll_encode<W: AsyncWrite>(
236                mut self,
237                cx: &mut Context,
238                writer: &mut W
239            ) -> PollEnc<Self> {
240                match writer.poll_write(cx, &mut self.bytes[self.offset as usize..]) {
241                    Ok(Ready(0)) => PollEnc::Errored(FutIoErr::new(ErrorKind::WriteZero, $name).into()),
242                    Ok(Ready(written)) => {
243                        self.offset += written as u8;
244                        if self.offset < $bytes {
245                            PollEnc::Progress(self, written)
246                        } else {
247                            PollEnc::Done(written)
248                        }
249                    },
250                    Ok(Pending) => PollEnc::Pending(self),
251                    Err(err) => PollEnc::Errored(err)
252                }
253            }
254        }
255
256        impl AsyncEncodeLen for EncodeNative {
257            fn remaining_bytes(&self) -> usize {
258                ($bytes - self.offset) as usize
259            }
260        }
261
262        #[doc = "Create an encoder for a `"]
263        #[doc = $name]
264        #[doc = "` in big-endian byte order."]
265        pub fn encode_be(num: $num) -> EncodeBE {
266            EncodeBE(encode_native(num.to_be()))
267        }
268
269        #[doc = "Encode a `"]
270        #[doc = $name]
271        #[doc = "` in big-endian byte order."]
272        pub struct EncodeBE(EncodeNative);
273
274        impl AsyncEncode for EncodeBE {
275            fn poll_encode<W: AsyncWrite>(
276                self,
277                cx: &mut Context,
278                writer: &mut W
279            ) -> PollEnc<Self> {
280                match self.0.poll_encode(cx, writer) {
281                    PollEnc::Done(written) => PollEnc::Done(written),
282                    PollEnc::Progress(inner, written) => {
283                        PollEnc::Progress(EncodeBE(inner), written)
284                    }
285                    PollEnc::Pending(inner) => {
286                        PollEnc::Pending(EncodeBE(inner))
287                    }
288                    PollEnc::Errored(err) => PollEnc::Errored(err),
289                }
290            }
291        }
292
293        impl AsyncEncodeLen for EncodeBE {
294            fn remaining_bytes(&self) -> usize {
295                self.0.remaining_bytes()
296            }
297        }
298
299        #[doc = "Create an encoder for a `"]
300        #[doc = $name]
301        #[doc = "` in little-endian byte order."]
302        pub fn encode_le(num: $num) -> EncodeLE {
303            EncodeLE(encode_native(num.to_le()))
304        }
305
306        #[doc = "Encode a `"]
307        #[doc = $name]
308        #[doc = "` in little-endian byte order."]
309        pub struct EncodeLE(EncodeNative);
310
311        impl AsyncEncode for EncodeLE {
312            fn poll_encode<W: AsyncWrite>(
313                self,
314                cx: &mut Context,
315                writer: &mut W
316            ) -> PollEnc<Self> {
317                match self.0.poll_encode(cx, writer) {
318                    PollEnc::Done(written) => PollEnc::Done(written),
319                    PollEnc::Progress(inner, written) => {
320                        PollEnc::Progress(EncodeLE(inner), written)
321                    }
322                    PollEnc::Pending(inner) => {
323                        PollEnc::Pending(EncodeLE(inner))
324                    }
325                    PollEnc::Errored(err) => PollEnc::Errored(err),
326                }
327            }
328        }
329
330        impl AsyncEncodeLen for EncodeLE {
331            fn remaining_bytes(&self) -> usize {
332                self.0.remaining_bytes()
333            }
334        }
335    )
336}
337
338mod mod_u8 {
339    gen_byte_module!{u8, "u8"}
340}
341pub use self::mod_u8::decode_byte as decode_u8;
342pub use self::mod_u8::DecodeByte as DecodeU8;
343pub use self::mod_u8::encode_byte as encode_u8;
344pub use self::mod_u8::EncodeByte as EncodeU8;
345
346mod mod_i8 {
347    gen_byte_module!{i8, "i8"}
348}
349pub use self::mod_i8::decode_byte as decode_i8;
350pub use self::mod_i8::DecodeByte as DecodeI8;
351pub use self::mod_i8::encode_byte as encode_i8;
352pub use self::mod_i8::EncodeByte as EncodeI8;
353
354mod mod_u16 {
355    gen_module!{u16, "u16", 2, u16::from_be, u16::from_le}
356}
357pub use self::mod_u16::decode_native as decode_u16_native;
358pub use self::mod_u16::DecodeNative as DecodeU16Native;
359pub use self::mod_u16::decode_be as decode_u16_be;
360pub use self::mod_u16::DecodeBE as DecodeU16BE;
361pub use self::mod_u16::decode_le as decode_u16_le;
362pub use self::mod_u16::DecodeLE as DecodeU16LE;
363pub use self::mod_u16::encode_native as encode_u16_native;
364pub use self::mod_u16::EncodeNative as EncodeU16Native;
365pub use self::mod_u16::encode_be as encode_u16_be;
366pub use self::mod_u16::EncodeBE as EncodeU16BE;
367pub use self::mod_u16::encode_le as encode_u16_le;
368pub use self::mod_u16::EncodeLE as EncodeU16LE;
369
370mod mod_u32 {
371    gen_module!{u32, "u32", 4, u32::from_be, u32::from_le}
372}
373pub use self::mod_u32::decode_native as decode_u32_native;
374pub use self::mod_u32::DecodeNative as DecodeU32Native;
375pub use self::mod_u32::decode_be as decode_u32_be;
376pub use self::mod_u32::DecodeBE as DecodeU32BE;
377pub use self::mod_u32::decode_le as decode_u32_le;
378pub use self::mod_u32::DecodeLE as DecodeU32LE;
379pub use self::mod_u32::encode_native as encode_u32_native;
380pub use self::mod_u32::EncodeNative as EncodeU32Native;
381pub use self::mod_u32::encode_be as encode_u32_be;
382pub use self::mod_u32::EncodeBE as EncodeU32BE;
383pub use self::mod_u32::encode_le as encode_u32_le;
384pub use self::mod_u32::EncodeLE as EncodeU32LE;
385
386mod mod_u64 {
387    gen_module!{u64, "u64", 8, u64::from_be, u64::from_le}
388}
389pub use self::mod_u64::decode_native as decode_u64_native;
390pub use self::mod_u64::DecodeNative as DecodeU64Native;
391pub use self::mod_u64::decode_be as decode_u64_be;
392pub use self::mod_u64::DecodeBE as DecodeU64BE;
393pub use self::mod_u64::decode_le as decode_u64_le;
394pub use self::mod_u64::DecodeLE as DecodeU64LE;
395pub use self::mod_u64::encode_native as encode_u64_native;
396pub use self::mod_u64::EncodeNative as EncodeU64Native;
397pub use self::mod_u64::encode_be as encode_u64_be;
398pub use self::mod_u64::EncodeBE as EncodeU64BE;
399pub use self::mod_u64::encode_le as encode_u64_le;
400pub use self::mod_u64::EncodeLE as EncodeU64LE;
401
402mod mod_i16 {
403    gen_module!{i16, "i16", 2, i16::from_be, i16::from_le}
404}
405pub use self::mod_i16::decode_native as decode_i16_native;
406pub use self::mod_i16::DecodeNative as DecodeI16Native;
407pub use self::mod_i16::decode_be as decode_i16_be;
408pub use self::mod_i16::DecodeBE as DecodeI16BE;
409pub use self::mod_i16::decode_le as decode_i16_le;
410pub use self::mod_i16::DecodeLE as DecodeI16LE;
411pub use self::mod_i16::encode_native as encode_i16_native;
412pub use self::mod_i16::EncodeNative as EncodeI16Native;
413pub use self::mod_i16::encode_be as encode_i16_be;
414pub use self::mod_i16::EncodeBE as EncodeI16BE;
415pub use self::mod_i16::encode_le as encode_i16_le;
416pub use self::mod_i16::EncodeLE as EncodeI16LE;
417
418mod mod_i32 {
419    gen_module!{i32, "i32", 4, i32::from_be, i32::from_le}
420}
421pub use self::mod_i32::decode_native as decode_i32_native;
422pub use self::mod_i32::DecodeNative as DecodeI32Native;
423pub use self::mod_i32::decode_be as decode_i32_be;
424pub use self::mod_i32::DecodeBE as DecodeI32BE;
425pub use self::mod_i32::decode_le as decode_i32_le;
426pub use self::mod_i32::DecodeLE as DecodeI32LE;
427pub use self::mod_i32::encode_native as encode_i32_native;
428pub use self::mod_i32::EncodeNative as EncodeI32Native;
429pub use self::mod_i32::encode_be as encode_i32_be;
430pub use self::mod_i32::EncodeBE as EncodeI32BE;
431pub use self::mod_i32::encode_le as encode_i32_le;
432pub use self::mod_i32::EncodeLE as EncodeI32LE;
433
434mod mod_i64 {
435    gen_module!{i64, "i64", 8, i64::from_be, i64::from_le}
436}
437pub use self::mod_i64::decode_native as decode_i64_native;
438pub use self::mod_i64::DecodeNative as DecodeI64Native;
439pub use self::mod_i64::decode_be as decode_i64_be;
440pub use self::mod_i64::DecodeBE as DecodeI64BE;
441pub use self::mod_i64::decode_le as decode_i64_le;
442pub use self::mod_i64::DecodeLE as DecodeI64LE;
443pub use self::mod_i64::encode_native as encode_i64_native;
444pub use self::mod_i64::EncodeNative as EncodeI64Native;
445pub use self::mod_i64::encode_be as encode_i64_be;
446pub use self::mod_i64::EncodeBE as EncodeI64BE;
447pub use self::mod_i64::encode_le as encode_i64_le;
448pub use self::mod_i64::EncodeLE as EncodeI64LE;
449
450#[cfg(test)]
451mod tests {
452    use atm_io_utils::partial::*;
453    use async_codec_util::testing::test_codec_len;
454    use async_ringbuffer::ring_buffer;
455
456    use super::*;
457
458    macro_rules! gen_byte_test {
459        ($num:ty, $decode_byte:expr, $encode_byte:expr) => (
460            quickcheck! {
461                fn test(buf_size: usize, read_ops: Vec<PartialOp>, write_ops: Vec<PartialOp>, num: $num) -> bool {
462                    let mut read_ops = read_ops;
463                    let mut write_ops = write_ops;
464                    let (w, r) = ring_buffer(buf_size + 1);
465                    let w = PartialWrite::new(w, write_ops.drain(..));
466                    let r = PartialRead::new(r, read_ops.drain(..));
467
468                    let test_outcome = test_codec_len(r, w, $decode_byte(), $encode_byte(num));
469                    test_outcome.1 && test_outcome.0 == num
470                }
471            }
472        );
473    }
474
475    macro_rules! gen_test {
476        ($num: ty, $decode_native:expr, $encode_native:expr, $decode_be:expr, $encode_be:expr, $decode_le:expr, $encode_le:expr) => (
477            quickcheck! {
478                fn native(buf_size: usize, read_ops: Vec<PartialOp>, write_ops: Vec<PartialOp>, num: $num) -> bool {
479                    let mut read_ops = read_ops;
480                    let mut write_ops = write_ops;
481                    let (w, r) = ring_buffer(buf_size + 1);
482                    let w = PartialWrite::new(w, write_ops.drain(..));
483                    let r = PartialRead::new(r, read_ops.drain(..));
484
485                    let test_outcome = test_codec_len(r, w, $decode_native(), $encode_native(num));
486                    test_outcome.1 && (test_outcome.0 == num)
487                }
488            }
489
490            quickcheck! {
491                fn be(buf_size: usize, read_ops: Vec<PartialOp>, write_ops: Vec<PartialOp>, num: $num) -> bool {
492                    let mut read_ops = read_ops;
493                    let mut write_ops = write_ops;
494                    let (w, r) = ring_buffer(buf_size + 1);
495                    let w = PartialWrite::new(w, write_ops.drain(..));
496                    let r = PartialRead::new(r, read_ops.drain(..));
497
498                    let test_outcome = test_codec_len(r, w, $decode_be(), $encode_be(num));
499                    test_outcome.1 && test_outcome.0 == num
500                }
501            }
502
503            quickcheck! {
504                fn le(buf_size: usize, read_ops: Vec<PartialOp>, write_ops: Vec<PartialOp>, num: $num) -> bool {
505                    let mut read_ops = read_ops;
506                    let mut write_ops = write_ops;
507                    let (w, r) = ring_buffer(buf_size + 1);
508                    let w = PartialWrite::new(w, write_ops.drain(..));
509                    let r = PartialRead::new(r, read_ops.drain(..));
510
511                    let test_outcome = test_codec_len(r, w, $decode_le(), $encode_le(num));
512                    test_outcome.1 && test_outcome.0 == num
513                }
514            }
515        )
516    }
517
518    mod test_u8 {
519        use super::*;
520        gen_byte_test!{u8, decode_u8, encode_u8}
521    }
522
523    mod test_i8 {
524        use super::*;
525        gen_byte_test!{i8, decode_i8, encode_i8}
526    }
527
528    mod test_u16 {
529        use super::*;
530        gen_test!{u16, decode_u16_native, encode_u16_native, decode_u16_be, encode_u16_be, decode_u16_le, encode_u16_le}
531    }
532
533    mod test_u32 {
534        use super::*;
535        gen_test!{u32, decode_u32_native, encode_u32_native, decode_u32_be, encode_u32_be, decode_u32_le, encode_u32_le}
536    }
537
538    mod test_u64 {
539        use super::*;
540        gen_test!{u64, decode_u64_native, encode_u64_native, decode_u64_be, encode_u64_be, decode_u64_le, encode_u64_le}
541    }
542
543    mod test_i16 {
544        use super::*;
545        gen_test!{i16, decode_i16_native, encode_i16_native, decode_i16_be, encode_i16_be, decode_i16_le, encode_i16_le}
546    }
547
548    mod test_i32 {
549        use super::*;
550        gen_test!{i32, decode_i32_native, encode_i32_native, decode_i32_be, encode_i32_be, decode_i32_le, encode_i32_le}
551    }
552
553    mod test_i64 {
554        use super::*;
555        gen_test!{i64, decode_i64_native, encode_i64_native, decode_i64_be, encode_i64_be, decode_i64_le, encode_i64_le}
556    }
557}