Coverage Report

Created: 2026-10-28 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/block-buffer-0.12.1/src/sealed.rs
Line
Count
Source
1
use hybrid_array::{
2
    sizes::{U0, U1, U256},
3
    typenum::{IsLess, NonZero, True, Unsigned},
4
};
5
6
use super::{Array, ArraySize};
7
use core::{mem::MaybeUninit, ptr};
8
9
type Block<N> = MaybeUninit<Array<u8, N>>;
10
11
/// Sealed trait for buffer kinds.
12
pub trait Sealed {
13
    #[cfg(not(feature = "zeroize"))]
14
    type Pos: Default + Clone;
15
    #[cfg(feature = "zeroize")]
16
    type Pos: Default + Clone + zeroize::Zeroize;
17
18
    type Overhead: ArraySize;
19
20
    const NAME: &'static str;
21
22
    fn get_pos<N: ArraySize>(buf: &Block<N>, pos: &Self::Pos) -> usize;
23
24
    fn set_pos<N: ArraySize>(buf: &mut Block<N>, pos: &mut Self::Pos, val: usize);
25
26
    /// Invariant guaranteed by a buffer kind, i.e. with correct
27
    /// buffer code this function always returns true.
28
    fn invariant(pos: usize, block_size: usize) -> bool;
29
30
    /// Split input data into slice of blocks and tail.
31
    fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]);
32
}
33
34
impl Sealed for super::Eager {
35
    type Pos = ();
36
    type Overhead = U0;
37
    const NAME: &'static str = "BlockBuffer<Eager>";
38
39
0
    fn get_pos<N: ArraySize>(buf: &Block<N>, _pos: &Self::Pos) -> usize {
40
        // SAFETY: last byte in `buf` for eager hashes is always properly initialized
41
0
        let pos = unsafe {
42
0
            let buf_ptr = buf.as_ptr().cast::<u8>();
43
0
            let last_byte_ptr = buf_ptr.add(N::USIZE - 1);
44
0
            ptr::read(last_byte_ptr)
45
        };
46
0
        pos as usize
47
0
    }
48
49
    #[allow(clippy::cast_possible_truncation)]
50
0
    fn set_pos<N: ArraySize>(buf: &mut Block<N>, _pos: &mut Self::Pos, val: usize) {
51
0
        debug_assert!(u8::try_from(val).is_ok());
52
        // SAFETY: we write to the last byte of `buf` which is always safe
53
0
        unsafe {
54
0
            let buf_ptr = buf.as_mut_ptr().cast::<u8>();
55
0
            let last_byte_ptr = buf_ptr.add(N::USIZE - 1);
56
0
            ptr::write(last_byte_ptr, val as u8);
57
0
        }
58
0
    }
59
60
    #[inline(always)]
61
0
    fn invariant(pos: usize, block_size: usize) -> bool {
62
0
        pos < block_size
63
0
    }
64
65
    #[inline(always)]
66
0
    fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]) {
67
0
        Array::slice_as_chunks(data)
68
0
    }
69
}
70
71
impl Sealed for super::Lazy {
72
    type Pos = u8;
73
    type Overhead = U1;
74
    const NAME: &'static str = "BlockBuffer<Lazy>";
75
76
    fn get_pos<N: ArraySize>(_buf_val: &Block<N>, pos: &Self::Pos) -> usize {
77
        *pos as usize
78
    }
79
80
    #[allow(clippy::cast_possible_truncation)]
81
    fn set_pos<N: ArraySize>(_: &mut Block<N>, pos: &mut Self::Pos, val: usize) {
82
        debug_assert!(u8::try_from(val).is_ok());
83
        *pos = val as u8;
84
    }
85
86
    #[inline(always)]
87
    fn invariant(pos: usize, block_size: usize) -> bool {
88
        pos <= block_size
89
    }
90
91
    #[inline(always)]
92
    fn split_blocks<N: ArraySize>(data: &[u8]) -> (&[Array<u8, N>], &[u8]) {
93
        let (blocks, tail) = Array::slice_as_chunks(data);
94
        if data.is_empty() || !tail.is_empty() {
95
            (blocks, tail)
96
        } else {
97
            let (tail, blocks) = blocks.split_last().expect("`blocks` can not be empty");
98
            (blocks, tail)
99
        }
100
    }
101
}
102
103
/// Sealed trait implemented for sizes from `U1` to `U255`.
104
pub trait BlockSizes {}
105
106
impl<T: Unsigned> BlockSizes for T where Self: IsLess<U256, Output = True> + NonZero {}