/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 {} |