musli_common/int/
traits.rs

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