diff options
Diffstat (limited to 'azalea-block')
| -rw-r--r-- | azalea-block/block-macros/src/lib.rs | 12 | ||||
| -rw-r--r-- | azalea-block/src/lib.rs | 41 |
2 files changed, 53 insertions, 0 deletions
diff --git a/azalea-block/block-macros/src/lib.rs b/azalea-block/block-macros/src/lib.rs index d38062d4..6206bb65 100644 --- a/azalea-block/block-macros/src/lib.rs +++ b/azalea-block/block-macros/src/lib.rs @@ -461,9 +461,12 @@ pub fn make_block_states(input: TokenStream) -> TokenStream { block_structs.extend(block_struct); } + let last_state_id = (state_id - 1) as u32; quote! { #property_enums + #[repr(u32)] + #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum BlockState { #block_state_enum_variants } @@ -479,6 +482,15 @@ pub fn make_block_states(input: TokenStream) -> TokenStream { } } } + + impl BlockState { + /// Returns the highest possible state + #[inline] + pub fn max_state() -> u32 { + #last_state_id + } + } + } .into() } diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs index 01c86b11..95e8ce37 100644 --- a/azalea-block/src/lib.rs +++ b/azalea-block/src/lib.rs @@ -4,3 +4,44 @@ mod blocks; pub use behavior::BlockBehavior; pub use blocks::*; +use std::mem; + +impl BlockState { + /// Transmutes a u32 to a block state. UB if the value is not a valid block + /// state. + #[inline] + pub unsafe fn from_u32_unsafe(state_id: u32) -> Self { + mem::transmute::<u32, BlockState>(state_id) + } + + #[inline] + pub fn is_valid_state(state_id: u32) -> bool { + state_id <= Self::max_state() + } +} + +impl TryFrom<u32> for BlockState { + type Error = (); + + /// Safely converts a state id to a block state. + fn try_from(state_id: u32) -> Result<Self, Self::Error> { + if Self::is_valid_state(state_id) { + Ok(unsafe { Self::from_u32_unsafe(state_id) }) + } else { + Err(()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_from_u32() { + assert_eq!(BlockState::try_from(0).unwrap(), BlockState::Air); + + assert!(BlockState::try_from(BlockState::max_state()).is_ok()); + assert!(BlockState::try_from(BlockState::max_state() + 1).is_err()); + } +} |
