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::BlockTrait;
9
10pub type BlockStateIntegerRepr = u16;
18
19#[derive(Copy, Clone, PartialEq, Eq, Default, Hash)]
27pub struct BlockState {
28 id: BlockStateIntegerRepr,
29}
30
31impl BlockState {
32 pub const AIR: BlockState = BlockState { id: 0 };
37
38 #[inline]
42 pub(crate) const fn new_const(id: BlockStateIntegerRepr) -> Self {
43 assert!(Self::is_valid_state(id));
44 Self { id }
45 }
46
47 #[inline]
52 pub const fn is_valid_state(state_id: BlockStateIntegerRepr) -> bool {
53 state_id <= Self::MAX_STATE
54 }
55
56 #[inline]
60 pub fn is_air(&self) -> bool {
61 self == &Self::AIR
62 }
63
64 #[inline]
69 pub const fn id(&self) -> BlockStateIntegerRepr {
70 self.id
71 }
72}
73
74impl TryFrom<u32> for BlockState {
75 type Error = ();
76
77 fn try_from(state_id: u32) -> Result<Self, Self::Error> {
79 let state_id = state_id as BlockStateIntegerRepr;
80 if Self::is_valid_state(state_id) {
81 Ok(BlockState { id: state_id })
82 } else {
83 Err(())
84 }
85 }
86}
87impl TryFrom<u16> for BlockState {
88 type Error = ();
89
90 fn try_from(state_id: u16) -> Result<Self, Self::Error> {
92 let state_id = state_id as BlockStateIntegerRepr;
93 if Self::is_valid_state(state_id) {
94 Ok(BlockState { id: state_id })
95 } else {
96 Err(())
97 }
98 }
99}
100impl From<BlockState> for u32 {
101 fn from(value: BlockState) -> Self {
103 value.id as u32
104 }
105}
106
107impl AzaleaRead for BlockState {
108 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
109 let state_id = u32::azalea_read_var(buf)?;
110 Self::try_from(state_id).map_err(|_| BufReadError::UnexpectedEnumVariant {
111 id: state_id as i32,
112 })
113 }
114}
115impl AzaleaWrite for BlockState {
116 fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
117 u32::azalea_write_var(&(self.id as u32), buf)
118 }
119}
120
121impl Debug for BlockState {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(
124 f,
125 "BlockState(id: {}, {:?})",
126 self.id,
127 Box::<dyn BlockTrait>::from(*self)
128 )
129 }
130}
131
132impl From<BlockState> for azalea_registry::Block {
133 fn from(value: BlockState) -> Self {
134 Box::<dyn BlockTrait>::from(value).as_registry_block()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_from_u32() {
144 assert_eq!(
145 BlockState::try_from(0 as BlockStateIntegerRepr).unwrap(),
146 BlockState::AIR
147 );
148
149 assert!(BlockState::try_from(BlockState::MAX_STATE).is_ok());
150 assert!(BlockState::try_from(BlockState::MAX_STATE + 1).is_err());
151 }
152
153 #[test]
154 fn test_from_blockstate() {
155 let block: Box<dyn BlockTrait> = Box::<dyn BlockTrait>::from(BlockState::AIR);
156 assert_eq!(block.id(), "air");
157
158 let block: Box<dyn BlockTrait> =
159 Box::<dyn BlockTrait>::from(BlockState::from(azalea_registry::Block::FloweringAzalea));
160 assert_eq!(block.id(), "flowering_azalea");
161 }
162
163 #[test]
164 fn test_debug_blockstate() {
165 let formatted = format!(
166 "{:?}",
167 BlockState::from(azalea_registry::Block::FloweringAzalea)
168 );
169 assert!(formatted.ends_with(", FloweringAzalea)"), "{}", formatted);
170
171 let formatted = format!(
172 "{:?}",
173 BlockState::from(azalea_registry::Block::BigDripleafStem)
174 );
175 assert!(
176 formatted.ends_with(", BigDripleafStem { facing: North, waterlogged: false })"),
177 "{}",
178 formatted
179 );
180 }
181}