recode/codec/
ux.rs

1use crate::bytes::{Buf, BufMut};
2use crate::util::EncoderExt;
3use crate::{Decoder, Encoder};
4
5pub use ux::{i24, i40, i48, i56, u24, u40, u48, u56};
6
7macro_rules! impl_ux {
8    ($t:ty; size: $s:literal; rep: $r:ty ) => {
9        impl<B: Buf> Decoder<B> for $t {
10            type Error = crate::Error;
11
12            fn decode(buf: &mut B) -> Result<Self, Self::Error> {
13                const REPR_LEN: usize = std::mem::size_of::<$r>();
14
15                if buf.remaining() < $s {
16                    return Err(crate::Error::BytesNeeded {
17                        needed: $s - buf.remaining(),
18                        full_len: $s,
19                        available: buf.remaining(),
20                    });
21                }
22
23                let mut be_repr = [0u8; REPR_LEN];
24                buf.copy_to_slice(&mut be_repr[(REPR_LEN - $s)..REPR_LEN]);
25
26                Ok(<$t>::new(<$r>::from_be_bytes(be_repr)))
27            }
28        }
29
30        impl<B: BufMut> Encoder<B> for $t {
31            type Error = std::convert::Infallible;
32
33            fn encode(item: &$t, buf: &mut B) -> Result<(), Self::Error> {
34                const REPR_LEN: usize = std::mem::size_of::<$r>();
35
36                let bytes = &<$r>::from(*item).to_be_bytes()[(REPR_LEN - $s)..];
37
38                buf.put_slice(bytes);
39
40                Ok(())
41            }
42
43            #[inline]
44            fn size_of(_: &$t, _: &B) -> usize {
45                $s
46            }
47        }
48
49        impl<B: Buf> Decoder<B, usize> for $t {
50            type Error = crate::Error;
51
52            fn decode(buf: &mut B) -> Result<usize, Self::Error> {
53                let value = <Self as crate::Decoder<B>>::decode(buf)?;
54
55                usize::try_from(<$r>::from(value))
56                    .map_err(|_| super::number::TryFromIntError(()))
57                    .map_err(Into::into)
58            }
59        }
60
61        impl<B: BufMut> Encoder<B, usize> for $t {
62            type Error = crate::Error;
63
64            fn encode(item: &usize, buf: &mut B) -> Result<(), Self::Error> {
65                let value = <$r>::try_from(*item)
66                    .map_err(|_| super::number::TryFromIntError(()))?;
67
68                <$t>::new(value).encode_to(buf).map_err(Into::into)
69            }
70
71            #[inline]
72            fn size_of(_: &usize, _: &B) -> usize {
73                $s
74            }
75        }
76    };
77}
78
79impl_ux!(i24; size: 3; rep: i32);
80impl_ux!(u24; size: 3; rep: u32);
81
82impl_ux!(i40; size: 5; rep: i64);
83impl_ux!(u40; size: 5; rep: u64);
84
85impl_ux!(i48; size: 6; rep: i64);
86impl_ux!(u48; size: 6; rep: u64);
87
88impl_ux!(i56; size: 7; rep: i64);
89impl_ux!(u56; size: 7; rep: u64);
90
91#[cfg(test)]
92mod tests {
93    use bytes::BytesMut;
94    use fake::Fake;
95
96    use super::*;
97    use crate::util::EncoderExt;
98
99    macro_rules! test_ux {
100        ($t:ty; size: $s:literal; rep: $r:ty ) => {
101            paste::paste! {
102                #[test]
103                fn [<test_ $t>]() {
104                    const REPR_LEN: usize = std::mem::size_of::<$r>();
105
106                    let rmax: $r = <$t>::MAX.into();
107                    let repr: $r = (0..rmax).fake();
108
109                    if stringify!($t).starts_with("u") {
110                        assert_eq!(rmax.trailing_ones(), $s * 8);
111                    } else {
112                        assert_eq!(rmax.trailing_ones(), $s * 8 - 1);
113                    }
114
115                    assert_eq!(repr & !rmax, 0);
116
117                    let value = <$t>::new(repr);
118                    let mut bytes = BytesMut::new();
119
120                    assert_eq!($s, value.size(&bytes));
121
122                    value.encode_to(&mut bytes).unwrap();
123
124                    assert_eq!($s, bytes.len());
125                    assert_eq!(&repr.to_be_bytes()[(REPR_LEN - $s)..], &bytes[..]);
126                }
127            }
128        };
129    }
130
131    test_ux!(i24; size: 3; rep: i32);
132    test_ux!(u24; size: 3; rep: u32);
133
134    test_ux!(i40; size: 5; rep: i64);
135    test_ux!(u40; size: 5; rep: u64);
136
137    test_ux!(i48; size: 6; rep: i64);
138    test_ux!(u48; size: 6; rep: u64);
139
140    test_ux!(i56; size: 7; rep: i64);
141    test_ux!(u56; size: 7; rep: u64);
142}