1use crate::Uint;
5use core::slice;
6
7#[cfg(feature = "alloc")]
8#[allow(unused_imports)]
9use alloc::{borrow::Cow, vec::Vec};
10
11impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
13 pub const BYTES: usize = (BITS + 7) / 8;
16
17 #[cfg(target_endian = "little")]
24 #[must_use]
25 #[inline(always)]
26 pub const fn as_le_slice(&self) -> &[u8] {
27 unsafe { slice::from_raw_parts(self.limbs.as_ptr().cast(), Self::BYTES) }
28 }
29
30 #[cfg(target_endian = "little")]
40 #[must_use]
41 #[inline(always)]
42 pub unsafe fn as_le_slice_mut(&mut self) -> &mut [u8] {
43 unsafe { slice::from_raw_parts_mut(self.limbs.as_mut_ptr().cast(), Self::BYTES) }
44 }
45
46 #[cfg(feature = "alloc")]
50 #[must_use]
51 #[inline]
52 #[allow(clippy::missing_const_for_fn)]
53 pub fn as_le_bytes(&self) -> Cow<'_, [u8]> {
54 #[cfg(target_endian = "little")]
56 return Cow::Borrowed(self.as_le_slice());
57
58 #[cfg(target_endian = "big")]
60 return Cow::Owned({
61 let mut cpy = *self;
62 for limb in &mut cpy.limbs {
63 *limb = limb.reverse_bits();
64 }
65 unsafe { slice::from_raw_parts(cpy.limbs.as_ptr().cast(), Self::BYTES).to_vec() }
66 });
67 }
68
69 #[cfg(feature = "alloc")]
74 #[must_use]
75 #[inline]
76 pub fn as_le_bytes_trimmed(&self) -> Cow<'_, [u8]> {
77 match self.as_le_bytes() {
78 Cow::Borrowed(slice) => Cow::Borrowed(crate::utils::trim_end_slice(slice, &0)),
79 Cow::Owned(mut vec) => {
80 crate::utils::trim_end_vec(&mut vec, &0);
81 Cow::Owned(vec)
82 }
83 }
84 }
85
86 #[inline]
97 #[must_use]
98 pub const fn to_le_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
99 assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
101
102 #[cfg(target_endian = "little")]
104 return unsafe { *self.as_le_slice().as_ptr().cast() };
106
107 #[cfg(target_endian = "big")]
109 {
110 let mut limbs = self.limbs;
111 let mut i = 0;
112 while i < LIMBS {
113 limbs[i] = limbs[i].to_le();
114 i += 1;
115 }
116 unsafe { *limbs.as_ptr().cast() }
118 }
119 }
120
121 #[cfg(feature = "alloc")]
127 #[must_use]
128 #[inline]
129 pub fn to_le_bytes_vec(&self) -> Vec<u8> {
130 self.as_le_bytes().into_owned()
131 }
132
133 #[cfg(feature = "alloc")]
136 #[must_use]
137 #[inline]
138 pub fn to_le_bytes_trimmed_vec(&self) -> Vec<u8> {
139 self.as_le_bytes_trimmed().into_owned()
140 }
141
142 #[must_use]
153 #[inline]
154 pub const fn to_be_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
155 let mut bytes = self.to_le_bytes::<BYTES>();
156
157 let len = bytes.len();
159 let half_len = len / 2;
160 let mut i = 0;
161 while i < half_len {
162 let tmp = bytes[i];
163 bytes[i] = bytes[len - 1 - i];
164 bytes[len - 1 - i] = tmp;
165 i += 1;
166 }
167
168 bytes
169 }
170
171 #[cfg(feature = "alloc")]
177 #[must_use]
178 #[inline]
179 pub fn to_be_bytes_vec(&self) -> Vec<u8> {
180 let mut bytes = self.to_le_bytes_vec();
181 bytes.reverse();
182 bytes
183 }
184
185 #[cfg(feature = "alloc")]
188 #[must_use]
189 #[inline]
190 pub fn to_be_bytes_trimmed_vec(&self) -> Vec<u8> {
191 let mut bytes = self.to_le_bytes_trimmed_vec();
192 bytes.reverse();
193 bytes
194 }
195
196 #[must_use]
209 #[track_caller]
210 #[inline]
211 pub const fn from_be_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
212 assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
214 Self::from_be_slice(&bytes)
215 }
216
217 #[must_use]
226 #[track_caller]
227 #[inline]
228 pub const fn from_be_slice(bytes: &[u8]) -> Self {
229 match Self::try_from_be_slice(bytes) {
230 Some(value) => value,
231 None => panic!("Value too large for Uint"),
232 }
233 }
234
235 #[must_use]
242 #[inline]
243 pub const fn try_from_be_slice(bytes: &[u8]) -> Option<Self> {
244 if bytes.len() > Self::BYTES {
245 return None;
246 }
247
248 if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
249 let mut limbs = [0; LIMBS];
251 let end = bytes.as_ptr_range().end;
252 let mut i = 0;
253 while i < LIMBS {
254 limbs[i] = u64::from_be_bytes(unsafe { *end.sub((i + 1) * 8).cast() });
255 i += 1;
256 }
257 return Some(Self::from_limbs(limbs));
258 }
259
260 let mut limbs = [0; LIMBS];
261 let mut i = 0;
262 let mut c = bytes.len();
263 while i < bytes.len() {
264 c -= 1;
265 limbs[i / 8] += (bytes[c] as u64) << ((i % 8) * 8);
266 i += 1;
267 }
268 if Self::LIMBS > 0 && limbs[Self::LIMBS - 1] > Self::MASK {
269 return None;
270 }
271 Some(Self::from_limbs(limbs))
272 }
273
274 #[must_use]
287 #[track_caller]
288 #[inline]
289 pub const fn from_le_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
290 assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
292 Self::from_le_slice(&bytes)
293 }
294
295 #[must_use]
304 #[track_caller]
305 #[inline]
306 pub const fn from_le_slice(bytes: &[u8]) -> Self {
307 match Self::try_from_le_slice(bytes) {
308 Some(value) => value,
309 None => panic!("Value too large for Uint"),
310 }
311 }
312
313 #[must_use]
320 #[inline]
321 pub const fn try_from_le_slice(bytes: &[u8]) -> Option<Self> {
322 if bytes.len() / 8 > Self::LIMBS {
323 return None;
324 }
325
326 if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
327 let mut limbs = [0; LIMBS];
329 let mut i = 0;
330 while i < LIMBS {
331 limbs[i] = u64::from_le_bytes(unsafe { *bytes.as_ptr().add(i * 8).cast() });
332 i += 1;
333 }
334 return Some(Self::from_limbs(limbs));
335 }
336
337 let mut limbs = [0; LIMBS];
338 let mut i = 0;
339 while i < bytes.len() {
340 limbs[i / 8] += (bytes[i] as u64) << ((i % 8) * 8);
341 i += 1;
342 }
343 if Self::LIMBS > 0 && limbs[Self::LIMBS - 1] > Self::MASK {
344 return None;
345 }
346 Some(Self::from_limbs(limbs))
347 }
348}
349
350#[inline]
356#[must_use]
357pub const fn nbytes(bits: usize) -> usize {
358 (bits + 7) / 8
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364 use crate::{const_for, nlimbs};
365 use proptest::proptest;
366
367 const N: Uint<128, 2> =
368 Uint::from_limbs([0x7890_1234_5678_9012_u64, 0x1234_5678_9012_3456_u64]);
369 const BE: [u8; 16] = [
370 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90,
371 0x12,
372 ];
373 const LE: [u8; 16] = [
374 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34,
375 0x12,
376 ];
377
378 const K: Uint<72, 2> = Uint::from_limbs([0x3456_7890_1234_5678_u64, 0x12_u64]);
379 const KBE: [u8; 9] = [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78];
380 const KLE: [u8; 9] = [0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12];
381
382 #[test]
383 const fn const_from_to_bytes() {
384 const NL: [u64; 2] = N.limbs;
385 const KL: [u64; 2] = K.limbs;
386 assert!(matches!(Uint::<128, 2>::from_be_bytes(BE).limbs, NL));
387 assert!(matches!(Uint::<128, 2>::from_le_bytes(LE).limbs, NL));
388 assert!(matches!(N.to_be_bytes::<{ BE.len() }>(), BE));
389 assert!(matches!(N.to_le_bytes::<{ LE.len() }>(), LE));
390
391 assert!(matches!(Uint::<72, 2>::from_be_bytes(KBE).limbs, KL));
392 assert!(matches!(Uint::<72, 2>::from_le_bytes(KLE).limbs, KL));
393 assert!(matches!(K.to_be_bytes::<{ KBE.len() }>(), KBE));
394 assert!(matches!(K.to_le_bytes::<{ KLE.len() }>(), KLE));
395
396 assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
397 assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
398 assert!(matches!(
399 Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
400 [1]
401 ));
402 assert!(matches!(
403 Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
404 [0x12, 0x34]
405 ));
406
407 assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
408 assert!(matches!(Uint::<0, 0>::ZERO.to_le_bytes::<0>(), []));
409 assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
410 assert!(matches!(Uint::<1, 1>::ZERO.to_le_bytes::<1>(), [0]));
411 assert!(matches!(
412 Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
413 [1]
414 ));
415 assert!(matches!(
416 Uint::<1, 1>::from_limbs([1]).to_le_bytes::<1>(),
417 [1]
418 ));
419 assert!(matches!(
420 Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
421 [0x12, 0x34]
422 ));
423 assert!(matches!(
424 Uint::<16, 1>::from_limbs([0x1234]).to_le_bytes::<2>(),
425 [0x34, 0x12]
426 ));
427
428 assert!(matches!(
429 Uint::<63, 1>::from_limbs([0x010203]).to_be_bytes::<8>(),
430 [0, 0, 0, 0, 0, 1, 2, 3]
431 ));
432 assert!(matches!(
433 Uint::<63, 1>::from_limbs([0x010203]).to_le_bytes::<8>(),
434 [3, 2, 1, 0, 0, 0, 0, 0]
435 ));
436 }
437
438 #[test]
439 fn test_from_bytes() {
440 assert_eq!(Uint::<0, 0>::from_be_bytes([]), Uint::ZERO);
441 assert_eq!(Uint::<0, 0>::from_le_bytes([]), Uint::ZERO);
442 assert_eq!(
443 Uint::<12, 1>::from_be_bytes([0x01, 0x23]),
444 Uint::from(0x0123)
445 );
446 assert_eq!(
447 Uint::<12, 1>::from_le_bytes([0x23, 0x01]),
448 Uint::from(0x0123)
449 );
450 assert_eq!(
451 Uint::<16, 1>::from_be_bytes([0x12, 0x34]),
452 Uint::from(0x1234)
453 );
454 assert_eq!(
455 Uint::<16, 1>::from_le_bytes([0x34, 0x12]),
456 Uint::from(0x1234)
457 );
458 assert_eq!(Uint::from_be_bytes(BE), N);
459 assert_eq!(Uint::from_le_bytes(LE), N);
460 assert_eq!(Uint::from_be_bytes(KBE), K);
461 assert_eq!(Uint::from_le_bytes(KLE), K);
462 }
463
464 #[test]
465 fn test_to_bytes() {
466 assert_eq!(Uint::<0, 0>::ZERO.to_le_bytes(), [0_u8; 0]);
467 assert_eq!(Uint::<0, 0>::ZERO.to_be_bytes(), [0_u8; 0]);
468 assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_le_bytes(), [0x23, 0x01]);
469 assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_be_bytes(), [0x01, 0x23]);
470 assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_le_bytes(), [0x34, 0x12]);
471 assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_be_bytes(), [0x12, 0x34]);
472 assert_eq!(K.to_be_bytes(), KBE);
473 assert_eq!(K.to_le_bytes(), KLE);
474 }
475
476 #[test]
477 fn test_bytes_roundtrip() {
478 const_for!(BITS in SIZES {
479 const LIMBS: usize = nlimbs(BITS);
480 const BYTES: usize = nbytes(BITS);
481 proptest!(|(value: Uint<BITS, LIMBS>)| {
482 assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes()).unwrap());
483 assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes_trimmed()).unwrap());
484 assert_eq!(value, Uint::try_from_be_slice(&value.to_be_bytes_trimmed_vec()).unwrap());
485 assert_eq!(value, Uint::try_from_le_slice(&value.to_le_bytes_trimmed_vec()).unwrap());
486 assert_eq!(value, Uint::from_be_bytes(value.to_be_bytes::<BYTES>()));
487 assert_eq!(value, Uint::from_le_bytes(value.to_le_bytes::<BYTES>()));
488 });
489 });
490 }
491}