rusty_files/storage/
bloom.rs1use parking_lot::RwLock;
2use probabilistic_collections::bloom::BloomFilter;
3
4pub struct FileBloomFilter {
5 filter: RwLock<BloomFilter<String>>,
6 capacity: usize,
7 error_rate: f64,
8}
9
10impl FileBloomFilter {
11 pub fn new(capacity: usize, error_rate: f64) -> Self {
12 let filter = BloomFilter::new(capacity, error_rate);
13 Self {
14 filter: RwLock::new(filter),
15 capacity,
16 error_rate,
17 }
18 }
19
20 pub fn insert<S: AsRef<str>>(&self, item: S) {
21 let mut filter = self.filter.write();
22 filter.insert(&item.as_ref().to_string());
23 }
24
25 pub fn contains<S: AsRef<str>>(&self, item: S) -> bool {
26 let filter = self.filter.read();
27 filter.contains(&item.as_ref().to_string())
28 }
29
30 pub fn clear(&self) {
31 let mut filter = self.filter.write();
32 *filter = BloomFilter::new(self.capacity, self.error_rate);
33 }
34
35 pub fn len(&self) -> usize {
36 self.filter.read().len()
37 }
38
39 pub fn is_empty(&self) -> bool {
40 self.filter.read().is_empty()
41 }
42}
43
44impl Default for FileBloomFilter {
45 fn default() -> Self {
46 Self::new(10_000_000, 0.0001)
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_bloom_filter_basic() {
56 let bloom = FileBloomFilter::new(1000, 0.01);
57
58 bloom.insert("test.txt");
59 bloom.insert("another.rs");
60
61 assert!(bloom.contains("test.txt"));
62 assert!(bloom.contains("another.rs"));
63 }
64
65 #[test]
66 fn test_bloom_filter_negative_lookup() {
67 let bloom = FileBloomFilter::new(1000, 0.01);
68
69 bloom.insert("exists.txt");
70
71 assert!(!bloom.contains("doesnotexist.txt"));
72 }
73
74 #[test]
75 fn test_bloom_filter_clear() {
76 let bloom = FileBloomFilter::new(1000, 0.01);
77
78 bloom.insert("test.txt");
79 assert!(bloom.contains("test.txt"));
80
81 bloom.clear();
82 assert!(!bloom.contains("test.txt"));
83 }
84}