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}