#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct ItemCategoryMask(pub u32);
impl ItemCategoryMask {
pub const CUSTOMIZATION: Self = Self(1 << 0);
pub const EQUIPMENT: Self = Self(1 << 1);
pub const WEAPONS: Self = Self(1 << 2);
pub const TOOLS: Self = Self(1 << 3);
pub const INSTRUMENT: Self = Self(1 << 4);
pub const FISHING_ROD: Self = Self(1 << 5);
pub const BUILD_TOOLS: Self = Self(1 << 6);
pub const CONSUMABLES: Self = Self(1 << 7);
pub const AMMUNITION: Self = Self(1 << 8);
pub const MATERIALS: Self = Self(1 << 9);
pub const BLUEPRINTS: Self = Self(1 << 10);
pub const CURRENCY: Self = Self(1 << 11);
pub const COLLECTIBLES: Self = Self(1 << 12);
pub const ANIMAL_FOOD: Self = Self(1 << 13);
pub const PET_FOOD: Self = Self(1 << 14);
pub const WEAPON_GEM: Self = Self(1 << 15);
pub const COLOR_PALETTE: Self = Self(1 << 16);
pub const NAMES: &[(&str, Self)] = &[
("Customization", Self::CUSTOMIZATION),
("Equipment", Self::EQUIPMENT),
("Weapons", Self::WEAPONS),
("Tools", Self::TOOLS),
("Instrument", Self::INSTRUMENT),
("FishingRod", Self::FISHING_ROD),
("BuildTools", Self::BUILD_TOOLS),
("Consumables", Self::CONSUMABLES),
("Ammunition", Self::AMMUNITION),
("Materials", Self::MATERIALS),
("Blueprints", Self::BLUEPRINTS),
("Currency", Self::CURRENCY),
("Collectibles", Self::COLLECTIBLES),
("AnimalFood", Self::ANIMAL_FOOD),
("PetFood", Self::PET_FOOD),
("WeaponGem", Self::WEAPON_GEM),
("ColorPalette", Self::COLOR_PALETTE),
];
#[must_use]
pub fn named(name: &str) -> Option<Self> {
Self::NAMES
.iter()
.find(|(game, _)| *game == name)
.map(|&(_, mask)| mask)
}
#[must_use]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[must_use]
pub const fn holds(self, category: u8) -> bool {
category < 32 && self.0 & (1 << category) != 0
}
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
impl core::ops::BitOr for ItemCategoryMask {
type Output = Self;
fn bitor(self, other: Self) -> Self {
self.union(other)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_category_is_found_by_the_game_s_name_and_one_bit() {
for &(name, mask) in ItemCategoryMask::NAMES {
assert_eq!(ItemCategoryMask::named(name), Some(mask));
assert_eq!(mask.0.count_ones(), 1, "{name}");
}
assert_eq!(ItemCategoryMask::named("Material"), None);
}
}