Skip to main content

yog_api/mirror/
traits.rs

1//! A block's traits as a block mirror writes them (`ClientBlocks::traits`):
2//! a bit each, the bit its place in `yog_ids::block_trait`.
3
4use yog_ids::block_trait;
5
6/// A set of block traits.
7#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
8pub struct BlockTraits(pub u64);
9
10/// `name`'s bit: its place in `block_trait`'s list.
11const fn bit(name: &str) -> u64 {
12    let all = block_trait::ALL_VALUES;
13    let mut i = 0;
14    while i < all.len() {
15        if eq(all[i], name) {
16            return 1 << i;
17        }
18        i += 1;
19    }
20    panic!("not a block trait")
21}
22
23const fn eq(a: &str, b: &str) -> bool {
24    let (a, b) = (a.as_bytes(), b.as_bytes());
25    if a.len() != b.len() {
26        return false;
27    }
28    let mut i = 0;
29    while i < a.len() {
30        if a[i] != b[i] {
31            return false;
32        }
33        i += 1;
34    }
35    true
36}
37
38macro_rules! traits {
39    ($($name:ident),* $(,)?) => {
40        impl BlockTraits {
41            $(
42                #[doc = concat!("`block_trait::", stringify!($name), "`.")]
43                pub const $name: BlockTraits = BlockTraits(bit(block_trait::$name));
44            )*
45            /// How many there are (each of `block_trait`'s).
46            #[cfg(test)]
47            pub(crate) const COUNT: usize = [$(stringify!($name)),*].len();
48        }
49    };
50}
51
52traits!(
53    AIR,
54    SOLID,
55    FULL,
56    LIQUID,
57    WATER,
58    LAVA,
59    SOURCE,
60    FLUID_BLOCK,
61    CLIMBABLE,
62    HARMFUL,
63    FALLS,
64    PATHFINDABLE,
65    REPLACEABLE,
66    STURDY_TOP,
67    FIRE,
68    SLAB,
69    STAIRS,
70    DOOR,
71    WOODEN_DOOR,
72    FENCE_GATE,
73    TRAPDOOR,
74    FENCE,
75    WALL,
76    CARPET,
77    SNOW_LAYER,
78    SKULL,
79    SHULKER_BOX,
80    LEAVES,
81    INFESTED,
82    CAULDRON,
83    AZALEA,
84    AMETHYST_CLUSTER,
85    POINTED_DRIPSTONE,
86    BAMBOO,
87    MOVING_PISTON,
88    SCAFFOLDING,
89    CHEST,
90    GLASS,
91);
92
93impl BlockTraits {
94    /// Whether every one of `t` is among these.
95    #[inline]
96    pub const fn has(self, t: BlockTraits) -> bool {
97        self.0 & t.0 == t.0
98    }
99
100    /// Whether any of `t` is among these.
101    #[inline]
102    pub const fn any(self, t: BlockTraits) -> bool {
103        self.0 & t.0 != 0
104    }
105}
106
107impl std::ops::BitOr for BlockTraits {
108    type Output = BlockTraits;
109
110    fn bitor(self, o: BlockTraits) -> BlockTraits {
111        BlockTraits(self.0 | o.0)
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn every_trait_has_its_bit() {
121        assert_eq!(BlockTraits::COUNT, block_trait::ALL_VALUES.len());
122        assert_eq!(BlockTraits::AIR.0, 1);
123        assert_eq!(BlockTraits::GLASS.0, 1 << (block_trait::ALL_VALUES.len() - 1));
124        assert!((BlockTraits::SLAB | BlockTraits::WATER).has(BlockTraits::SLAB));
125    }
126}