reweb3_num/buint/endian.rs
1use crate::digit;
2use crate::doc;
3// use core::mem::MaybeUninit;
4
5macro_rules! endian {
6 ($BUint: ident, $BInt: ident, $Digit: ident) => {
7 #[doc = doc::endian::impl_desc!($BUint)]
8 impl<const N: usize> $BUint<N> {
9 #[doc = doc::endian::from_be!(U 256)]
10 #[must_use]
11 #[inline]
12 pub const fn from_be(x: Self) -> Self {
13 #[cfg(target_endian = "big")]
14 return x;
15 #[cfg(not(target_endian = "big"))]
16 x.swap_bytes()
17 }
18
19 #[doc = doc::endian::from_le!(U 256)]
20 #[must_use]
21 #[inline]
22 pub const fn from_le(x: Self) -> Self {
23 #[cfg(target_endian = "little")]
24 return x;
25 #[cfg(not(target_endian = "little"))]
26 x.swap_bytes()
27 }
28
29 #[doc = doc::endian::to_be!(U 256)]
30 #[must_use = doc::must_use_op!()]
31 #[inline]
32 pub const fn to_be(self) -> Self {
33 Self::from_be(self)
34 }
35
36 #[doc = doc::endian::to_le!(U 256)]
37 #[must_use = doc::must_use_op!()]
38 #[inline]
39 pub const fn to_le(self) -> Self {
40 Self::from_le(self)
41 }
42
43 /// Create an integer value from a slice of bytes in big endian. The value is wrapped in an `Option` as the integer represented by the slice of bytes may represent an integer too large to be represented by the type.
44 ///
45 /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros at the start so that it's length equals `Self::BYTES`.
46 ///
47 /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless leading zeros from the slice can be removed until the length of the slice equals `Self::BYTES`.
48 ///
49 /// # Examples
50 ///
51 /// ```
52 /// use reweb3_num::types::U128;
53 ///
54 /// let value_from_array = U128::from(u128::from_be_bytes([0, 0, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]));
55 /// // using the `from_be_bytes` method on the primitve `u128` here instead of on `U128` as `from_be_bytes` is currently only available in bnum on nightly
56 /// let value_from_slice = U128::from_be_slice(&[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]).unwrap();
57 /// let value_from_long_slice = U128::from_be_slice(&[0, 0, 0, 0, 0, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]).unwrap();
58 ///
59 /// assert_eq!(value_from_array, value_from_slice);
60 /// assert_eq!(value_from_array, value_from_long_slice);
61 ///
62 /// let invalid_slice = &[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90];
63 /// assert_eq!(U128::from_be_slice(invalid_slice), None);
64 /// ```
65 #[must_use]
66 pub const fn from_be_slice(slice: &[u8]) -> Option<Self> {
67 let len = slice.len();
68 let mut out = Self::ZERO;
69 // let slice_ptr = slice.as_ptr();
70 let mut i = 0;
71 let exact = len >> digit::$Digit::BYTE_SHIFT;
72 while i < exact {
73 let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize];
74 let init_index = len - digit::$Digit::BYTES as usize;
75 let mut j = init_index;
76 while j < slice.len() {
77 digit_bytes[j - init_index] = slice[j - (i << digit::$Digit::BYTE_SHIFT)];
78 j += 1;
79 }
80 let digit = $Digit::from_be_bytes(digit_bytes);
81 if i < N {
82 out.digits[i] = digit;
83 } else if digit != 0 {
84 return None;
85 };
86 i += 1;
87 }
88 let rem = len & (digit::$Digit::BYTES as usize - 1);
89 if rem == 0 {
90 Some(out)
91 } else {
92 let mut last_digit_bytes = [0; digit::$Digit::BYTES as usize];
93 let mut j = 0;
94 while j < rem {
95 last_digit_bytes[digit::$Digit::BYTES as usize - rem + j] = slice[j];
96 j += 1;
97 }
98 let digit = $Digit::from_be_bytes(last_digit_bytes);
99 if i < N {
100 out.digits[i] = digit;
101 } else if digit != 0 {
102 return None;
103 };
104 Some(out)
105 }
106 }
107
108 /// Creates an integer value from a slice of bytes in little endian. The value is wrapped in an `Option` as the bytes may represent an integer too large to be represented by the type.
109 ///
110 /// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros at the end so that it's length equals `Self::BYTES`.
111 ///
112 /// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless trailing zeros from the slice can be removed until the length of the slice equals `Self::BYTES`.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use reweb3_num::types::U128;
118 ///
119 /// let value_from_array = U128::from(u128::from_le_bytes([0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0, 0]));
120 /// // using the `from_le_bytes` method on the primitve `u128` here instead of on `U128` as `from_le_bytes` is currently only available in bnum on nightly
121 /// let value_from_slice = U128::from_le_slice(&[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56]).unwrap();
122 /// let value_from_long_slice = U128::from_le_slice(&[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0, 0, 0, 0, 0, 0]).unwrap();
123 ///
124 /// assert_eq!(value_from_array, value_from_slice);
125 /// assert_eq!(value_from_array, value_from_long_slice);
126 ///
127 /// let invalid_slice = &[0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90];
128 /// assert_eq!(U128::from_le_slice(invalid_slice), None);
129 /// ```
130 #[must_use]
131 pub const fn from_le_slice(slice: &[u8]) -> Option<Self> {
132 let len = slice.len();
133 let mut out = Self::ZERO;
134 // let slice_ptr = slice.as_ptr();
135 let mut i = 0;
136 let exact = len >> digit::$Digit::BYTE_SHIFT;
137 while i < exact {
138 let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize];
139 let init_index = i << digit::$Digit::BYTE_SHIFT;
140 let mut j = init_index;
141 while j < init_index + digit::$Digit::BYTES as usize {
142 digit_bytes[j - init_index] = slice[j];
143 j += 1;
144 }
145 let digit = $Digit::from_le_bytes(digit_bytes);
146 if i < N {
147 out.digits[i] = digit;
148 } else if digit != 0 {
149 return None;
150 };
151 i += 1;
152 }
153 if len & (digit::$Digit::BYTES as usize - 1) == 0 {
154 Some(out)
155 } else {
156 let mut last_digit_bytes = [0; digit::$Digit::BYTES as usize];
157 let addition = exact << digit::$Digit::BYTE_SHIFT;
158 let mut j = 0;
159 while j + addition < len {
160 last_digit_bytes[j] = slice[j + addition];
161 j += 1;
162 }
163 let digit = $Digit::from_le_bytes(last_digit_bytes);
164 if i < N {
165 out.digits[i] = digit;
166 } else if digit != 0 {
167 return None;
168 };
169 Some(out)
170 }
171 }
172 }
173 };
174}
175
176crate::macro_impl!(endian);