2个版本
0.1.1 | 2023年12月27日 |
---|---|
0.1.0 | 2023年12月27日 |
#1959 在 算法
14KB
143 行
bufhash
Rust的缓冲哈希实用工具。
概述
请参阅文档了解该包的详细信息以及如何编写缓冲哈希器。
lib.rs
:
缓冲哈希功能。
此crate提供编写利用各种方式缓冲的哈希器的功能。最值得注意的是,它提供了“分区”哈希器的概念,这是一种在哈希前将数据分成固定大小块的一类哈希器。此crate及其所有功能均使用100% Rust编写,并旨在与现有的Rust特质集成,例如std::hash::Hasher
。
概述
分区哈希器是一类在固定大小数据块上工作的哈希器(例如,MurmurHash3)。从根本上说,在partitioned
命名空间下提供的设施旨在解决在增量哈希时分区数据的问题。在底层,分区哈希器跟踪将分块流输入到适当大小,并在内部缓冲区中存储多余数据,以便在下一次write()
调用中使用。
例如,考虑以下调用虚构的哈希算法的示例,该算法以每次4字节的大小工作
let mut hasher = MyHasher::default();
hasher.write(b"Hi,");
hasher.write(b"there ");
hasher.write(b"world!");
println!("Result: 0x{:X}", hasher.finish());
在这个例子中,要哈希的数据通过三次不同的write()
调用逐渐提供给哈希器。回想一下我们的哈希器在4字节块上工作,字节字符串字面量中的前三个字符(即b"Hi,"
)不足以填充一个完整的要哈希的数据块。然而,我们也不希望将这些三个字符视为数据流的结尾,因为可能还有更多数据(事实上,在我们的例子中确实如此。借助Rust标准库提供的设施,由实现者负责跟踪这些各种边缘情况并确保哈希器适当地工作。
为了简化符合上述描述的哈希器的实现,分区哈希器在幕后处理必要的会计工作,使实现者只需关注哈希的固定大小接口。
实现分区哈希器
让我们看看核心的bufhash::partitioned::Hasher
特质,以了解编写分区哈希器与编写std::hash::Hasher
实现有何不同。
pub trait Hasher<const S: usize> {
fn write(&mut self, bytes: &[u8; S]);
fn finish(&self, bytes: &[u8]) -> u64;
}
您会发现有两个与std::hash::Hash
提供的方法相同,但有几个细微(但重要!)的差异。
- 该特质有一个泛型参数
const S: usize
,它定义了每个分区的字节数。在我们的示例中,我们将此设置为四个(4)字节。 write()
方法接受一个固定大小的字节数组(&[u8; S]
)。参数bytes
保证正好是泛型参数的大小,这使得实现者可以省去大小检查。finish()
方法也提供了一个作为字节切片的bytes
参数。这些参数是需要处理才能完成哈希器的内部缓冲区中剩余的字节:保证其大小小于泛型参数。
作为一个例子,让我们实现一个分区哈希器,该哈希器(a)将字节流解释为需要相加的little-endian u64
,然后在调用finish()
时将结果左移缓冲区中剩余的字节数(不是一个特别好的哈希算法,但可以用于我们的演示目的)。
#[derive(Debug, Default)]
pub struct Simple(u64);
impl bufhash::partitioned::Hasher<8> for Simple {
fn write(&mut self, bytes: &[u8; 8]) {
let data = u64::from_le_bytes(*bytes);
self.0 = self.0.wrapping_add(data);
}
fn finish(&self, bytes: &[u8]) -> u64 {
self.0 << bytes.len()
}
}
如您所见,这比自行处理会计工作要简单得多。
要使用此新实现与std::hash::Hasher
接口,您可以使用PartitionedHasher
适配器,如下所示
use std::hash::Hasher as _;
#
let mut hasher = bufhash::PartitionedHasher::new(Simple::default());
hasher.write(b"Hello, world!");
println!("Result: {:#X}", hasher.finish());