deterministic_bloom_wasm/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![warn(missing_debug_implementations, missing_docs, rust_2018_idioms)]
3#![deny(unreachable_pub, private_in_public)]
4
5//! Wasm/JS bindings for [BloomFilter]
6
7use derive_more::{From, Into};
8use deterministic_bloom::const_size::BloomFilter;
9use std::boxed::Box;
10use wasm_bindgen::prelude::{wasm_bindgen, JsError};
11
12//------------------------------------------------------------------------------
13// Utilities
14//------------------------------------------------------------------------------
15
16/// Panic hook lets us get better error messages if our Rust code ever panics.
17///
18/// For more details see
19/// <https://github.com/rustwasm/console_error_panic_hook#readme>
20#[wasm_bindgen(js_name = "setPanicHook")]
21pub fn set_panic_hook() {
22    #[cfg(feature = "console_error_panic_hook")]
23    console_error_panic_hook::set_once();
24}
25
26//------------------------------------------------------------------------------
27// Macros
28//------------------------------------------------------------------------------
29
30/// Generate a monomorphic [BloomFilter] newtypes.
31macro_rules! gen_bloom {
32    ($name: ident, $n: expr, $k: expr) => {
33        #[doc = concat!("A monomorphic wrapper for [BloomFilter]`s with a size of ", stringify!($n), " bytes and ", stringify!($k), " hash functions.")]
34        #[wasm_bindgen]
35        #[derive(Debug, Default, From, Into)]
36        pub struct $name {
37            pub(crate) boxed: Box<BloomFilter<$n, $k>>,
38        }
39
40        #[wasm_bindgen]
41        impl $name {
42            #[doc = concat!("Initialize a blank [", stringify!($name), "] (i.e. contains no elements).")]
43            ///
44            /// # Examples
45            ///
46            /// ```
47            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
48            ///
49            #[doc = concat!("let blank = ", stringify!($name), "::new();")]
50            #[doc = concat!("assert_eq!(", stringify!($name), "::count_ones(&blank), 0);")]
51            /// ```
52            #[wasm_bindgen(constructor)]
53            pub fn new() -> Self {
54                Default::default()
55            }
56
57            #[doc = concat!("Attempt to initialize a [", stringify!($name), "] with a starting array.")]
58            #[doc = concat!("Fails with a [JsError] if the [Vec] is not exactly ", stringify!($n), " bytes long.")]
59            pub fn try_from_vec(vec: Vec<u8>) -> Result<$name, JsError> {
60                $name::try_from(vec).map_err(|e| JsError::new(&e.to_string()))
61            }
62
63            /// The (constant) size of the underlying [BloomFilter] in bytes.
64            ///
65            /// # Examples
66            ///
67            /// ```
68            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
69            ///
70            #[doc = concat!("let size = ", stringify!($name), "::byte_count();")]
71            #[doc = concat!("assert_eq!(size, ", stringify!($k), ");")]
72            /// ```
73            pub fn byte_count() -> usize {
74                $k
75            }
76
77            /// The number of hashes used in the underlying [BloomFilter].
78            ///
79            /// # Examples
80            ///
81            /// ```
82            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
83            ///
84            #[doc = concat!("assert_eq!(", stringify!($name), "::hash_count(), ", stringify!($n), ");")]
85            /// ```
86            pub fn hash_count() -> usize {
87                $n
88            }
89
90            /// Insert a new elememt into the underlying [BloomFilter].
91            /// This [Vec] can be of any length.
92            ///
93            /// # Examples
94            ///
95            /// ```
96            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
97            ///
98            #[doc = concat!("let mut bloom = ", stringify!($name), "::new();")]
99            /// let item = vec![1, 2, 3, 4, 5];
100            /// bloom.insert_vec(item.clone());
101            ///
102            /// assert!(bloom.contains(item.clone()));
103            /// ```
104            pub fn insert_vec(&mut self, new_val: Vec<u8>) -> () {
105                self.boxed.insert(&new_val);
106            }
107
108            /// Check if some [Vec] is in the underlying [BloomFilter].
109            ///
110            /// # Examples
111            ///
112            /// ```
113            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
114            ///
115            #[doc = concat!("let mut bloom = ", stringify!($name), "::new();")]
116            /// let item = vec![1, 2, 3, 4, 5];
117            /// bloom.insert_vec(item.clone());
118            ///
119            /// assert!(bloom.contains(item.clone()));
120            /// ```
121            pub fn contains(&self, item: Vec<u8>) -> bool {
122                self.boxed.contains(&item)
123            }
124
125            /// Count how many bits are set to 1 (sometimes called a `popcount`).
126            ///
127            /// # Examples
128            ///
129            /// ```
130            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
131            ///
132            #[doc = concat!("let mut bloom = ", stringify!($name), "::new();")]
133            /// let item1 = vec![1, 2, 3, 4, 5];
134            /// bloom.insert_vec(item1.clone());
135            /// bloom.insert_vec(item1.clone());
136            /// bloom.insert_vec(item1.clone());
137            ///
138            /// let item2 = vec![6, 7];
139            /// bloom.insert_vec(item2.clone());
140            ///
141            /// let item3 = vec![8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
142            /// bloom.insert_vec(item2.clone());
143            ///
144            #[doc = concat!("assert!(bloom.count_ones() >= ", $k, ");")]
145            #[doc = concat!("assert!(bloom.count_ones() <= 3 * ", $k, ");")]
146            /// ```
147            pub fn count_ones(&self) -> usize {
148                self.boxed.count_ones()
149            }
150
151            /// Retreive the underlying byte array.
152            ///
153            /// # Examples
154            ///
155            /// ```
156            #[doc = concat!("use deterministic_bloom_wasm::", stringify!($name), ";")]
157            ///
158            #[doc = concat!("let mut bloom = ", stringify!($name), "::new();")]
159            /// bloom.insert_vec(vec![1, 2, 3, 4, 5]);
160            ///
161            #[doc = concat!("assert_ne!(bloom.as_bytes(), vec![0; ", $n, "]);")]
162            #[doc = concat!("assert_eq!(bloom.as_bytes().len(), ", $n, ");")]
163            /// ```
164            pub fn as_bytes(&self) -> Vec<u8> {
165                self.boxed.as_bytes().to_vec()
166            }
167        }
168
169        impl From<BloomFilter<$n, $k>> for $name {
170            fn from(bloom: BloomFilter<$n, $k>) -> Self {
171                $name {
172                    boxed: Box::new(bloom)
173                }
174            }
175        }
176
177        impl TryFrom<Vec<u8>> for $name {
178            type Error = deterministic_bloom::common::Error;
179
180            fn try_from(vec: Vec<u8>) -> Result<Self, deterministic_bloom::common::Error> {
181                <BloomFilter<$n, $k>>::try_from(vec).map($name::from)
182            }
183        }
184    };
185}
186
187gen_bloom!(SmallBloomFilter, 256, 13);
188gen_bloom!(MediumBloomFilter, 4096, 17);
189gen_bloom!(LargeBloomFilter, 1048576, 23);