ibig/
primitive.rs

1//! Primitive integral types.
2
3use crate::{
4    arch::word::{DoubleWord, Word},
5    error::OutOfBoundsError,
6    sign::Sign::{self, *},
7};
8use core::{
9    convert::{TryFrom, TryInto},
10    fmt::Debug,
11    mem,
12    ops::{Add, Div, Mul, Shl, Shr, Sub},
13};
14
15/// Cast `Word` to `DoubleWord`.
16#[inline]
17pub(crate) const fn extend_word(word: Word) -> DoubleWord {
18    word as DoubleWord
19}
20
21/// Create a `DoubleWord` from two `Word`s.
22#[inline]
23pub(crate) const fn double_word(low: Word, high: Word) -> DoubleWord {
24    extend_word(low) | extend_word(high) << WORD_BITS
25}
26
27#[inline]
28pub(crate) const fn split_double_word(dw: DoubleWord) -> (Word, Word) {
29    (dw as Word, (dw >> WORD_BITS) as Word)
30}
31
32pub(crate) trait PrimitiveUnsigned
33where
34    Self: Copy,
35    Self: Debug,
36    Self: Default,
37    Self: From<u8>,
38    Self: TryFrom<Word>,
39    Self: TryInto<Word>,
40    Self: TryInto<usize>,
41    Self: Eq,
42    Self: Add<Output = Self>,
43    Self: Div<Output = Self>,
44    Self: Mul<Output = Self>,
45    Self: Sub<Output = Self>,
46    Self: Shl<u32, Output = Self>,
47    Self: Shr<u32, Output = Self>,
48{
49    const BYTE_SIZE: usize = mem::size_of::<Self>();
50    const BIT_SIZE: u32 = 8 * Self::BYTE_SIZE as u32;
51    const MAX: Self;
52    type ByteRepr: AsRef<[u8]> + AsMut<[u8]>;
53
54    fn to_le_bytes(self) -> Self::ByteRepr;
55    fn from_le_bytes(repr: Self::ByteRepr) -> Self;
56    fn leading_zeros(self) -> u32;
57}
58
59pub(crate) trait PrimitiveSigned
60where
61    Self: Copy,
62    Self: TryFrom<Word>,
63    Self::Unsigned: PrimitiveUnsigned,
64    Self::Unsigned: TryFrom<Self>,
65    Self::Unsigned: TryInto<Self>,
66{
67    type Unsigned;
68
69    fn to_sign_magnitude(self) -> (Sign, Self::Unsigned);
70    fn try_from_sign_magnitude(sign: Sign, mag: Self::Unsigned) -> Result<Self, OutOfBoundsError>;
71}
72
73macro_rules! impl_primitive_unsigned {
74    ($t:ty) => {
75        impl PrimitiveUnsigned for $t {
76            // LEGACY: In Rust 1.49 this could be [u8; Self::BYTE_SIZE].
77            type ByteRepr = [u8; mem::size_of::<Self>()];
78            const MAX: Self = Self::MAX;
79
80            #[inline]
81            fn to_le_bytes(self) -> Self::ByteRepr {
82                self.to_le_bytes()
83            }
84
85            #[inline]
86            fn from_le_bytes(repr: Self::ByteRepr) -> Self {
87                Self::from_le_bytes(repr)
88            }
89
90            #[inline]
91            fn leading_zeros(self) -> u32 {
92                self.leading_zeros()
93            }
94        }
95    };
96}
97
98macro_rules! impl_primitive_signed {
99    ($t:ty, $u:ty) => {
100        impl PrimitiveSigned for $t {
101            type Unsigned = $u;
102
103            #[inline]
104            fn to_sign_magnitude(self) -> (Sign, Self::Unsigned) {
105                if self >= 0 {
106                    (Positive, self as Self::Unsigned)
107                } else {
108                    (Negative, (self as Self::Unsigned).wrapping_neg())
109                }
110            }
111
112            #[inline]
113            fn try_from_sign_magnitude(
114                sign: Sign,
115                mag: Self::Unsigned,
116            ) -> Result<Self, OutOfBoundsError> {
117                match sign {
118                    Positive => mag.try_into().map_err(|_| OutOfBoundsError),
119                    Negative => {
120                        let x = mag.wrapping_neg() as Self;
121                        if x <= 0 {
122                            Ok(x)
123                        } else {
124                            Err(OutOfBoundsError)
125                        }
126                    }
127                }
128            }
129        }
130    };
131}
132
133impl_primitive_unsigned!(u8);
134impl_primitive_unsigned!(u16);
135impl_primitive_unsigned!(u32);
136impl_primitive_unsigned!(u64);
137impl_primitive_unsigned!(u128);
138impl_primitive_unsigned!(usize);
139
140impl_primitive_signed!(i8, u8);
141impl_primitive_signed!(i16, u16);
142impl_primitive_signed!(i32, u32);
143impl_primitive_signed!(i64, u64);
144impl_primitive_signed!(i128, u128);
145impl_primitive_signed!(isize, usize);
146
147pub(crate) const WORD_BITS: u32 = Word::BIT_SIZE;
148pub(crate) const WORD_BITS_USIZE: usize = WORD_BITS as usize;
149pub(crate) const WORD_BYTES: usize = Word::BYTE_SIZE;
150
151#[inline]
152pub(crate) fn word_from_le_bytes_partial(bytes: &[u8]) -> Word {
153    let mut word_bytes = [0; WORD_BYTES];
154    word_bytes[..bytes.len()].copy_from_slice(bytes);
155    Word::from_le_bytes(word_bytes)
156}
157
158#[inline]
159pub(crate) fn word_from_be_bytes_partial(bytes: &[u8]) -> Word {
160    let mut word_bytes = [0; WORD_BYTES];
161    word_bytes[Word::BYTE_SIZE - bytes.len()..].copy_from_slice(bytes);
162    Word::from_be_bytes(word_bytes)
163}
164
165#[cfg(test)]
166mod tests {
167    use super::*;
168
169    #[test]
170    fn test_bits_bytes() {
171        assert_eq!(u8::BIT_SIZE, 8);
172        assert_eq!(u64::BIT_SIZE, 64);
173        assert_eq!(u8::BYTE_SIZE, 1);
174        assert_eq!(u64::BYTE_SIZE, 8);
175    }
176
177    #[test]
178    fn test_word_from_le_bytes_partial() {
179        assert_eq!(word_from_le_bytes_partial(&[1, 2]), 0x0201);
180    }
181
182    #[test]
183    fn test_word_from_be_bytes_partial() {
184        assert_eq!(word_from_be_bytes_partial(&[1, 2]), 0x0102);
185    }
186
187    #[test]
188    fn test_double_word() {
189        assert_eq!(DoubleWord::BIT_SIZE, 2 * WORD_BITS);
190        assert_eq!(split_double_word(double_word(3, 4)), (3, 4));
191    }
192
193    #[test]
194    fn test_to_sign_magnitude() {
195        assert_eq!(0.to_sign_magnitude(), (Positive, 0u32));
196        assert_eq!(5.to_sign_magnitude(), (Positive, 5u32));
197        assert_eq!(0x7fffffff.to_sign_magnitude(), (Positive, 0x7fffffffu32));
198        assert_eq!((-0x80000000).to_sign_magnitude(), (Negative, 0x80000000u32));
199    }
200
201    #[test]
202    fn test_try_from_sign_magnitude() {
203        assert_eq!(i32::try_from_sign_magnitude(Positive, 0), Ok(0));
204        assert_eq!(i32::try_from_sign_magnitude(Positive, 5), Ok(5));
205        assert_eq!(
206            i32::try_from_sign_magnitude(Positive, 0x7fffffff),
207            Ok(0x7fffffff)
208        );
209        assert!(i32::try_from_sign_magnitude(Positive, 0x80000000).is_err());
210        assert_eq!(i32::try_from_sign_magnitude(Negative, 0), Ok(0));
211        assert_eq!(i32::try_from_sign_magnitude(Negative, 5), Ok(-5));
212        assert_eq!(
213            i32::try_from_sign_magnitude(Negative, 0x7fffffff),
214            Ok(-0x7fffffff)
215        );
216        assert_eq!(
217            i32::try_from_sign_magnitude(Negative, 0x80000000),
218            Ok(-0x80000000)
219        );
220        assert!(i32::try_from_sign_magnitude(Negative, 0x80000001).is_err());
221        assert!(i32::try_from_sign_magnitude(Negative, 0xffffffff).is_err());
222    }
223}