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.swap_bytes();
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 let (limb, byte) = (i / 8, i % 8);
266 limbs[limb] += (bytes[c] as u64) << (byte * 8);
267 i += 1;
268 }
269 if Self::LIMBS > 0 && limbs[Self::LIMBS - 1] > Self::MASK {
270 return None;
271 }
272 Some(Self::from_limbs(limbs))
273 }
274
275 #[must_use]
288 #[track_caller]
289 #[inline]
290 pub const fn from_le_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
291 assert!(BYTES == Self::BYTES, "BYTES must be equal to Self::BYTES");
293 Self::from_le_slice(&bytes)
294 }
295
296 #[must_use]
305 #[track_caller]
306 #[inline]
307 pub const fn from_le_slice(bytes: &[u8]) -> Self {
308 match Self::try_from_le_slice(bytes) {
309 Some(value) => value,
310 None => panic!("Value too large for Uint"),
311 }
312 }
313
314 #[must_use]
321 #[inline]
322 pub const fn try_from_le_slice(bytes: &[u8]) -> Option<Self> {
323 if bytes.len() > Self::BYTES {
324 return None;
325 }
326
327 if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
328 let mut limbs = [0; LIMBS];
330 let mut i = 0;
331 while i < LIMBS {
332 limbs[i] = u64::from_le_bytes(unsafe { *bytes.as_ptr().add(i * 8).cast() });
333 i += 1;
334 }
335 return Some(Self::from_limbs(limbs));
336 }
337
338 let mut limbs = [0; LIMBS];
339 let mut i = 0;
340 while i < bytes.len() {
341 let (limb, byte) = (i / 8, i % 8);
342 limbs[limb] += (bytes[i] as u64) << (byte * 8);
343 i += 1;
344 }
345 if Self::LIMBS > 0 && limbs[Self::LIMBS - 1] > Self::MASK {
346 return None;
347 }
348 Some(Self::from_limbs(limbs))
349 }
350
351 #[inline]
363 pub fn copy_le_bytes_to(&self, buf: &mut [u8]) -> usize {
364 debug_assert!(
366 buf.len() >= Self::BYTES,
367 "Buffer is too small to hold the bytes of the Uint"
368 );
369
370 #[cfg(target_endian = "little")]
371 buf[..Self::BYTES].copy_from_slice(self.as_le_slice());
372
373 #[cfg(target_endian = "big")]
374 {
375 let chunks = buf[..Self::BYTES].chunks_mut(8);
376
377 self.limbs.iter().zip(chunks).for_each(|(&limb, chunk)| {
378 let le = limb.to_le_bytes();
379 chunk.copy_from_slice(&le[..chunk.len()]);
380 });
381 }
382
383 Self::BYTES
384 }
385
386 #[inline]
398 pub fn checked_copy_le_bytes_to(&self, buf: &mut [u8]) -> Option<usize> {
399 if buf.len() < Self::BYTES {
400 return None;
401 }
402
403 Some(self.copy_le_bytes_to(buf))
404 }
405
406 #[inline]
418 pub fn copy_be_bytes_to(&self, buf: &mut [u8]) -> usize {
419 debug_assert!(
421 buf.len() >= Self::BYTES,
422 "Buffer is too small to hold the bytes of the Uint"
423 );
424
425 let chunks = buf[..Self::BYTES].rchunks_mut(8);
427
428 self.limbs.iter().zip(chunks).for_each(|(&limb, chunk)| {
429 let be = limb.to_be_bytes();
430 let copy_from = 8 - chunk.len();
431 chunk.copy_from_slice(&be[copy_from..]);
432 });
433
434 Self::BYTES
435 }
436
437 #[inline]
449 pub fn checked_copy_be_bytes_to(&self, buf: &mut [u8]) -> Option<usize> {
450 if buf.len() < Self::BYTES {
451 return None;
452 }
453
454 Some(self.copy_be_bytes_to(buf))
455 }
456}
457
458#[inline]
464#[must_use]
465pub const fn nbytes(bits: usize) -> usize {
466 (bits + 7) / 8
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472 use crate::{const_for, nlimbs};
473 use proptest::proptest;
474
475 const N: Uint<128, 2> =
476 Uint::from_limbs([0x7890_1234_5678_9012_u64, 0x1234_5678_9012_3456_u64]);
477 const BE: [u8; 16] = [
478 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90,
479 0x12,
480 ];
481 const LE: [u8; 16] = [
482 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34,
483 0x12,
484 ];
485
486 const K: Uint<72, 2> = Uint::from_limbs([0x3456_7890_1234_5678_u64, 0x12_u64]);
487 const KBE: [u8; 9] = [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78];
488 const KLE: [u8; 9] = [0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12];
489
490 #[test]
491 const fn const_from_to_bytes() {
492 const NL: [u64; 2] = N.limbs;
493 const KL: [u64; 2] = K.limbs;
494 assert!(matches!(Uint::<128, 2>::from_be_bytes(BE).limbs, NL));
495 assert!(matches!(Uint::<128, 2>::from_le_bytes(LE).limbs, NL));
496 assert!(matches!(N.to_be_bytes::<{ BE.len() }>(), BE));
497 assert!(matches!(N.to_le_bytes::<{ LE.len() }>(), LE));
498
499 assert!(matches!(Uint::<72, 2>::from_be_bytes(KBE).limbs, KL));
500 assert!(matches!(Uint::<72, 2>::from_le_bytes(KLE).limbs, KL));
501 assert!(matches!(K.to_be_bytes::<{ KBE.len() }>(), KBE));
502 assert!(matches!(K.to_le_bytes::<{ KLE.len() }>(), KLE));
503
504 assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
505 assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
506 assert!(matches!(
507 Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
508 [1]
509 ));
510 assert!(matches!(
511 Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
512 [0x12, 0x34]
513 ));
514
515 assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
516 assert!(matches!(Uint::<0, 0>::ZERO.to_le_bytes::<0>(), []));
517 assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
518 assert!(matches!(Uint::<1, 1>::ZERO.to_le_bytes::<1>(), [0]));
519 assert!(matches!(
520 Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
521 [1]
522 ));
523 assert!(matches!(
524 Uint::<1, 1>::from_limbs([1]).to_le_bytes::<1>(),
525 [1]
526 ));
527 assert!(matches!(
528 Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
529 [0x12, 0x34]
530 ));
531 assert!(matches!(
532 Uint::<16, 1>::from_limbs([0x1234]).to_le_bytes::<2>(),
533 [0x34, 0x12]
534 ));
535
536 assert!(matches!(
537 Uint::<63, 1>::from_limbs([0x010203]).to_be_bytes::<8>(),
538 [0, 0, 0, 0, 0, 1, 2, 3]
539 ));
540 assert!(matches!(
541 Uint::<63, 1>::from_limbs([0x010203]).to_le_bytes::<8>(),
542 [3, 2, 1, 0, 0, 0, 0, 0]
543 ));
544 }
545
546 #[test]
547 fn test_from_bytes() {
548 assert_eq!(Uint::<0, 0>::from_be_bytes([]), Uint::ZERO);
549 assert_eq!(Uint::<0, 0>::from_le_bytes([]), Uint::ZERO);
550 assert_eq!(
551 Uint::<12, 1>::from_be_bytes([0x01, 0x23]),
552 Uint::from(0x0123)
553 );
554 assert_eq!(
555 Uint::<12, 1>::from_le_bytes([0x23, 0x01]),
556 Uint::from(0x0123)
557 );
558 assert_eq!(
559 Uint::<16, 1>::from_be_bytes([0x12, 0x34]),
560 Uint::from(0x1234)
561 );
562 assert_eq!(
563 Uint::<16, 1>::from_le_bytes([0x34, 0x12]),
564 Uint::from(0x1234)
565 );
566
567 assert_eq!(Uint::from_be_bytes(BE), N);
568 assert_eq!(Uint::from_le_bytes(LE), N);
569 assert_eq!(Uint::from_be_bytes(KBE), K);
570 assert_eq!(Uint::from_le_bytes(KLE), K);
571
572 assert_eq!(Uint::<128, 2>::try_from_be_slice(&BE), Some(N));
573 assert_eq!(
574 Uint::<128, 2>::try_from_be_slice(&[&BE[..], &[0xff][..]].concat()),
575 None
576 );
577 assert_eq!(Uint::<128, 2>::try_from_le_slice(&LE), Some(N));
578 assert_eq!(
579 Uint::<128, 2>::try_from_le_slice(&[&LE[..], &[0xff]].concat()),
580 None
581 );
582 assert_eq!(Uint::<72, 2>::try_from_be_slice(&KBE), Some(K));
583 assert_eq!(
584 Uint::<72, 2>::try_from_be_slice(&[&KBE[..], &[0xff][..]].concat()),
585 None
586 );
587 assert_eq!(Uint::<72, 2>::try_from_le_slice(&KLE), Some(K));
588 assert_eq!(
589 Uint::<72, 2>::try_from_le_slice(&[&KLE[..], &[0xff]].concat()),
590 None
591 );
592 }
593
594 #[test]
595 fn test_to_bytes() {
596 assert_eq!(Uint::<0, 0>::ZERO.to_le_bytes(), [0_u8; 0]);
597 assert_eq!(Uint::<0, 0>::ZERO.to_be_bytes(), [0_u8; 0]);
598 assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_le_bytes(), [0x23, 0x01]);
599 assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_be_bytes(), [0x01, 0x23]);
600 assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_le_bytes(), [0x34, 0x12]);
601 assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_be_bytes(), [0x12, 0x34]);
602 assert_eq!(K.to_be_bytes(), KBE);
603 assert_eq!(K.to_le_bytes(), KLE);
604 }
605
606 #[test]
607 fn test_bytes_roundtrip() {
608 const_for!(BITS in SIZES {
609 const LIMBS: usize = nlimbs(BITS);
610 const BYTES: usize = nbytes(BITS);
611 proptest!(|(value: Uint<BITS, LIMBS>)| {
612 assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes()).unwrap());
613 assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes_trimmed()).unwrap());
614 assert_eq!(value, Uint::try_from_be_slice(&value.to_be_bytes_trimmed_vec()).unwrap());
615 assert_eq!(value, Uint::try_from_le_slice(&value.to_le_bytes_trimmed_vec()).unwrap());
616 assert_eq!(value, Uint::from_be_bytes(value.to_be_bytes::<BYTES>()));
617 assert_eq!(value, Uint::from_le_bytes(value.to_le_bytes::<BYTES>()));
618 });
619 });
620 }
621
622 #[test]
623 fn copy_to() {
624 const_for!(BITS in SIZES {
625 const LIMBS: usize = nlimbs(BITS);
626 const BYTES: usize = nbytes(BITS);
627 proptest!(|(value: Uint<BITS, LIMBS>)|{
628 let mut buf = [0; BYTES];
629 value.copy_le_bytes_to(&mut buf);
630 assert_eq!(buf, value.to_le_bytes::<BYTES>());
631 assert_eq!(value, Uint::try_from_le_slice(&buf).unwrap());
632
633 let mut buf = [0; BYTES];
634 value.copy_be_bytes_to(&mut buf);
635 assert_eq!(buf, value.to_be_bytes::<BYTES>());
636 assert_eq!(value, Uint::try_from_be_slice(&buf).unwrap());
637 });
638 });
639 }
640
641 #[test]
642 fn checked_copy_to() {
643 const_for!(BITS in SIZES {
644 const LIMBS: usize = nlimbs(BITS);
645 const BYTES: usize = nbytes(BITS);
646 proptest!(|(value: Uint<BITS, LIMBS>)|{
647 if BYTES != 0 {
648 let mut buf = [0; BYTES];
649 let too_short = buf.len() - 1;
650
651 assert_eq!(value.checked_copy_le_bytes_to(&mut buf[..too_short]), None);
652 assert_eq!(buf, [0; BYTES], "buffer was modified");
653
654 assert_eq!(value.checked_copy_be_bytes_to(&mut buf[..too_short]), None);
655 assert_eq!(buf, [0; BYTES], "buffer was modified");
656 }
657 });
658 });
659 }
660}