@peerbit/riblt 0.0.1-5cf61cb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Intersubjective
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # riblt-rust
2
+ Rust port of [RIBLT library](https://github.com/yangl1996/riblt) by yang1996.
3
+
4
+ Implementation of Rateless Invertible Bloom Lookup Tables (Rateless IBLTs), as
5
+ proposed in paper Practical Rateless Set Reconciliation by Lei Yang, Yossi
6
+ Gilad, and Mohammad Alizadeh. Preprint available at
7
+ [arxiv.org/abs/2402.02668](https://arxiv.org/abs/2402.02668).
8
+
9
+ ## Library API
10
+
11
+ To use this library, implement a `Symbol` trait, and create `Encoder` or `Decoder` objects to encode and decode symbols.
12
+
13
+ ### `Symbol` trait
14
+ - `fn zero() -> Self` - Create a zero symbol.
15
+ - `fn xor(&self, other: &Self) -> Self` - XOR of this symbol and another symbol.
16
+ - `fn hash(&self) -> u64` - Calculate a hash of the symbol.
17
+
18
+ Example implementation for 64-bit integer symbols:
19
+ ```rs
20
+ use riblt::*;
21
+ use std::hash::{SipHasher, Hasher};
22
+
23
+ pub type MyU64 = u64;
24
+
25
+ impl Symbol for MyU64 {
26
+ fn zero() -> MyU64 {
27
+ return 0;
28
+ }
29
+
30
+ fn xor(&self, other: &MyU64) -> MyU64 {
31
+ return self ^ other;
32
+ }
33
+
34
+ fn hash(&self) -> u64 {
35
+ let mut hasher = SipHasher::new_with_keys(123, 456);
36
+ hasher.write_u64(*self);
37
+ return hasher.finish();
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### `Encoder` methods
43
+ - `Encoder::<T>::new()` - Create a new Encoder for symbols of type `T`.
44
+ - `enc.reset()` - Reset the Encoder state.
45
+ - `enc.add_symbol(symbol: &T)` - Add a new symbol to the Encoder.
46
+ - `enc.produce_next_coded_symbol() -> CodedSymbol<T>` - Produce the next coded symbol that can be decoded by the Decoder.
47
+
48
+ #### Example usage
49
+ ```rs
50
+ use riblt::*;
51
+
52
+ fn foo() {
53
+ let mut enc = Encoder::<MyU64>::new();
54
+ let symbols : [MyU64; 5] = [ 1, 2, 3, 4, 5 ];
55
+ for x in symbols {
56
+ enc.add_symbol(&x);
57
+ }
58
+
59
+ let coded = enc.produce_next_coded_symbol();
60
+
61
+ // send symbol to the decoder...
62
+ }
63
+ ```
64
+
65
+ ### `Decoder` methods
66
+ - `Decoder::<T>::new()` - Create a new Decoder for symbols of type `T`.
67
+ - `dec.reset()` - Reset the Decoder state.
68
+ - `dec.add_symbol(symbol: &T)` - Add a new symbol to the Decoder.
69
+ - `dec.add_coded_symbol(symbol: &CodedSymbol<T>)` - Add a new coded symbol to the Decoder.
70
+ - `dec.try_decode()` - Try to decode added symbols. May returns `Err(InvalidDegree)`.
71
+ - `dec.decoded()` - Returns `true` if all added coded symbols where decoded.
72
+ - `dec.get_remote_symbols() -> Vec<HashedSymbol<T>>` - Returns an array of decoded remote symbols.
73
+ - `dec.get_local_symbols() -> Vec<HashedSymbol<T>>` - Returns an array of local symbols.
74
+
75
+ Remote and local symbols can be accessed directly via Decoder properties:
76
+ - `dec.remote.symbols`,
77
+ - `dec.local.symbols`.
78
+
79
+ #### Example usage
80
+ ```rs
81
+ use riblt::*;
82
+
83
+ fn foo() {
84
+ let symbols : [CodedSymbol<MyU64>; 5] = ...;
85
+
86
+ let mut dec = Decoder::<MyU64>::new();
87
+ for i in 0..symbols.len() {
88
+ dec.add_coded_symbol(&symbols[i]);
89
+ }
90
+
91
+ if dec.try_decode().is_err() {
92
+ // Decoding error...
93
+ }
94
+
95
+ if dec.decoded() {
96
+ // Success...
97
+ }
98
+ }
99
+ ```
100
+
101
+ For the complete example see test `example` in `src/tests.rs`.
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@peerbit/riblt",
3
+ "version": "0.0.1-5cf61cb",
4
+ "description": "Riblt",
5
+ "sideEffects": false,
6
+ "type": "module",
7
+ "types": "./pkg/riblt.d.ts",
8
+ "typesVersions": {
9
+ "*": {
10
+ "*": [
11
+ "*",
12
+ "pkg/*",
13
+ "pkg/*/index"
14
+ ],
15
+ "src/*": [
16
+ "*",
17
+ "pkg/*",
18
+ "pkg/*/index"
19
+ ]
20
+ }
21
+ },
22
+ "files": [
23
+ "src",
24
+ "dist",
25
+ "!dist/test",
26
+ "!**/*.tsbuildinfo"
27
+ ],
28
+ "exports": {
29
+ ".": {
30
+ "types": "./pkg/riblt.d.ts",
31
+ "import": "./pkg/riblt.js"
32
+ }
33
+ },
34
+ "eslintConfig": {
35
+ "extends": "peerbit",
36
+ "parserOptions": {
37
+ "project": true,
38
+ "sourceType": "module"
39
+ },
40
+ "ignorePatterns": [
41
+ "!.aegir.js",
42
+ "test/ts-use",
43
+ "*.d.ts"
44
+ ]
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "scripts": {
50
+ "benchmark": "cargo bench",
51
+ "clean": "cargo clear",
52
+ "build": "wasm-pack build --target web && shx rm -rf ./pkg/package.json",
53
+ "test": "cargo test && aegir test",
54
+ "lint": "cargo fmt"
55
+ },
56
+ "author": "dao.xyz",
57
+ "license": "MIT"
58
+ }
@@ -0,0 +1,397 @@
1
+ // NOTE
2
+ // - Investigate static/dynamic dispatch in regard to
3
+ // the performance when using traits like Symbol.
4
+ // - Hash values are hardcoded to be u64, make it more generic.
5
+ // - SipHasher is deprecated. Maybe replace it with a different hasher.
6
+
7
+ use std::vec::Vec;
8
+
9
+ pub trait Symbol {
10
+ fn zero() -> Self;
11
+ fn xor(&self, other: &Self) -> Self;
12
+ fn hash(&self) -> u64;
13
+ }
14
+
15
+ #[derive(Clone, Copy)]
16
+ pub enum Direction {
17
+ ADD = 1,
18
+ REMOVE = -1,
19
+ }
20
+
21
+ #[derive(Clone, Copy)]
22
+ pub enum Error {
23
+ InvalidDegree = 1,
24
+ InvalidSize = 2,
25
+ DecodeFailed = 3,
26
+ }
27
+
28
+ #[derive(Clone, Copy)]
29
+ pub struct SymbolMapping {
30
+ pub source_idx: u64,
31
+ pub coded_idx: u64,
32
+ }
33
+
34
+ #[derive(Clone, Copy)]
35
+ pub struct RandomMapping {
36
+ pub prng: u64,
37
+ pub last_idx: u64,
38
+ }
39
+
40
+ #[derive(Clone, Copy)]
41
+ pub struct HashedSymbol<T: Symbol + Copy> {
42
+ pub symbol: T,
43
+ pub hash: u64,
44
+ }
45
+
46
+ #[derive(Clone, Copy, PartialEq, Debug)]
47
+ pub struct CodedSymbol<T: Symbol + Copy> {
48
+ pub symbol: T,
49
+ pub hash: u64,
50
+ pub count: i64,
51
+ }
52
+
53
+ #[derive(Clone)]
54
+ pub struct Encoder<T: Symbol + Copy> {
55
+ pub symbols: Vec<HashedSymbol<T>>,
56
+ pub mappings: Vec<RandomMapping>,
57
+ pub queue: Vec<SymbolMapping>,
58
+ pub next_idx: u64,
59
+ }
60
+
61
+ pub struct Decoder<T: Symbol + Copy> {
62
+ coded: Vec<CodedSymbol<T>>,
63
+ pub local: Encoder<T>,
64
+ pub remote: Encoder<T>,
65
+ window: Encoder<T>,
66
+ decodable: Vec<i64>,
67
+ num_decoded: u64,
68
+ }
69
+
70
+ impl RandomMapping {
71
+ pub fn next_index(&mut self) -> u64 {
72
+ let r = self.prng.wrapping_mul(0xda942042e4dd58b5);
73
+ self.prng = r;
74
+ self.last_idx = self.last_idx.wrapping_add(
75
+ (((self.last_idx as f64) + 1.5)
76
+ * (((1i64 << 32) as f64) / f64::sqrt((r as f64) + 1.0) - 1.0))
77
+ .ceil() as u64,
78
+ );
79
+ return self.last_idx;
80
+ }
81
+ }
82
+
83
+ impl<T: Symbol + Copy> CodedSymbol<T> {
84
+ pub fn apply(&mut self, sym: &HashedSymbol<T>, direction: Direction) {
85
+ self.symbol = self.symbol.xor(&sym.symbol);
86
+ self.hash ^= sym.hash;
87
+ self.count += direction as i64;
88
+ }
89
+ }
90
+
91
+ impl<T: Symbol + Copy + PartialEq> Encoder<T> {
92
+ pub fn new() -> Self {
93
+ return Encoder::<T> {
94
+ symbols: Vec::<HashedSymbol<T>>::new(),
95
+ mappings: Vec::<RandomMapping>::new(),
96
+ queue: Vec::<SymbolMapping>::new(),
97
+ next_idx: 0,
98
+ };
99
+ }
100
+
101
+ pub fn reset(&mut self) {
102
+ self.symbols.clear();
103
+ self.mappings.clear();
104
+ self.queue.clear();
105
+ self.next_idx = 0;
106
+ }
107
+
108
+ pub fn add_hashed_symbol_with_mapping(&mut self, sym: &HashedSymbol<T>, mapp: &RandomMapping) {
109
+ self.symbols.push(*sym);
110
+ self.mappings.push(*mapp);
111
+
112
+ self.queue.push(SymbolMapping {
113
+ source_idx: (self.symbols.len() as u64) - 1,
114
+ coded_idx: mapp.last_idx,
115
+ });
116
+
117
+ // Fix tail
118
+ //
119
+ let mut cur: usize = self.queue.len() - 1;
120
+ while cur > 0 {
121
+ let parent = (cur - 1) / 2;
122
+ if cur == parent || self.queue[parent].coded_idx <= self.queue[cur].coded_idx {
123
+ break;
124
+ }
125
+ self.queue.swap(parent, cur);
126
+ cur = parent;
127
+ }
128
+ }
129
+
130
+ pub fn add_hashed_symbol(&mut self, sym: &HashedSymbol<T>) {
131
+ self.add_hashed_symbol_with_mapping(
132
+ sym,
133
+ &RandomMapping {
134
+ prng: sym.hash,
135
+ last_idx: 0,
136
+ },
137
+ );
138
+ }
139
+
140
+ pub fn add_symbol(&mut self, sym: &T) {
141
+ self.add_hashed_symbol(&HashedSymbol::<T> {
142
+ symbol: *sym,
143
+ hash: sym.hash(),
144
+ });
145
+ }
146
+
147
+ pub fn apply_window(&mut self, sym: &CodedSymbol<T>, direction: Direction) -> CodedSymbol<T> {
148
+ let mut next_sym = *sym;
149
+
150
+ if self.queue.is_empty() {
151
+ self.next_idx += 1;
152
+ return next_sym;
153
+ }
154
+
155
+ while self.queue[0].coded_idx == self.next_idx {
156
+ next_sym.apply(&self.symbols[self.queue[0].source_idx as usize], direction);
157
+ self.queue[0].coded_idx = self.mappings[self.queue[0].source_idx as usize].next_index();
158
+
159
+ // Fix head
160
+ //
161
+ let mut cur: usize = 0;
162
+ loop {
163
+ let mut child = cur * 2 + 1;
164
+ if child >= self.queue.len() {
165
+ break;
166
+ }
167
+ let right_child = child + 1;
168
+ if right_child < self.queue.len()
169
+ && self.queue[right_child].coded_idx < self.queue[child].coded_idx
170
+ {
171
+ child = right_child;
172
+ }
173
+ if self.queue[cur].coded_idx <= self.queue[child].coded_idx {
174
+ break;
175
+ }
176
+ self.queue.swap(cur, child);
177
+ cur = child;
178
+ }
179
+ }
180
+
181
+ self.next_idx += 1;
182
+ return next_sym;
183
+ }
184
+
185
+ pub fn produce_next_coded_symbol(&mut self) -> CodedSymbol<T> {
186
+ return self.apply_window(
187
+ &CodedSymbol::<T> {
188
+ symbol: T::zero(),
189
+ hash: 0,
190
+ count: 0,
191
+ },
192
+ Direction::ADD,
193
+ );
194
+ }
195
+
196
+ pub fn remove_symbol(&mut self, sym: &T) {
197
+ let hash = sym.hash();
198
+ // Find the position of the symbol to remove
199
+ if let Some(pos) = self
200
+ .symbols
201
+ .iter()
202
+ .position(|s| s.hash == hash && s.symbol == *sym)
203
+ {
204
+ // Remove the symbol and its mapping
205
+ self.symbols.remove(pos);
206
+ self.mappings.remove(pos);
207
+
208
+ // Update the queue
209
+ // Collect indices in the queue that need to be removed or adjusted
210
+ let mut indices_to_remove = Vec::new();
211
+ for (i, sm) in self.queue.iter_mut().enumerate() {
212
+ if sm.source_idx == pos as u64 {
213
+ // Mark this index for removal
214
+ indices_to_remove.push(i);
215
+ } else if sm.source_idx > pos as u64 {
216
+ // Decrement source_idx to account for the removed symbol
217
+ sm.source_idx -= 1;
218
+ }
219
+ }
220
+
221
+ // Remove the SymbolMappings from the queue in reverse order to maintain correct indexing
222
+ for &i in indices_to_remove.iter().rev() {
223
+ self.queue.remove(i);
224
+ }
225
+
226
+ // Rebuild the heap property of the queue
227
+ self.build_queue_heap();
228
+ } else {
229
+ // Symbol not found; you may choose to handle this case differently
230
+ eprintln!("Symbol not found in encoder.");
231
+ }
232
+ }
233
+
234
+ // Helper method to rebuild the heap property of the queue
235
+ fn build_queue_heap(&mut self) {
236
+ let len = self.queue.len();
237
+ for i in (0..len / 2).rev() {
238
+ self.heapify_down(i);
239
+ }
240
+ }
241
+
242
+ // Helper method to restore the heap property from a given index downwards
243
+ fn heapify_down(&mut self, mut cur: usize) {
244
+ let len = self.queue.len();
245
+ loop {
246
+ let mut child = 2 * cur + 1;
247
+ if child >= len {
248
+ break;
249
+ }
250
+ let right = child + 1;
251
+ if right < len && self.queue[right].coded_idx < self.queue[child].coded_idx {
252
+ child = right;
253
+ }
254
+ if self.queue[cur].coded_idx <= self.queue[child].coded_idx {
255
+ break;
256
+ }
257
+ self.queue.swap(cur, child);
258
+ cur = child;
259
+ }
260
+ }
261
+ }
262
+
263
+ impl<T: Symbol + Copy + PartialEq> Encoder<T> {
264
+ pub fn to_decoder(&self) -> Decoder<T> {
265
+ let mut decoder = Decoder::<T>::new();
266
+ // Clone the current encoder state into the decoder's window encoder
267
+ decoder.window = self.clone();
268
+ decoder
269
+ }
270
+ }
271
+
272
+ impl<T: Symbol + Copy + PartialEq> Decoder<T> {
273
+ pub fn new() -> Self {
274
+ return Decoder::<T> {
275
+ coded: Vec::<CodedSymbol<T>>::new(),
276
+ local: Encoder::<T>::new(),
277
+ remote: Encoder::<T>::new(),
278
+ window: Encoder::<T>::new(),
279
+ decodable: Vec::<i64>::new(),
280
+ num_decoded: 0,
281
+ };
282
+ }
283
+
284
+ pub fn reset(&mut self) {
285
+ self.coded.clear();
286
+ self.local.reset();
287
+ self.remote.reset();
288
+ self.window.reset();
289
+ self.decodable.clear();
290
+ self.num_decoded = 0;
291
+ }
292
+
293
+ pub fn add_symbol(&mut self, sym: &T) {
294
+ self.window.add_hashed_symbol(&HashedSymbol::<T> {
295
+ symbol: *sym,
296
+ hash: sym.hash(),
297
+ });
298
+ }
299
+
300
+ pub fn add_coded_symbol(&mut self, sym: &CodedSymbol<T>) {
301
+ let mut next_sym = self.window.apply_window(sym, Direction::REMOVE);
302
+ next_sym = self.remote.apply_window(&next_sym, Direction::REMOVE);
303
+ next_sym = self.local.apply_window(&next_sym, Direction::ADD);
304
+
305
+ self.coded.push(next_sym);
306
+
307
+ if ((next_sym.count == 1 || next_sym.count == -1)
308
+ && (next_sym.hash == next_sym.symbol.hash()))
309
+ || (next_sym.count == 0 && next_sym.hash == 0)
310
+ {
311
+ self.decodable.push((self.coded.len() as i64) - 1);
312
+ }
313
+ }
314
+
315
+ fn apply_new_symbol(&mut self, sym: &HashedSymbol<T>, direction: Direction) -> RandomMapping {
316
+ let mut mapp = RandomMapping {
317
+ prng: sym.hash,
318
+ last_idx: 0,
319
+ };
320
+
321
+ while mapp.last_idx < (self.coded.len() as u64) {
322
+ let n = mapp.last_idx as usize;
323
+ self.coded[n].apply(&sym, direction);
324
+
325
+ if (self.coded[n].count == -1 || self.coded[n].count == 1)
326
+ && self.coded[n].hash == self.coded[n].symbol.hash()
327
+ {
328
+ self.decodable.push(n as i64);
329
+ }
330
+
331
+ mapp.next_index();
332
+ }
333
+
334
+ return mapp;
335
+ }
336
+
337
+ pub fn try_decode(&mut self) -> Result<(), Error> {
338
+ let mut didx: usize = 0;
339
+
340
+ // self.decodable.len() will increase in apply_new_symbol
341
+ //
342
+ while didx < self.decodable.len() {
343
+ let cidx = self.decodable[didx] as usize;
344
+ let sym = self.coded[cidx];
345
+
346
+ match sym.count {
347
+ 1 => {
348
+ let new_sym = HashedSymbol::<T> {
349
+ symbol: T::zero().xor(&sym.symbol),
350
+ hash: sym.hash,
351
+ };
352
+
353
+ let mapp = self.apply_new_symbol(&new_sym, Direction::REMOVE);
354
+ self.remote.add_hashed_symbol_with_mapping(&new_sym, &mapp);
355
+ self.num_decoded += 1;
356
+ }
357
+
358
+ -1 => {
359
+ let new_sym = HashedSymbol::<T> {
360
+ symbol: T::zero().xor(&sym.symbol),
361
+ hash: sym.hash,
362
+ };
363
+
364
+ let mapp = self.apply_new_symbol(&new_sym, Direction::ADD);
365
+ self.local.add_hashed_symbol_with_mapping(&new_sym, &mapp);
366
+ self.num_decoded += 1;
367
+ }
368
+
369
+ 0 => {
370
+ self.num_decoded += 1;
371
+ }
372
+
373
+ _ => {
374
+ return Err(Error::InvalidDegree);
375
+ }
376
+ }
377
+
378
+ didx += 1;
379
+ }
380
+
381
+ self.decodable.clear();
382
+
383
+ return Ok(());
384
+ }
385
+
386
+ pub fn decoded(&self) -> bool {
387
+ return self.num_decoded == (self.coded.len() as u64);
388
+ }
389
+
390
+ pub fn get_remote_symbols(&self) -> Vec<HashedSymbol<T>> {
391
+ return self.remote.symbols.clone();
392
+ }
393
+
394
+ pub fn get_local_symbols(&self) -> Vec<HashedSymbol<T>> {
395
+ return self.local.symbols.clone();
396
+ }
397
+ }
package/src/lib.rs ADDED
@@ -0,0 +1,7 @@
1
+ #[cfg(test)]
2
+ mod tests;
3
+
4
+ pub mod encoding;
5
+ pub mod sketch;
6
+ pub mod testing;
7
+ pub mod wasm;
package/src/sketch.rs ADDED
@@ -0,0 +1,101 @@
1
+ // FIXME
2
+ // Mostly untested code.
3
+
4
+ use super::encoding::*;
5
+ use std::vec::Vec;
6
+
7
+ pub struct Sketch<T: Symbol + Copy> {
8
+ pub v: Vec<CodedSymbol<T>>,
9
+ }
10
+
11
+ pub struct SketchDecodeResult<T: Symbol + Copy> {
12
+ pub fwd: Vec<HashedSymbol<T>>,
13
+ pub rev: Vec<HashedSymbol<T>>,
14
+ pub is_decoded: bool,
15
+ }
16
+
17
+ impl<T: Symbol + Copy + PartialEq> Sketch<T> {
18
+ pub fn new(size: usize) -> Sketch<T> {
19
+ return Sketch::<T> {
20
+ v: vec![
21
+ CodedSymbol::<T> {
22
+ symbol: T::zero(),
23
+ hash: 0,
24
+ count: 0,
25
+ };
26
+ size
27
+ ],
28
+ };
29
+ }
30
+
31
+ pub fn add_hashed_symbol(&mut self, sym: &HashedSymbol<T>) {
32
+ let mut mapp = RandomMapping {
33
+ prng: sym.hash,
34
+ last_idx: 0,
35
+ };
36
+
37
+ while (mapp.last_idx as usize) < self.v.len() {
38
+ let idx = mapp.last_idx as usize;
39
+ self.v[idx].symbol = self.v[idx].symbol.xor(&sym.symbol);
40
+ self.v[idx].count += 1;
41
+ self.v[idx].hash ^= sym.hash;
42
+ mapp.next_index();
43
+ }
44
+ }
45
+
46
+ pub fn remove_hashed_symbol(&mut self, sym: &HashedSymbol<T>) {
47
+ let mut mapp = RandomMapping {
48
+ prng: sym.hash,
49
+ last_idx: 0,
50
+ };
51
+
52
+ while (mapp.last_idx as usize) < self.v.len() {
53
+ let idx = mapp.last_idx as usize;
54
+ self.v[idx].symbol = self.v[idx].symbol.xor(&sym.symbol);
55
+ self.v[idx].count -= 1;
56
+ self.v[idx].hash ^= sym.hash;
57
+ mapp.next_index();
58
+ }
59
+ }
60
+
61
+ pub fn add_symbol(&mut self, sym: &T) {
62
+ self.add_hashed_symbol(&HashedSymbol::<T> {
63
+ symbol: *sym,
64
+ hash: sym.hash(),
65
+ });
66
+ }
67
+
68
+ pub fn remove_symbol(&mut self, sym: &T) {
69
+ self.remove_hashed_symbol(&HashedSymbol::<T> {
70
+ symbol: *sym,
71
+ hash: sym.hash(),
72
+ });
73
+ }
74
+
75
+ pub fn subtract(&mut self, other: &Sketch<T>) -> Result<(), Error> {
76
+ if self.v.len() != other.v.len() {
77
+ return Err(Error::InvalidSize);
78
+ }
79
+ for i in 0..self.v.len() {
80
+ self.v[i].symbol = self.v[i].symbol.xor(&other.v[i].symbol);
81
+ self.v[i].count = self.v[i].count - other.v[i].count;
82
+ self.v[i].hash ^= other.v[i].hash;
83
+ }
84
+ return Ok(());
85
+ }
86
+
87
+ pub fn decode(&mut self) -> Result<SketchDecodeResult<T>, Error> {
88
+ let mut dec = Decoder::<T>::new();
89
+ for i in 0..self.v.len() {
90
+ dec.add_coded_symbol(&self.v[i]);
91
+ }
92
+ return match dec.try_decode() {
93
+ Ok(()) => Ok(SketchDecodeResult::<T> {
94
+ fwd: dec.get_remote_symbols(),
95
+ rev: dec.get_local_symbols(),
96
+ is_decoded: dec.decoded(),
97
+ }),
98
+ Err(x) => Err(x),
99
+ };
100
+ }
101
+ }