azalea_block/
block_state.rs1use std::{
2 fmt::{self, Debug},
3 io::{self, Cursor, Write},
4};
5
6use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
7
8use crate::Block;
9
10pub type BlockStateIntegerRepr = u16;
18
19#[derive(Copy, Clone, PartialEq, Eq, Default, Hash)]
27pub struct BlockState {
28 pub id: BlockStateIntegerRepr,
31}
32
33impl BlockState {
34 pub const AIR: BlockState = BlockState { id: 0 };
37
38 #[inline]
43 pub fn is_valid_state(state_id: BlockStateIntegerRepr) -> bool {
44 state_id <= Self::MAX_STATE
45 }
46
47 #[inline]
50 pub fn is_air(&self) -> bool {
51 self == &Self::AIR
52 }
53}
54
55impl TryFrom<u32> for BlockState {
56 type Error = ();
57
58 fn try_from(state_id: u32) -> Result<Self, Self::Error> {
60 let state_id = state_id as BlockStateIntegerRepr;
61 if Self::is_valid_state(state_id) {
62 Ok(BlockState { id: state_id })
63 } else {
64 Err(())
65 }
66 }
67}
68impl TryFrom<u16> for BlockState {
69 type Error = ();
70
71 fn try_from(state_id: u16) -> Result<Self, Self::Error> {
73 let state_id = state_id as BlockStateIntegerRepr;
74 if Self::is_valid_state(state_id) {
75 Ok(BlockState { id: state_id })
76 } else {
77 Err(())
78 }
79 }
80}
81
82impl AzaleaRead for BlockState {
83 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
84 let state_id = u32::azalea_read_var(buf)?;
85 Self::try_from(state_id).map_err(|_| BufReadError::UnexpectedEnumVariant {
86 id: state_id as i32,
87 })
88 }
89}
90impl AzaleaWrite for BlockState {
91 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), io::Error> {
92 u32::azalea_write_var(&(self.id as u32), buf)
93 }
94}
95
96impl Debug for BlockState {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 write!(
99 f,
100 "BlockState(id: {}, {:?})",
101 self.id,
102 Box::<dyn Block>::from(*self)
103 )
104 }
105}
106
107impl From<BlockState> for azalea_registry::Block {
108 fn from(value: BlockState) -> Self {
109 Box::<dyn Block>::from(value).as_registry_block()
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_from_u32() {
119 assert_eq!(
120 BlockState::try_from(0 as BlockStateIntegerRepr).unwrap(),
121 BlockState::AIR
122 );
123
124 assert!(BlockState::try_from(BlockState::MAX_STATE).is_ok());
125 assert!(BlockState::try_from(BlockState::MAX_STATE + 1).is_err());
126 }
127
128 #[test]
129 fn test_from_blockstate() {
130 let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::AIR);
131 assert_eq!(block.id(), "air");
132
133 let block: Box<dyn Block> =
134 Box::<dyn Block>::from(BlockState::from(azalea_registry::Block::FloweringAzalea));
135 assert_eq!(block.id(), "flowering_azalea");
136 }
137
138 #[test]
139 fn test_debug_blockstate() {
140 let formatted = format!(
141 "{:?}",
142 BlockState::from(azalea_registry::Block::FloweringAzalea)
143 );
144 assert!(formatted.ends_with(", FloweringAzalea)"), "{}", formatted);
145
146 let formatted = format!(
147 "{:?}",
148 BlockState::from(azalea_registry::Block::BigDripleafStem)
149 );
150 assert!(
151 formatted.ends_with(", BigDripleafStem { facing: North, waterlogged: false })"),
152 "{}",
153 formatted
154 );
155 }
156}