1use crate::{Error, Result, Word};
13
14const USIZE_BYTES: usize = size_of::<usize>();
15
16#[inline(always)]
19pub const fn words_for(data: &[u8]) -> usize {
20 words_for_len(data.len())
21}
22
23#[inline(always)]
26#[allow(clippy::manual_div_ceil)] pub const fn words_for_len(len: usize) -> usize {
28 (len + 31) / 32
29}
30
31#[inline(always)]
33pub(crate) const fn padded_len(data: &[u8]) -> usize {
34 next_multiple_of_32(data.len())
35}
36
37#[inline(always)]
39pub const fn next_multiple_of_32(n: usize) -> usize {
40 match n % 32 {
41 0 => n,
42 r => n + (32 - r),
43 }
44}
45
46#[inline]
48pub(crate) fn pad_usize(value: usize) -> Word {
49 let mut padded = Word::ZERO;
50 padded[32 - USIZE_BYTES..32].copy_from_slice(&value.to_be_bytes());
51 padded
52}
53
54#[inline]
55pub(crate) fn check_zeroes(data: &[u8]) -> bool {
56 data.iter().all(|b| *b == 0)
57}
58
59#[inline]
60pub(crate) fn as_offset(word: &Word) -> Result<usize> {
61 let (before, data) = word.split_last_chunk::<USIZE_BYTES>().unwrap();
62 if !check_zeroes(before) {
63 return Err(Error::type_check_fail(&word[..], "offset (usize)"));
64 }
65 Ok(usize::from_be_bytes(*data))
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use alloy_primitives::b256;
72
73 #[test]
74 fn test_words_for() {
75 assert_eq!(words_for(&[]), 0);
76 assert_eq!(words_for(&[0; 31]), 1);
77 assert_eq!(words_for(&[0; 32]), 1);
78 assert_eq!(words_for(&[0; 33]), 2);
79 }
80
81 #[test]
82 fn test_pad_u32() {
83 assert_eq!(
85 pad_usize(0),
86 b256!("0x0000000000000000000000000000000000000000000000000000000000000000")
87 );
88 assert_eq!(
89 pad_usize(1),
90 b256!("0x0000000000000000000000000000000000000000000000000000000000000001")
91 );
92 assert_eq!(
93 pad_usize(0x100),
94 b256!("0x0000000000000000000000000000000000000000000000000000000000000100")
95 );
96 assert_eq!(
97 pad_usize(0xffffffff),
98 b256!("0x00000000000000000000000000000000000000000000000000000000ffffffff")
99 );
100 }
101}