musli/int/
traits.rs

1use core::ops::{BitAnd, BitXor, Neg, Shl, Shr};
2
3use crate::options::ByteOrder;
4use crate::{Context, Reader, Writer};
5
6/// Trait that encodes common behaviors of unsigned numbers.
7pub(crate) trait Unsigned:
8    Copy
9    + Shr<u32, Output = Self>
10    + Shl<u32, Output = Self>
11    + BitXor<Output = Self>
12    + BitAnd<Output = Self>
13    + Ord
14{
15    /// The number `1` as represented by the current unsigned number.
16    const ONE: Self;
17
18    /// Number of bytes.
19    #[cfg(feature = "wire")]
20    const BYTES: u8;
21
22    /// Number of bits.
23    const BITS: u32;
24
25    /// The signed representation of this unsigned number.
26    type Signed: Signed<Unsigned = Self>;
27
28    /// Coerce this number bitwise into its signed representation.
29    fn signed(self) -> Self::Signed;
30
31    /// Construct from the first byte.
32    fn from_byte(byte: u8) -> Self;
33
34    /// Coerce into the lowest 8-bits as a byte.
35    fn as_byte(self) -> u8;
36
37    /// Test if this value is smaller than the specified byte.
38    #[cfg(feature = "wire")]
39    fn is_smaller_than(self, byte: u8) -> bool;
40
41    /// Test if value is zero.
42    fn is_zero(self) -> bool;
43
44    /// Perform a wrapping shift-left operation.
45    fn wrapping_shl(self, value: u32) -> Self;
46
47    /// Perform a wrapping addition.
48    fn wrapping_add(self, value: Self) -> Self;
49}
50
51/// Helper trait for performing I/O over [Unsigned] types.
52pub(crate) trait UnsignedOps: Unsigned {
53    /// Write the current byte array to the given writer in little-endian
54    /// encoding.
55    fn write_bytes<C, W>(self, cx: &C, writer: W, byte_order: ByteOrder) -> Result<(), C::Error>
56    where
57        C: ?Sized + Context,
58        W: Writer;
59
60    /// Read the current value from the reader in little-endian encoding.
61    fn read_bytes<'de, C, R>(cx: &C, reader: R, byte_order: ByteOrder) -> Result<Self, C::Error>
62    where
63        C: ?Sized + Context,
64        R: Reader<'de>;
65}
66
67/// Trait that encodes common behaviors of signed numbers.
68pub(crate) trait Signed:
69    Copy
70    + Neg<Output = Self>
71    + Shr<u32, Output = Self>
72    + Shl<u32, Output = Self>
73    + BitXor<Output = Self>
74{
75    /// The number of bits in this signed number.
76    const BITS: u32;
77
78    /// The unsigned representation of this number.
79    type Unsigned: Unsigned<Signed = Self>;
80
81    /// Coerce this number bitwise into its unsigned representation.
82    fn unsigned(self) -> Self::Unsigned;
83}
84
85macro_rules! implement {
86    ($signed:ty, $unsigned:ty) => {
87        impl Signed for $signed {
88            const BITS: u32 = <$signed>::BITS;
89
90            type Unsigned = $unsigned;
91
92            fn unsigned(self) -> Self::Unsigned {
93                self as $unsigned
94            }
95        }
96
97        impl Unsigned for $unsigned {
98            const ONE: Self = 1;
99            #[cfg(feature = "wire")]
100            const BYTES: u8 = (<$unsigned>::BITS / 8) as u8;
101            const BITS: u32 = <$signed>::BITS;
102
103            type Signed = $signed;
104
105            #[inline]
106            fn signed(self) -> Self::Signed {
107                self as $signed
108            }
109
110            #[inline]
111            fn from_byte(byte: u8) -> Self {
112                byte as $unsigned
113            }
114
115            #[inline]
116            fn as_byte(self) -> u8 {
117                self as u8
118            }
119
120            #[inline]
121            #[cfg(feature = "wire")]
122            fn is_smaller_than(self, b: u8) -> bool {
123                self < b as $unsigned
124            }
125
126            #[inline]
127            fn is_zero(self) -> bool {
128                self == 0
129            }
130
131            #[inline]
132            fn wrapping_shl(self, value: u32) -> Self {
133                <$unsigned>::wrapping_shl(self, value)
134            }
135
136            #[inline]
137            fn wrapping_add(self, value: Self) -> Self {
138                <$unsigned>::wrapping_add(self, value)
139            }
140        }
141    };
142}
143
144macro_rules! implement_ops {
145    ($signed:ty, $unsigned:ty) => {
146        implement!($signed, $unsigned);
147
148        impl UnsignedOps for $unsigned {
149            #[inline(always)]
150            fn write_bytes<C, W>(
151                self,
152                cx: &C,
153                mut writer: W,
154                byte_order: ByteOrder,
155            ) -> Result<(), C::Error>
156            where
157                C: ?Sized + Context,
158                W: Writer,
159            {
160                let bytes = match byte_order {
161                    ByteOrder::NATIVE => self,
162                    _ => <$unsigned>::swap_bytes(self),
163                };
164
165                let bytes = <$unsigned>::to_ne_bytes(bytes);
166                writer.write_bytes(cx, &bytes)
167            }
168
169            #[inline(always)]
170            fn read_bytes<'de, C, R>(
171                cx: &C,
172                mut reader: R,
173                byte_order: ByteOrder,
174            ) -> Result<Self, C::Error>
175            where
176                C: ?Sized + Context,
177                R: Reader<'de>,
178            {
179                let bytes = reader.read_array(cx)?;
180                let bytes = <$unsigned>::from_ne_bytes(bytes);
181
182                let bytes = match byte_order {
183                    ByteOrder::NATIVE => bytes,
184                    _ => <$unsigned>::swap_bytes(bytes),
185                };
186
187                Ok(bytes)
188            }
189        }
190    };
191}
192
193implement_ops!(i8, u8);
194implement_ops!(i16, u16);
195implement_ops!(i32, u32);
196implement_ops!(i64, u64);
197implement_ops!(i128, u128);
198implement!(isize, usize);