1use crate::Word;
2
3pub const WORD_SIZE: usize = core::mem::size_of::<Word>();
5
6pub const fn padded_len(bytes: &[u8]) -> Option<usize> {
9 padded_len_usize(bytes.len())
10}
11
12#[allow(clippy::arithmetic_side_effects)] pub const fn padded_len_usize(len: usize) -> Option<usize> {
16 let modulo = len % WORD_SIZE;
17 if modulo == 0 {
18 Some(len)
19 } else {
20 let padding = WORD_SIZE - modulo;
21 len.checked_add(padding)
22 }
23}
24
25#[allow(clippy::arithmetic_side_effects)] pub const fn padded_len_word(len: Word) -> Option<Word> {
29 let modulo = len % WORD_SIZE as Word;
30 if modulo == 0 {
31 Some(len)
32 } else {
33 let padding = WORD_SIZE as Word - modulo;
34 len.checked_add(padding)
35 }
36}
37
38#[cfg(feature = "unsafe")]
39#[allow(unsafe_code)]
40pub unsafe fn from_slice_unchecked<const N: usize>(buf: &[u8]) -> [u8; N] {
47 let ptr = buf.as_ptr() as *const [u8; N];
48
49 *ptr
52}
53
54#[test]
55#[allow(clippy::erasing_op)]
56#[allow(clippy::identity_op)]
57fn padded_len_returns_multiple_of_word_len() {
58 assert_eq!(Some(WORD_SIZE * 0), padded_len(&[]));
59 assert_eq!(Some(WORD_SIZE * 1), padded_len(&[0]));
60 assert_eq!(Some(WORD_SIZE * 1), padded_len(&[0; WORD_SIZE]));
61 assert_eq!(Some(WORD_SIZE * 2), padded_len(&[0; WORD_SIZE + 1]));
62 assert_eq!(Some(WORD_SIZE * 2), padded_len(&[0; WORD_SIZE * 2]));
63}
64
65#[test]
66fn padded_len_usize_returns_multiple_of_word_len() {
67 assert_eq!(padded_len_usize(0), Some(0));
68 assert_eq!(padded_len_usize(1), Some(8));
69 assert_eq!(padded_len_usize(2), Some(8));
70 assert_eq!(padded_len_usize(7), Some(8));
71 assert_eq!(padded_len_usize(8), Some(8));
72 assert_eq!(padded_len_usize(9), Some(16));
73}
74
75#[test]
76fn padded_len_usize_handles_overflow() {
77 for i in 0..7 {
78 assert_eq!(padded_len_usize(usize::MAX - i), None);
79 }
80 assert_eq!(padded_len_usize(usize::MAX - 7), Some(usize::MAX - 7));
81}