1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use crate::digit;
use crate::doc;
// use core::mem::MaybeUninit;
macro_rules! endian {
($BUint: ident, $BInt: ident, $Digit: ident) => {
macro_rules! set_digit {
($out_digits: ident, $i: expr, $digit: expr, $is_negative: expr, $sign_bits: expr) => {
if $i == Self::N_MINUS_1 {
if ($digit as digit::$Digit::SignedDigit).is_negative() == $is_negative {
$out_digits[$i] = $digit;
} else {
return None;
}
} else if $i < N {
$out_digits[$i] = $digit;
} else if $digit != $sign_bits {
return None;
};
};
}
#[doc = doc::endian::impl_desc!($BInt)]
impl<const N: usize> $BInt<N> {
#[doc = doc::endian::from_be!(I 256)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn from_be(x: Self) -> Self {
Self::from_bits($BUint::from_be(x.bits))
}
#[doc = doc::endian::from_le!(I 256)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn from_le(x: Self) -> Self {
Self::from_bits($BUint::from_le(x.bits))
}
#[doc = doc::endian::to_be!(I 256)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn to_be(self) -> Self {
Self::from_be(self)
}
#[doc = doc::endian::to_le!(I 256)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn to_le(self) -> Self {
Self::from_le(self)
}
/// Create an integer value from a slice of bytes in big endian. The value is wrapped in an [`Option`](https://doc.rust-lang.org/core/option/enum.Option.html) as the integer represented by the slice of bytes may represent an integer too large to be represented by the type.
///
/// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros or ones at the start so that it's length equals `Self::BYTES`. It is padded with ones if the bytes represent a negative integer, otherwise it is padded with zeros.
///
/// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless the bytes represent a non-negative integer and leading zeros from the slice can be removed until the length of the slice equals `Self::BYTES`, or if the bytes represent a negative integer and leading ones from the slice can be removed until the length of the slice equals `Self::BYTES`.
///
/// For examples, see the
#[doc = concat!("[`from_be_slice`](crate::", stringify!($BUint), "::from_be_slice)")]
/// method documentation for
#[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
#[must_use = doc::must_use_op!()]
pub const fn from_be_slice(slice: &[u8]) -> Option<Self> {
let len = slice.len();
if len == 0 {
return Some(Self::ZERO);
}
let is_negative = (slice[0] as i8).is_negative();
let sign_bits = if is_negative {
$Digit::MAX
} else {
$Digit::MIN
};
let mut out_digits = if is_negative {
[$Digit::MAX; N]
} else {
[0; N]
};
let mut i = 0;
let exact = len >> digit::$Digit::BYTE_SHIFT;
while i < exact {
let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize];
let init_index = len - digit::$Digit::BYTES as usize;
let mut j = init_index;
while j < slice.len() {
digit_bytes[j - init_index] = slice[j - (i << digit::$Digit::BYTE_SHIFT)];
j += 1;
}
let digit = $Digit::from_be_bytes(digit_bytes);
set_digit!(out_digits, i, digit, is_negative, sign_bits);
i += 1;
}
let rem = len & (digit::$Digit::BYTES as usize - 1);
if rem == 0 {
Some(Self::from_bits($BUint::from_digits(out_digits)))
} else {
let pad_byte = if is_negative { u8::MAX } else { 0 };
let mut last_digit_bytes = [pad_byte; digit::$Digit::BYTES as usize];
let mut j = 0;
while j < rem {
last_digit_bytes[digit::$Digit::BYTES as usize - rem + j] = slice[j];
j += 1;
}
let digit = $Digit::from_be_bytes(last_digit_bytes);
set_digit!(out_digits, i, digit, is_negative, sign_bits);
Some(Self::from_bits($BUint::from_digits(out_digits)))
}
}
/// Creates an integer value from a slice of bytes in little endian. The value is wrapped in an [`Option`](https://doc.rust-lang.org/core/option/enum.Option.html) as the bytes may represent an integer too large to be represented by the type.
///
/// If the length of the slice is shorter than `Self::BYTES`, the slice is padded with zeros or ones at the end so that it's length equals `Self::BYTES`. It is padded with ones if the bytes represent a negative integer, otherwise it is padded with zeros.
///
/// If the length of the slice is longer than `Self::BYTES`, `None` will be returned, unless the bytes represent a non-negative integer and trailing zeros from the slice can be removed until the length of the slice equals `Self::BYTES`, or if the bytes represent a negative integer and trailing ones from the slice can be removed until the length of the slice equals `Self::BYTES`.
///
/// For examples, see the
#[doc = concat!("[`from_le_slice`](crate::", stringify!($BUint), "::from_le_slice)")]
/// method documentation for
#[doc = concat!("[`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
#[must_use = doc::must_use_op!()]
pub const fn from_le_slice(slice: &[u8]) -> Option<Self> {
let len = slice.len();
if len == 0 {
return Some(Self::ZERO);
}
let is_negative = (slice[len - 1] as i8).is_negative();
let sign_bits = if is_negative {
$Digit::MAX
} else {
$Digit::MIN
};
let mut out_digits = [sign_bits; N];
// let slice_ptr = slice.as_ptr();
let mut i = 0;
let exact = len >> digit::$Digit::BYTE_SHIFT;
while i < exact {
let mut digit_bytes = [0u8; digit::$Digit::BYTES as usize];
let init_index = i << digit::$Digit::BYTE_SHIFT;
let mut j = init_index;
while j < init_index + digit::$Digit::BYTES as usize {
digit_bytes[j - init_index] = slice[j];
j += 1;
}
let digit = $Digit::from_le_bytes(digit_bytes);
set_digit!(out_digits, i, digit, is_negative, sign_bits);
i += 1;
}
if len & (digit::$Digit::BYTES as usize - 1) == 0 {
Some(Self::from_bits($BUint::from_digits(out_digits)))
} else {
let pad_byte = if is_negative { u8::MAX } else { 0 };
let mut last_digit_bytes = [pad_byte; digit::$Digit::BYTES as usize];
let addition = exact << digit::$Digit::BYTE_SHIFT;
let mut j = 0;
while j + addition < len {
last_digit_bytes[j] = slice[j + addition];
j += 1;
}
let digit = $Digit::from_le_bytes(last_digit_bytes);
set_digit!(out_digits, i, digit, is_negative, sign_bits);
Some(Self::from_bits($BUint::from_digits(out_digits)))
}
}
}
};
}
crate::macro_impl!(endian);