Beatsaber Rust Utilities: A Beatsaber V3 parsing library.
beatsaber beatmap
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Added `count_filtered` method and reverse filter support for `is_in_filter`.

+80 -14
+69 -14
src/difficulty/lightshow/filter.rs
··· 56 56 /// If the [`FilterType`] is `Unknown` then the result will be `true`. 57 57 /// # Panics 58 58 /// Will panic if the light id is greater than or equal to the group size. 59 - pub fn is_in_filter(&self, light_id: i32, group_size: i32) -> bool { 59 + pub fn is_in_filter(&self, mut light_id: i32, group_size: i32) -> bool { 60 60 assert!(light_id < group_size); 61 + 62 + if self.reverse.as_bool() { 63 + light_id = group_size - light_id - 1; 64 + } 65 + 61 66 match self.filter_type { 62 67 FilterType::Division => { 63 68 let start = self.parameter2 * group_size / self.parameter1.max(1); ··· 71 76 FilterType::Unknown(_) => true, 72 77 } 73 78 } 79 + 80 + /// Returns the number of lights effected by the filter. 81 + /// # Unknown 82 + /// If the [`FilterType`] is `Unknown` then the result will be the same as `group_size`. 83 + pub fn count_filtered(&self, group_size: i32) -> i32 { 84 + match self.filter_type { 85 + FilterType::Division => { 86 + let start = self.parameter2 * group_size / self.parameter1.max(1); 87 + let end = (self.parameter2 + 1) * group_size / self.parameter1.max(1); 88 + end - start 89 + } 90 + FilterType::StepAndOffset => { 91 + group_size / self.parameter2.max(1) - self.parameter1 / self.parameter2.max(1) 92 + } 93 + FilterType::Unknown(_) => group_size, 94 + } 95 + } 74 96 } 75 97 76 98 loose_enum! { ··· 100 122 use super::*; 101 123 102 124 #[test] 103 - fn is_in_filter_division_first_half() { 125 + fn division_first_half() { 104 126 let filter = Filter { 105 127 filter_type: FilterType::Division, 106 128 parameter1: 2, ··· 110 132 111 133 assert!((0..6).all(|i| filter.is_in_filter(i, 12))); 112 134 assert!((6..12).all(|i| !filter.is_in_filter(i, 12))); 135 + assert_eq!(filter.count_filtered(12), 6); 113 136 } 114 137 115 138 #[test] 116 - fn is_in_filter_division_second_half() { 139 + fn division_second_half() { 117 140 let filter = Filter { 118 141 filter_type: FilterType::Division, 119 142 parameter1: 2, ··· 123 146 124 147 assert!((0..6).all(|i| !filter.is_in_filter(i, 12))); 125 148 assert!((6..12).all(|i| filter.is_in_filter(i, 12))); 149 + assert_eq!(filter.count_filtered(12), 6); 126 150 } 127 151 128 152 #[test] 129 - fn is_in_filter_division_all() { 153 + fn division_first_half_rev() { 154 + let filter = Filter { 155 + filter_type: FilterType::Division, 156 + parameter1: 2, 157 + parameter2: 0, 158 + reverse: LooseBool::True, 159 + ..Default::default() 160 + }; 161 + 162 + assert!((0..6).all(|i| !filter.is_in_filter(i, 12))); 163 + assert!((6..12).all(|i| filter.is_in_filter(i, 12))); 164 + assert_eq!(filter.count_filtered(12), 6); 165 + } 166 + 167 + #[test] 168 + fn division_second_half_rev() { 169 + let filter = Filter { 170 + filter_type: FilterType::Division, 171 + parameter1: 2, 172 + parameter2: 1, 173 + reverse: LooseBool::True, 174 + ..Default::default() 175 + }; 176 + 177 + assert!((0..6).all(|i| filter.is_in_filter(i, 12))); 178 + assert!((6..12).all(|i| !filter.is_in_filter(i, 12))); 179 + assert_eq!(filter.count_filtered(12), 6); 180 + } 181 + 182 + #[test] 183 + fn division_select_all() { 130 184 let filter = Filter { 131 185 filter_type: FilterType::Division, 132 186 parameter1: 1, ··· 134 188 ..Default::default() 135 189 }; 136 190 137 - for i in 0..12 { 138 - assert_eq!(filter.is_in_filter(i, 12), true,); 139 - } 191 + assert!((0..12).all(|i| filter.is_in_filter(i, 12))); 192 + assert_eq!(filter.count_filtered(12), 12); 140 193 } 141 194 142 195 #[test] 143 - fn is_in_filter_step_all() { 196 + fn step_select_all() { 144 197 let filter = Filter { 145 198 filter_type: FilterType::StepAndOffset, 146 199 parameter1: 0, ··· 148 201 ..Default::default() 149 202 }; 150 203 151 - for i in 0..12 { 152 - assert_eq!(filter.is_in_filter(i, 12), true); 153 - } 204 + assert!((0..12).all(|i| filter.is_in_filter(i, 12))); 205 + assert_eq!(filter.count_filtered(12), 12); 154 206 } 155 207 156 208 #[test] 157 - fn is_in_filter_step_start_index() { 209 + fn step_start_index() { 158 210 for i in 0..12 { 159 211 let filter = Filter { 160 212 filter_type: FilterType::StepAndOffset, ··· 163 215 ..Default::default() 164 216 }; 165 217 assert!((i..12).all(|i| filter.is_in_filter(i, 12))); 218 + assert_eq!(filter.count_filtered(12), 12 - i); 166 219 } 167 220 } 168 221 169 222 #[test] 170 - fn is_in_filter_step_every_other() { 223 + fn step_every_other() { 171 224 let filter = Filter { 172 225 filter_type: FilterType::StepAndOffset, 173 226 parameter1: 0, ··· 178 231 for i in 0..12 { 179 232 assert_eq!(filter.is_in_filter(i, 12), i % 2 == 0); 180 233 } 234 + assert_eq!(filter.count_filtered(12), 6); 181 235 } 182 236 183 237 #[test] 184 - fn is_in_filter_step_every_other_offset() { 238 + fn step_every_other_offset() { 185 239 let filter = Filter { 186 240 filter_type: FilterType::StepAndOffset, 187 241 parameter1: 1, ··· 192 246 for i in 0..12 { 193 247 assert_eq!(filter.is_in_filter(i, 12), i % 2 != 0); 194 248 } 249 + assert_eq!(filter.count_filtered(12), 6); 195 250 } 196 251 }
+11
src/utils.rs
··· 124 124 True = 1, 125 125 } 126 126 } 127 + 128 + impl LooseBool { 129 + /// Returns as a bool, with unknown values counting as `false`. 130 + pub fn as_bool(&self) -> bool { 131 + match self { 132 + LooseBool::False => false, 133 + LooseBool::True => true, 134 + LooseBool::Unknown(_) => false, 135 + } 136 + } 137 + }