Skip to main content

naia_shared/world/update/
diff_mask.rs

1use std::fmt;
2
3/// Variable-length bitmask where each bit tracks whether the corresponding property on a replicated component has been mutated and needs to be sent to the remote peer.
4#[derive(PartialEq, Eq, Clone, Debug)]
5pub struct DiffMask {
6    mask: Vec<u8>,
7}
8
9impl DiffMask {
10    /// Create a new DiffMask with a given number of bytes
11    pub fn new(bytes: u8) -> DiffMask {
12        DiffMask {
13            mask: vec![0; bytes as usize],
14        }
15    }
16
17    /// Gets the bit at the specified position within the DiffMask
18    pub fn bit(&self, index: u8) -> Option<bool> {
19        if let Some(byte) = self.mask.get((index / 8) as usize) {
20            let adjusted_index = index % 8;
21            return Some(byte & (1 << adjusted_index) != 0);
22        }
23
24        None
25    }
26
27    /// Sets the bit at the specified position within the DiffMask
28    pub fn set_bit(&mut self, index: u8, value: bool) {
29        if let Some(byte) = self.mask.get_mut((index / 8) as usize) {
30            let adjusted_index = index % 8;
31            let bit_mask = 1 << adjusted_index;
32            if value {
33                *byte |= bit_mask;
34            } else {
35                *byte &= !bit_mask;
36            }
37        }
38    }
39
40    /// Clears the whole DiffMask
41    pub fn clear(&mut self) {
42        let size = self.mask.len();
43        self.mask = vec![0; size];
44    }
45
46    /// Returns whether any bit has been set in the DiffMask
47    pub fn is_clear(&self) -> bool {
48        for byte in self.mask.iter() {
49            if *byte != 0 {
50                return false;
51            }
52        }
53        true
54    }
55
56    /// Get the number of bytes required to represent the DiffMask
57    pub fn byte_number(&self) -> u8 {
58        self.mask.len() as u8
59    }
60
61    /// Gets a byte at the specified index in the DiffMask
62    pub fn byte(&self, index: usize) -> u8 {
63        self.mask[index]
64    }
65
66    /// Performs a NAND operation on the DiffMask, with another DiffMask
67    pub fn nand(&mut self, other: &DiffMask) {
68        // NOTE: this is not actually a NAND operation, but a "AND NOT" operation
69
70        //if other diff mask has different capacity, do nothing
71        if other.byte_number() != self.byte_number() {
72            return;
73        }
74
75        for n in 0..self.mask.len() {
76            if let Some(my_byte) = self.mask.get_mut(n) {
77                let other_byte = !other.byte(n);
78                *my_byte &= other_byte;
79            }
80        }
81    }
82
83    /// Performs an OR operation on the DiffMask, with another DiffMask
84    pub fn or(&mut self, other: &DiffMask) {
85        //if other diff mask has different capacity, do nothing
86        if other.byte_number() != self.byte_number() {
87            return;
88        }
89
90        for n in 0..self.mask.len() {
91            if let Some(my_byte) = self.mask.get_mut(n) {
92                let other_byte = other.byte(n);
93                *my_byte |= other_byte;
94            }
95        }
96    }
97
98    /// Copies the DiffMask into another DiffMask
99    pub fn copy_contents(&mut self, other: &DiffMask) {
100        //if other diff mask has different capacity, do nothing
101        if other.byte_number() != self.byte_number() {
102            return;
103        }
104
105        for n in 0..self.mask.len() {
106            if let Some(my_byte) = self.mask.get_mut(n) {
107                let other_byte = other.byte(n);
108                *my_byte = other_byte;
109            }
110        }
111    }
112}
113
114impl fmt::Display for DiffMask {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        let mut out_string: String = String::new();
117        for y in 0..8 {
118            if let Some(bit) = self.bit(y) {
119                if bit {
120                    out_string.push('1');
121                } else {
122                    out_string.push('0');
123                }
124            }
125        }
126        write!(f, "{}", out_string)
127    }
128}
129
130#[cfg(test)]
131mod single_byte_tests {
132    use crate::DiffMask;
133
134    #[test]
135    fn getset() {
136        let mut mask = DiffMask::new(1);
137
138        mask.set_bit(0, true);
139        mask.set_bit(2, true);
140        mask.set_bit(4, true);
141        mask.set_bit(6, true);
142        mask.set_bit(4, false);
143
144        assert!(mask.bit(0).unwrap());
145        assert!(!mask.bit(1).unwrap());
146        assert!(mask.bit(2).unwrap());
147        assert!(!mask.bit(4).unwrap());
148        assert!(mask.bit(6).unwrap());
149    }
150
151    #[test]
152    fn clear() {
153        let mut mask = DiffMask::new(1);
154
155        mask.set_bit(0, true);
156        mask.set_bit(2, true);
157        mask.set_bit(4, true);
158        mask.set_bit(6, true);
159
160        mask.clear();
161
162        assert!(!mask.bit(0).unwrap());
163        assert!(!mask.bit(2).unwrap());
164        assert!(!mask.bit(4).unwrap());
165        assert!(!mask.bit(6).unwrap());
166    }
167
168    #[test]
169    fn is_clear_true() {
170        let mut mask = DiffMask::new(1);
171
172        mask.set_bit(2, true);
173
174        assert!(!mask.is_clear());
175
176        mask.set_bit(2, false);
177
178        assert!(mask.is_clear());
179    }
180
181    #[test]
182    fn bytes() {
183        let mask = DiffMask::new(1);
184        assert!(mask.byte_number() == 1);
185    }
186
187    #[test]
188    fn byte() {
189        let mut mask = DiffMask::new(1);
190        mask.set_bit(2, true);
191        let byte = mask.byte(0);
192        assert!(byte == 4);
193    }
194
195    #[test]
196    fn nand() {
197        let mut mask_a = DiffMask::new(1);
198        mask_a.set_bit(1, true);
199        mask_a.set_bit(2, true);
200
201        let mut mask_b = DiffMask::new(1);
202        mask_b.set_bit(1, true);
203
204        mask_a.nand(&mask_b);
205
206        assert!(!mask_a.bit(0).unwrap());
207        assert!(!mask_a.bit(1).unwrap());
208        assert!(mask_a.bit(2).unwrap());
209        assert!(!mask_a.bit(3).unwrap());
210    }
211
212    #[test]
213    fn or() {
214        let mut mask_a = DiffMask::new(1);
215        mask_a.set_bit(1, true);
216        mask_a.set_bit(2, true);
217
218        let mut mask_b = DiffMask::new(1);
219        mask_b.set_bit(2, true);
220        mask_b.set_bit(3, true);
221
222        mask_a.or(&mask_b);
223
224        assert!(!mask_a.bit(0).unwrap());
225        assert!(mask_a.bit(1).unwrap());
226        assert!(mask_a.bit(2).unwrap());
227        assert!(mask_a.bit(3).unwrap());
228        assert!(!mask_a.bit(4).unwrap());
229    }
230
231    #[test]
232    fn clone() {
233        let mut mask_a = DiffMask::new(1);
234        mask_a.set_bit(1, true);
235        mask_a.set_bit(4, true);
236
237        let mask_b = mask_a.clone();
238
239        assert!(mask_b.bit(1).unwrap());
240        assert!(!mask_b.bit(3).unwrap());
241        assert!(mask_b.bit(4).unwrap());
242    }
243}
244
245#[cfg(test)]
246mod double_byte_tests {
247    use crate::DiffMask;
248
249    #[test]
250    fn getset() {
251        let mut mask = DiffMask::new(2);
252
253        mask.set_bit(0, true);
254        mask.set_bit(4, true);
255        mask.set_bit(8, true);
256        mask.set_bit(12, true);
257        mask.set_bit(8, false);
258
259        assert!(mask.bit(0).unwrap());
260        assert!(mask.bit(4).unwrap());
261        assert!(!mask.bit(8).unwrap());
262        assert!(mask.bit(12).unwrap());
263        assert!(!mask.bit(13).unwrap());
264    }
265
266    #[test]
267    fn clear() {
268        let mut mask = DiffMask::new(2);
269
270        mask.set_bit(0, true);
271        mask.set_bit(4, true);
272        mask.set_bit(8, true);
273        mask.set_bit(12, true);
274
275        mask.clear();
276
277        assert!(!mask.bit(0).unwrap());
278        assert!(!mask.bit(4).unwrap());
279        assert!(!mask.bit(8).unwrap());
280        assert!(!mask.bit(12).unwrap());
281    }
282
283    #[test]
284    fn is_clear_true() {
285        let mut mask = DiffMask::new(2);
286
287        mask.set_bit(9, true);
288
289        assert!(!mask.is_clear());
290
291        mask.set_bit(9, false);
292
293        assert!(mask.is_clear());
294    }
295
296    #[test]
297    fn bytes() {
298        let mask = DiffMask::new(2);
299        assert!(mask.byte_number() == 2);
300    }
301
302    #[test]
303    fn byte() {
304        let mut mask = DiffMask::new(2);
305        mask.set_bit(10, true);
306        let byte = mask.byte(1);
307        assert!(byte == 4);
308    }
309
310    #[test]
311    fn nand() {
312        let mut mask_a = DiffMask::new(2);
313        mask_a.set_bit(1, true);
314        mask_a.set_bit(2, true);
315        mask_a.set_bit(9, true);
316        mask_a.set_bit(10, true);
317
318        let mut mask_b = DiffMask::new(2);
319        mask_b.set_bit(1, true);
320        mask_b.set_bit(9, true);
321
322        mask_a.nand(&mask_b);
323
324        assert!(!mask_a.bit(0).unwrap());
325        assert!(!mask_a.bit(1).unwrap());
326        assert!(mask_a.bit(2).unwrap());
327        assert!(!mask_a.bit(3).unwrap());
328
329        assert!(!mask_a.bit(8).unwrap());
330        assert!(!mask_a.bit(9).unwrap());
331        assert!(mask_a.bit(10).unwrap());
332        assert!(!mask_a.bit(11).unwrap());
333    }
334
335    #[test]
336    fn or() {
337        let mut mask_a = DiffMask::new(2);
338        mask_a.set_bit(4, true);
339        mask_a.set_bit(8, true);
340
341        let mut mask_b = DiffMask::new(2);
342        mask_b.set_bit(8, true);
343        mask_b.set_bit(12, true);
344
345        mask_a.or(&mask_b);
346
347        assert!(!mask_a.bit(0).unwrap());
348        assert!(mask_a.bit(4).unwrap());
349        assert!(mask_a.bit(8).unwrap());
350        assert!(mask_a.bit(12).unwrap());
351        assert!(!mask_a.bit(15).unwrap());
352    }
353
354    #[test]
355    fn clone() {
356        let mut mask_a = DiffMask::new(2);
357        mask_a.set_bit(2, true);
358        mask_a.set_bit(10, true);
359
360        let mask_b = mask_a.clone();
361
362        assert!(mask_b.bit(2).unwrap());
363        assert!(!mask_b.bit(4).unwrap());
364        assert!(!mask_b.bit(9).unwrap());
365        assert!(mask_b.bit(10).unwrap());
366    }
367}