rustywallet_bloom/lib.rs
1//! # rustywallet-bloom
2//!
3//! Fast and memory-efficient Bloom Filter implementation optimized for
4//! large datasets like cryptocurrency address lookups.
5//!
6//! ## Features
7//!
8//! - **Memory efficient**: ~1.2 bytes per item at 1% false positive rate
9//! - **Fast**: Uses FNV-1a hash with double hashing technique
10//! - **No dependencies**: Pure Rust implementation
11//! - **Streaming insert**: Load millions of items efficiently
12//!
13//! ## Example
14//!
15//! ```rust
16//! use rustywallet_bloom::BloomFilter;
17//!
18//! // Create filter for 1 million items with 1% false positive rate
19//! let mut bloom = BloomFilter::new(1_000_000, 0.01);
20//!
21//! bloom.insert("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa");
22//! bloom.insert("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4");
23//!
24//! assert!(bloom.contains("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"));
25//! assert!(!bloom.contains("not_in_filter")); // probably false
26//! ```
27
28mod bloom;
29mod hash;
30
31pub use bloom::BloomFilter;
32
33/// Prelude module for convenient imports
34pub mod prelude {
35 pub use crate::BloomFilter;
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn test_basic_operations() {
44 let mut bloom = BloomFilter::new(1000, 0.01);
45
46 bloom.insert("hello");
47 bloom.insert("world");
48
49 assert!(bloom.contains("hello"));
50 assert!(bloom.contains("world"));
51 }
52
53 #[test]
54 fn test_false_positive_rate() {
55 let items = 10_000usize;
56 let fpr = 0.01;
57 let mut bloom = BloomFilter::new(items, fpr);
58
59 // Insert items
60 for i in 0..items {
61 bloom.insert(&format!("item_{}", i));
62 }
63
64 // Check inserted items - should all be found
65 for i in 0..items {
66 assert!(bloom.contains(&format!("item_{}", i)));
67 }
68
69 // Check non-existent items - count false positives
70 let test_count = 10_000;
71 let mut false_positives = 0;
72 for i in 0..test_count {
73 if bloom.contains(&format!("nonexistent_{}", i)) {
74 false_positives += 1;
75 }
76 }
77
78 let actual_fpr = false_positives as f64 / test_count as f64;
79 // Allow 3x tolerance for statistical variance
80 assert!(actual_fpr < fpr * 3.0,
81 "FPR too high: {} (expected < {})", actual_fpr, fpr * 3.0);
82 }
83
84 #[test]
85 fn test_memory_estimate() {
86 let bloom = BloomFilter::new(1_000_000, 0.01);
87 let bytes = bloom.memory_usage();
88
89 // Should be around 1.2MB for 1M items at 1% FPR
90 assert!(bytes > 1_000_000, "Too small: {} bytes", bytes);
91 assert!(bytes < 2_000_000, "Too large: {} bytes", bytes);
92 }
93}