1use crate::Uint;
2use core::slice;
3
4#[cfg(feature = "alloc")]
5#[allow(unused_imports)]
6use alloc::{borrow::Cow, vec::Vec};
7
8impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
10 pub const BYTES: usize = BITS.div_ceil(8);
13
14 #[cfg(target_endian = "little")]
21 #[must_use]
22 #[inline(always)]
23 pub const fn as_le_slice(&self) -> &[u8] {
24 unsafe { slice::from_raw_parts(self.limbs.as_ptr().cast(), Self::BYTES) }
25 }
26
27 #[cfg(target_endian = "little")]
37 #[must_use]
38 #[inline(always)]
39 pub const unsafe fn as_le_slice_mut(&mut self) -> &mut [u8] {
40 unsafe { slice::from_raw_parts_mut(self.limbs.as_mut_ptr().cast(), Self::BYTES) }
41 }
42
43 #[cfg(feature = "alloc")]
47 #[must_use]
48 #[inline]
49 #[cfg_attr(target_endian = "little", allow(clippy::missing_const_for_fn))] pub fn as_le_bytes(&self) -> Cow<'_, [u8]> {
51 #[cfg(target_endian = "little")]
53 return Cow::Borrowed(self.as_le_slice());
54
55 #[cfg(target_endian = "big")]
57 return Cow::Owned({
58 let mut limbs = self.limbs;
59 for limb in &mut limbs {
60 *limb = limb.swap_bytes();
61 }
62 unsafe { slice::from_raw_parts(limbs.as_ptr().cast(), Self::BYTES).to_vec() }
63 });
64 }
65
66 #[cfg(feature = "alloc")]
71 #[must_use]
72 #[inline]
73 pub fn as_le_bytes_trimmed(&self) -> Cow<'_, [u8]> {
74 match self.as_le_bytes() {
75 Cow::Borrowed(slice) => Cow::Borrowed(crate::utils::trim_end_slice(slice, &0)),
76 Cow::Owned(mut vec) => {
77 crate::utils::trim_end_vec(&mut vec, &0);
78 Cow::Owned(vec)
79 }
80 }
81 }
82
83 #[inline]
94 #[must_use]
95 pub const fn to_le_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
96 const { Self::assert_bytes(BYTES) }
97
98 #[cfg(target_endian = "little")]
100 return unsafe { *self.as_le_slice().as_ptr().cast() };
102
103 #[cfg(target_endian = "big")]
105 {
106 let mut limbs = self.limbs;
107 let mut i = 0;
108 while i < LIMBS {
109 limbs[i] = limbs[i].to_le();
110 i += 1;
111 }
112 unsafe { *limbs.as_ptr().cast() }
114 }
115 }
116
117 #[cfg(feature = "alloc")]
123 #[must_use]
124 #[inline]
125 pub fn to_le_bytes_vec(&self) -> Vec<u8> {
126 self.as_le_bytes().into_owned()
127 }
128
129 #[cfg(feature = "alloc")]
132 #[must_use]
133 #[inline]
134 pub fn to_le_bytes_trimmed_vec(&self) -> Vec<u8> {
135 self.as_le_bytes_trimmed().into_owned()
136 }
137
138 #[must_use]
149 #[inline]
150 pub const fn to_be_bytes<const BYTES: usize>(&self) -> [u8; BYTES] {
151 let mut bytes = self.to_le_bytes::<BYTES>();
152
153 let len = bytes.len();
155 let half_len = len / 2;
156 let mut i = 0;
157 while i < half_len {
158 let tmp = bytes[i];
159 bytes[i] = bytes[len - 1 - i];
160 bytes[len - 1 - i] = tmp;
161 i += 1;
162 }
163
164 bytes
165 }
166
167 #[cfg(feature = "alloc")]
173 #[must_use]
174 #[inline]
175 pub fn to_be_bytes_vec(&self) -> Vec<u8> {
176 let mut bytes = self.to_le_bytes_vec();
177 bytes.reverse();
178 bytes
179 }
180
181 #[cfg(feature = "alloc")]
184 #[must_use]
185 #[inline]
186 pub fn to_be_bytes_trimmed_vec(&self) -> Vec<u8> {
187 let mut bytes = self.to_le_bytes_trimmed_vec();
188 bytes.reverse();
189 bytes
190 }
191
192 #[must_use]
205 #[track_caller]
206 #[inline]
207 pub const fn from_be_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
208 const { Self::assert_bytes(BYTES) }
209 Self::from_be_slice(&bytes)
210 }
211
212 #[must_use]
221 #[track_caller]
222 #[inline]
223 pub const fn from_be_slice(bytes: &[u8]) -> Self {
224 match Self::try_from_be_slice(bytes) {
225 Some(value) => value,
226 None => panic!("Value too large for Uint"),
227 }
228 }
229
230 #[must_use]
237 #[inline]
238 pub const fn try_from_be_slice(bytes: &[u8]) -> Option<Self> {
239 if bytes.len() > Self::BYTES {
240 return None;
241 }
242
243 if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
244 let mut limbs = [0; LIMBS];
246 let end = bytes.as_ptr_range().end;
247 let mut i = 0;
248 while i < LIMBS {
249 limbs[i] = u64::from_be_bytes(unsafe { *end.sub((i + 1) * 8).cast() });
250 i += 1;
251 }
252 return Some(Self::from_limbs(limbs));
253 }
254
255 let mut limbs = [0; LIMBS];
256 let mut i = 0;
257 let mut c = bytes.len();
258 while i < bytes.len() {
259 c -= 1;
260 let (limb, byte) = (i / 8, i % 8);
261 limbs[limb] += (bytes[c] as u64) << (byte * 8);
262 i += 1;
263 }
264 if LIMBS > 0 && limbs[LIMBS - 1] > Self::MASK {
265 return None;
266 }
267 Some(Self::from_limbs(limbs))
268 }
269
270 #[must_use]
283 #[track_caller]
284 #[inline]
285 pub const fn from_le_bytes<const BYTES: usize>(bytes: [u8; BYTES]) -> Self {
286 const { Self::assert_bytes(BYTES) }
287 Self::from_le_slice(&bytes)
288 }
289
290 #[must_use]
299 #[track_caller]
300 #[inline]
301 pub const fn from_le_slice(bytes: &[u8]) -> Self {
302 match Self::try_from_le_slice(bytes) {
303 Some(value) => value,
304 None => panic!("Value too large for Uint"),
305 }
306 }
307
308 #[must_use]
315 #[inline]
316 pub const fn try_from_le_slice(bytes: &[u8]) -> Option<Self> {
317 if bytes.len() > Self::BYTES {
318 return None;
319 }
320
321 if Self::BYTES % 8 == 0 && bytes.len() == Self::BYTES {
322 let mut limbs = [0; LIMBS];
324 let mut i = 0;
325 while i < LIMBS {
326 limbs[i] = u64::from_le_bytes(unsafe { *bytes.as_ptr().add(i * 8).cast() });
327 i += 1;
328 }
329 return Some(Self::from_limbs(limbs));
330 }
331
332 let mut limbs = [0; LIMBS];
333 let mut i = 0;
334 while i < bytes.len() {
335 let (limb, byte) = (i / 8, i % 8);
336 limbs[limb] += (bytes[i] as u64) << (byte * 8);
337 i += 1;
338 }
339 if LIMBS > 0 && limbs[LIMBS - 1] > Self::MASK {
340 return None;
341 }
342 Some(Self::from_limbs(limbs))
343 }
344
345 #[inline]
357 pub fn copy_le_bytes_to(&self, buf: &mut [u8]) -> usize {
358 debug_assert!(
360 buf.len() >= Self::BYTES,
361 "Buffer is too small to hold the bytes of the Uint"
362 );
363
364 #[cfg(target_endian = "little")]
365 buf[..Self::BYTES].copy_from_slice(self.as_le_slice());
366
367 #[cfg(target_endian = "big")]
368 {
369 let chunks = buf[..Self::BYTES].chunks_mut(8);
370
371 self.limbs.iter().zip(chunks).for_each(|(&limb, chunk)| {
372 let le = limb.to_le_bytes();
373 chunk.copy_from_slice(&le[..chunk.len()]);
374 });
375 }
376
377 Self::BYTES
378 }
379
380 #[inline]
392 pub fn checked_copy_le_bytes_to(&self, buf: &mut [u8]) -> Option<usize> {
393 if buf.len() < Self::BYTES {
394 return None;
395 }
396
397 Some(self.copy_le_bytes_to(buf))
398 }
399
400 #[inline]
412 pub fn copy_be_bytes_to(&self, buf: &mut [u8]) -> usize {
413 debug_assert!(
415 buf.len() >= Self::BYTES,
416 "Buffer is too small to hold the bytes of the Uint"
417 );
418
419 let chunks = buf[..Self::BYTES].rchunks_mut(8);
421
422 self.limbs.iter().zip(chunks).for_each(|(&limb, chunk)| {
423 let be = limb.to_be_bytes();
424 let copy_from = 8 - chunk.len();
425 chunk.copy_from_slice(&be[copy_from..]);
426 });
427
428 Self::BYTES
429 }
430
431 #[inline]
443 pub fn checked_copy_be_bytes_to(&self, buf: &mut [u8]) -> Option<usize> {
444 if buf.len() < Self::BYTES {
445 return None;
446 }
447
448 Some(self.copy_be_bytes_to(buf))
449 }
450
451 #[track_caller]
452 const fn assert_bytes(bytes: usize) {
453 assert!(bytes == Self::BYTES, "BYTES must be equal to Self::BYTES");
454 }
455}
456
457#[inline]
463#[must_use]
464pub const fn nbytes(bits: usize) -> usize {
465 bits.div_ceil(8)
466}
467
468#[cfg(test)]
469mod tests {
470 use super::*;
471 use crate::{const_for, nlimbs};
472 use proptest::proptest;
473
474 const N: Uint<128, 2> =
475 Uint::from_limbs([0x7890_1234_5678_9012_u64, 0x1234_5678_9012_3456_u64]);
476 const BE: [u8; 16] = [
477 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90,
478 0x12,
479 ];
480 const LE: [u8; 16] = [
481 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34,
482 0x12,
483 ];
484
485 const K: Uint<72, 2> = Uint::from_limbs([0x3456_7890_1234_5678_u64, 0x12_u64]);
486 const KBE: [u8; 9] = [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78];
487 const KLE: [u8; 9] = [0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12];
488
489 #[test]
490 const fn const_from_to_bytes() {
491 const NL: [u64; 2] = N.limbs;
492 const KL: [u64; 2] = K.limbs;
493 assert!(matches!(Uint::<128, 2>::from_be_bytes(BE).limbs, NL));
494 assert!(matches!(Uint::<128, 2>::from_le_bytes(LE).limbs, NL));
495 assert!(matches!(N.to_be_bytes::<{ BE.len() }>(), BE));
496 assert!(matches!(N.to_le_bytes::<{ LE.len() }>(), LE));
497
498 assert!(matches!(Uint::<72, 2>::from_be_bytes(KBE).limbs, KL));
499 assert!(matches!(Uint::<72, 2>::from_le_bytes(KLE).limbs, KL));
500 assert!(matches!(K.to_be_bytes::<{ KBE.len() }>(), KBE));
501 assert!(matches!(K.to_le_bytes::<{ KLE.len() }>(), KLE));
502
503 assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
504 assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
505 assert!(matches!(
506 Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
507 [1]
508 ));
509 assert!(matches!(
510 Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
511 [0x12, 0x34]
512 ));
513
514 assert!(matches!(Uint::<0, 0>::ZERO.to_be_bytes::<0>(), []));
515 assert!(matches!(Uint::<0, 0>::ZERO.to_le_bytes::<0>(), []));
516 assert!(matches!(Uint::<1, 1>::ZERO.to_be_bytes::<1>(), [0]));
517 assert!(matches!(Uint::<1, 1>::ZERO.to_le_bytes::<1>(), [0]));
518 assert!(matches!(
519 Uint::<1, 1>::from_limbs([1]).to_be_bytes::<1>(),
520 [1]
521 ));
522 assert!(matches!(
523 Uint::<1, 1>::from_limbs([1]).to_le_bytes::<1>(),
524 [1]
525 ));
526 assert!(matches!(
527 Uint::<16, 1>::from_limbs([0x1234]).to_be_bytes::<2>(),
528 [0x12, 0x34]
529 ));
530 assert!(matches!(
531 Uint::<16, 1>::from_limbs([0x1234]).to_le_bytes::<2>(),
532 [0x34, 0x12]
533 ));
534
535 assert!(matches!(
536 Uint::<63, 1>::from_limbs([0x010203]).to_be_bytes::<8>(),
537 [0, 0, 0, 0, 0, 1, 2, 3]
538 ));
539 assert!(matches!(
540 Uint::<63, 1>::from_limbs([0x010203]).to_le_bytes::<8>(),
541 [3, 2, 1, 0, 0, 0, 0, 0]
542 ));
543 }
544
545 #[test]
546 fn test_from_bytes() {
547 assert_eq!(Uint::<0, 0>::from_be_bytes([]), Uint::ZERO);
548 assert_eq!(Uint::<0, 0>::from_le_bytes([]), Uint::ZERO);
549 assert_eq!(
550 Uint::<12, 1>::from_be_bytes([0x01, 0x23]),
551 Uint::from(0x0123)
552 );
553 assert_eq!(
554 Uint::<12, 1>::from_le_bytes([0x23, 0x01]),
555 Uint::from(0x0123)
556 );
557 assert_eq!(
558 Uint::<16, 1>::from_be_bytes([0x12, 0x34]),
559 Uint::from(0x1234)
560 );
561 assert_eq!(
562 Uint::<16, 1>::from_le_bytes([0x34, 0x12]),
563 Uint::from(0x1234)
564 );
565
566 assert_eq!(Uint::from_be_bytes(BE), N);
567 assert_eq!(Uint::from_le_bytes(LE), N);
568 assert_eq!(Uint::from_be_bytes(KBE), K);
569 assert_eq!(Uint::from_le_bytes(KLE), K);
570
571 assert_eq!(Uint::<128, 2>::try_from_be_slice(&BE), Some(N));
572 assert_eq!(
573 Uint::<128, 2>::try_from_be_slice(&[&BE[..], &[0xff][..]].concat()),
574 None
575 );
576 assert_eq!(Uint::<128, 2>::try_from_le_slice(&LE), Some(N));
577 assert_eq!(
578 Uint::<128, 2>::try_from_le_slice(&[&LE[..], &[0xff]].concat()),
579 None
580 );
581 assert_eq!(Uint::<72, 2>::try_from_be_slice(&KBE), Some(K));
582 assert_eq!(
583 Uint::<72, 2>::try_from_be_slice(&[&KBE[..], &[0xff][..]].concat()),
584 None
585 );
586 assert_eq!(Uint::<72, 2>::try_from_le_slice(&KLE), Some(K));
587 assert_eq!(
588 Uint::<72, 2>::try_from_le_slice(&[&KLE[..], &[0xff]].concat()),
589 None
590 );
591 }
592
593 #[test]
594 fn test_to_bytes() {
595 assert_eq!(Uint::<0, 0>::ZERO.to_le_bytes(), [0_u8; 0]);
596 assert_eq!(Uint::<0, 0>::ZERO.to_be_bytes(), [0_u8; 0]);
597 assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_le_bytes(), [0x23, 0x01]);
598 assert_eq!(Uint::<12, 1>::from(0x0123_u64).to_be_bytes(), [0x01, 0x23]);
599 assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_le_bytes(), [0x34, 0x12]);
600 assert_eq!(Uint::<16, 1>::from(0x1234_u64).to_be_bytes(), [0x12, 0x34]);
601 assert_eq!(K.to_be_bytes(), KBE);
602 assert_eq!(K.to_le_bytes(), KLE);
603 }
604
605 #[test]
606 fn test_bytes_roundtrip() {
607 const_for!(BITS in SIZES {
608 const LIMBS: usize = nlimbs(BITS);
609 const BYTES: usize = nbytes(BITS);
610 proptest!(|(value: Uint<BITS, LIMBS>)| {
611 assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes()).unwrap());
612 assert_eq!(value, Uint::try_from_le_slice(&value.as_le_bytes_trimmed()).unwrap());
613 assert_eq!(value, Uint::try_from_be_slice(&value.to_be_bytes_trimmed_vec()).unwrap());
614 assert_eq!(value, Uint::try_from_le_slice(&value.to_le_bytes_trimmed_vec()).unwrap());
615 assert_eq!(value, Uint::from_be_bytes(value.to_be_bytes::<BYTES>()));
616 assert_eq!(value, Uint::from_le_bytes(value.to_le_bytes::<BYTES>()));
617 });
618 });
619 }
620
621 #[test]
622 fn copy_to() {
623 const_for!(BITS in SIZES {
624 const LIMBS: usize = nlimbs(BITS);
625 const BYTES: usize = nbytes(BITS);
626 proptest!(|(value: Uint<BITS, LIMBS>)|{
627 let mut buf = [0; BYTES];
628 value.copy_le_bytes_to(&mut buf);
629 assert_eq!(buf, value.to_le_bytes::<BYTES>());
630 assert_eq!(value, Uint::try_from_le_slice(&buf).unwrap());
631
632 let mut buf = [0; BYTES];
633 value.copy_be_bytes_to(&mut buf);
634 assert_eq!(buf, value.to_be_bytes::<BYTES>());
635 assert_eq!(value, Uint::try_from_be_slice(&buf).unwrap());
636 });
637 });
638 }
639
640 #[test]
641 fn checked_copy_to() {
642 const_for!(BITS in SIZES {
643 const LIMBS: usize = nlimbs(BITS);
644 const BYTES: usize = nbytes(BITS);
645 proptest!(|(value: Uint<BITS, LIMBS>)|{
646 if BYTES != 0 {
647 let mut buf = [0; BYTES];
648 let too_short = buf.len() - 1;
649
650 assert_eq!(value.checked_copy_le_bytes_to(&mut buf[..too_short]), None);
651 assert_eq!(buf, [0; BYTES], "buffer was modified");
652
653 assert_eq!(value.checked_copy_be_bytes_to(&mut buf[..too_short]), None);
654 assert_eq!(buf, [0; BYTES], "buffer was modified");
655 }
656 });
657 });
658 }
659}