use core::hash::Hasher; use siphasher::sip128::{Hash128, Hasher128}; pub struct PortableSipHasher { inner: H, } impl PortableSipHasher { pub fn new(inner: H) -> Self { Self { inner } } } impl Hasher for PortableSipHasher { fn finish(&self) -> u64 { self.inner.finish() } fn write(&mut self, bytes: &[u8]) { self.inner.write(bytes) } fn write_u8(&mut self, i: u8) { self.inner.write_u8(i) } // `SipHasher` invokes `to_le` on integers before encoding them, treating them as byte arrays // rather than values, which is not the right interpretation for us; fix that by flipping // endianness twice. fn write_u16(&mut self, i: u16) { self.inner.write_u16(i.to_le()); } fn write_u32(&mut self, i: u32) { self.inner.write_u32(i.to_le()); } fn write_u64(&mut self, i: u64) { self.inner.write_u64(i.to_le()); } fn write_u128(&mut self, i: u128) { self.inner.write_u128(i.to_le()); } fn write_usize(&mut self, i: usize) { self.inner.write_u64((i as u64).to_le()); } // The default `write_isize` implementation casts to `usize` first, so we end up with // `i as usize as u64`, which is different on 32-bit and 64-bit architectures: // // 32-bit: `-1` -> `2^32 - 1` -> `2^32 - 1` // 64-bit: `-1` -> `2^64 - 1` -> `2^64 - 1` fn write_isize(&mut self, i: isize) { self.inner.write_u64((i as u64).to_le()); } // Fixed-size signed integers correctly forward to unsigned implementations. } impl Hasher128 for PortableSipHasher { fn finish128(&self) -> Hash128 { self.inner.finish128() } }