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}