-
-
Notifications
You must be signed in to change notification settings - Fork 351
Expand file tree
/
Copy pathinteraction_groups.rs
More file actions
96 lines (86 loc) · 3.46 KB
/
interaction_groups.rs
File metadata and controls
96 lines (86 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#[repr(transparent)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
/// Pairwise filtering using bit masks.
///
/// This filtering method is based on two 32-bit values:
/// - The interaction groups (the 32 left-most bits of `self.0`).
/// - The interaction mask (the 32 right-most bits of `self.0`).
///
/// An interaction is allowed between two filters `a` and `b` when two conditions
/// are met simultaneously for [`Self::test_and`] or individually for [`Self::test_or`]:
/// - The interaction groups of `a` has at least one bit set to `1` in common with the interaction mask of `b`.
/// - The interaction groups of `b` has at least one bit set to `1` in common with the interaction mask of `a`.
///
/// In other words, interactions are allowed between two filter iff. the following condition is met
/// for [`Self::test_and`]:
/// ```ignore
/// ((self.0 >> 32) & rhs.0) != 0 && ((rhs.0 >> 32) & self.0) != 0
/// ```
/// or for [`Self::test_or`]:
/// ```ignore
/// ((self.0 >> 32) & rhs.0) != 0 || ((rhs.0 >> 32) & self.0) != 0
/// ```
pub struct InteractionGroups(pub u64);
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
/// Specifies which method should be used to test interactions
pub enum InteractionTestMode {
/// Use [`InteractionGroups::test_and`].
AND,
/// Use [`InteractionGroups::test_or`].
OR,
}
impl InteractionGroups {
/// Initializes with the given interaction groups and interaction mask.
pub const fn new(groups: u32, masks: u32) -> Self {
Self::none().with_groups(groups).with_mask(masks)
}
/// Allow interaction with everything.
pub const fn all() -> Self {
Self(u64::MAX)
}
/// Prevent all interactions.
pub const fn none() -> Self {
Self(0)
}
/// Sets the group this filter is part of.
pub const fn with_groups(self, groups: u32) -> Self {
Self((self.0 & 0x0000_0000_ffff_ffff) | ((groups as u64) << 32))
}
/// Sets the interaction mask of this filter.
pub const fn with_mask(self, mask: u32) -> Self {
Self((self.0 & 0xffff_ffff_0000_0000) | (mask as u64))
}
/// Check if interactions should be allowed based on the interaction groups and mask.
///
/// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common
/// with the mask of `rhs`, **and** vice-versa.
#[inline]
pub const fn test_and(self, rhs: Self) -> bool {
((self.0 >> 32) & rhs.0) != 0 && ((rhs.0 >> 32) & self.0) != 0
}
/// Check if interactions should be allowed based on the interaction groups and mask.
///
/// An interaction is allowed iff. the groups of `self` contain at least one bit set to 1 in common
/// with the mask of `rhs`, **or** vice-versa.
#[inline]
pub const fn test_or(self, rhs: Self) -> bool {
((self.0 >> 32) & rhs.0) != 0 || ((rhs.0 >> 32) & self.0) != 0
}
/// Check if interactions should be allowed based on the interaction groups and mask.
///
/// See [`InteractionTestMode`] for more info.
#[inline]
pub const fn test(self, rhs: Self, mode: InteractionTestMode) -> bool {
match mode {
InteractionTestMode::AND => self.test_and(rhs),
InteractionTestMode::OR => self.test_or(rhs),
}
}
}
impl Default for InteractionGroups {
fn default() -> Self {
Self::all()
}
}