highway/
internal.rs

1#[cfg(any(
2    target_arch = "x86_64",
3    target_arch = "aarch64",
4    all(target_family = "wasm", target_feature = "simd128")
5))]
6pub fn unordered_load3(from: &[u8]) -> u64 {
7    if from.is_empty() {
8        return 0;
9    }
10
11    let size_mod4 = from.len() % 4;
12
13    u64::from(from[0])
14        + (u64::from(from[size_mod4 >> 1]) << 8)
15        + (u64::from(from[size_mod4 - 1]) << 16)
16}
17
18pub const PACKET_SIZE: usize = 32;
19
20/// The c layout is needed as we'll be interpretting the buffer as different types and passing it
21/// to simd instructions, so we need to subscribe to the whole "do what C does", else we will
22/// segfault.
23#[repr(C)]
24#[derive(Default, Debug, Clone, Copy)]
25pub struct HashPacket {
26    pub(crate) buf: [u8; PACKET_SIZE],
27    buf_index: usize,
28}
29
30impl HashPacket {
31    #[inline]
32    pub const fn len(&self) -> usize {
33        self.buf_index
34    }
35
36    #[inline]
37    pub const fn is_empty(&self) -> bool {
38        self.buf_index == 0
39    }
40
41    #[inline]
42    pub fn as_slice(&self) -> &[u8] {
43        debug_assert!(self.buf_index <= self.buf.len(), "buf index too long");
44        self.buf.get(..self.buf_index).unwrap_or(&self.buf)
45    }
46
47    #[inline]
48    pub const fn inner(&self) -> &[u8; PACKET_SIZE] {
49        &self.buf
50    }
51
52    #[inline]
53    pub fn fill<'a>(&mut self, data: &'a [u8]) -> Option<&'a [u8]> {
54        let dest = self.buf.get_mut(self.buf_index..).unwrap_or_default();
55        if dest.len() > data.len() {
56            dest[..data.len()].copy_from_slice(data);
57            self.buf_index += data.len();
58            None
59        } else {
60            let (head, tail) = data.split_at(dest.len());
61            dest.copy_from_slice(head);
62            self.buf_index = PACKET_SIZE;
63            Some(tail)
64        }
65    }
66
67    #[inline]
68    pub fn set_to(&mut self, data: &[u8]) {
69        debug_assert!(
70            data.len() < PACKET_SIZE,
71            "data large enough to process packet"
72        );
73        self.buf_index = data.len();
74        if !data.is_empty() {
75            self.buf[..data.len()].copy_from_slice(data);
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_hash_packet() {
86        let mut packet: HashPacket = Default::default();
87        for i in 0..31 {
88            assert_eq!(&vec![0; i as usize][..], packet.as_slice());
89            if let Some(_) = packet.fill(&[0]) {
90                assert!(false);
91            }
92
93            assert_eq!(i + 1, packet.len() as u8);
94            assert_eq!(&vec![0; (i + 1) as usize][..], packet.as_slice());
95        }
96    }
97
98    #[test]
99    fn test_hash_cusp_full_packet() {
100        let mut packet: HashPacket = Default::default();
101        assert_eq!(Some(&[][..]), packet.fill(&[0; 32]));
102        assert_eq!(32, packet.len());
103    }
104
105    #[test]
106    fn test_hash_packet_set_to() {
107        let mut packet: HashPacket = Default::default();
108        for i in 0..31 {
109            let d = vec![0; i as usize];
110            packet.set_to(&d[..]);
111            assert_eq!(&d[..], packet.as_slice());
112            assert_eq!(d.len(), packet.len());
113        }
114    }
115}