1use std::fmt::{Debug, Formatter, Result as FmtResult};
2use std::collections::HashMap;
3use std::ptr::NonNull;
4
5use super::{Block, UntypedProperty, Property, PropertySerializable};
6use crate::util::OpaquePtr;
7
8
9pub const MAX_STATES_COUNT: usize = 0x10000;
11
12
13#[derive(Debug)]
14pub(crate) struct SharedProperty {
15 prop: &'static dyn UntypedProperty,
16 index: usize,
17 length: u8,
18 period: usize
19}
20
21
22pub struct BlockState {
28 index: u16,
30 properties: Vec<u8>,
32 block: NonNull<Block>
34}
35
36pub type BlockStateKey = OpaquePtr<BlockState>;
37
38unsafe impl Send for BlockState {}
39unsafe impl Sync for BlockState {}
40
41
42impl BlockState {
43
44 pub(crate) fn build_singleton() -> BlockState {
45 BlockState {
46 index: 0,
47 properties: Vec::new(),
48 block: NonNull::dangling()
49 }
50 }
51
52 pub(crate) fn build_complex(properties: &[&'static dyn UntypedProperty]) -> (HashMap<&'static str, SharedProperty>, Vec<BlockState>) {
53
54 debug_assert!(!properties.is_empty(), "building complex states without properties is not allowed");
55
56 let mut states_count = 1;
57 let mut properties_periods = Vec::with_capacity(properties.len());
58
59 for &prop in properties {
60 let length = prop.len();
61 states_count *= length as usize;
62 properties_periods.push((prop, length, 1usize));
63 }
64
65 if states_count > MAX_STATES_COUNT {
66 panic!("Too many properties for this state, the maximum number is {}.", MAX_STATES_COUNT);
67 }
68
69 let mut shared_properties = HashMap::with_capacity(properties.len());
70
71 let mut next_period = 1;
72 for (i, (prop, length, period)) in properties_periods.iter_mut().enumerate().rev() {
73 let prop = *prop;
74 *period = next_period;
75 next_period *= *length as usize;
76 shared_properties.insert(prop.name(), SharedProperty {
77 prop,
78 index: i,
79 length: *length,
80 period: *period
81 });
82 }
83
84 let mut shared_states = Vec::with_capacity(states_count);
85
86 for i in 0..states_count {
87
88 let mut state_properties = Vec::with_capacity(properties.len());
89 for (_, length, period) in &properties_periods {
90 state_properties.push(((i / *period) % (*length as usize)) as u8);
91 }
92
93 shared_states.push(BlockState {
94 index: i as u16,
95 properties: state_properties,
96 block: NonNull::dangling()
97 });
98
99 }
100
101 (shared_properties, shared_states)
102
103 }
104
105 #[inline]
106 pub fn get_index(&self) -> u16 {
107 self.index
108 }
109
110 #[inline]
111 pub fn get_key(&'static self) -> BlockStateKey {
112 OpaquePtr::new(self)
113 }
114
115 #[inline]
116 pub fn get_block(&self) -> &'static Block {
117 unsafe { self.block.as_ref() }
121 }
122
123 #[inline]
125 pub(super) fn set_block(&mut self, block: NonNull<Block>) {
126 self.block = block;
128 }
129
130 #[inline]
131 pub fn is_block(&self, block: &'static Block) -> bool {
132 self.get_block() == block
133 }
134
135 #[inline]
136 fn get_block_shared_prop(&self, name: &str) -> Option<&SharedProperty> {
137 self.get_block().get_storage().get_shared_prop(name)
138 }
139
140 pub fn get<T, P>(&self, property: &P) -> Option<T>
142 where
143 T: PropertySerializable,
144 P: Property<T>
145 {
146
147 let prop = self.get_block_shared_prop(&property.name())?;
148 if prop.prop.type_id() == property.type_id() {
149 property.decode(self.properties[prop.index])
150 } else {
151 None
152 }
153
154 }
155
156 pub fn expect<T, P>(&self, property: &P) -> T
157 where
158 T: PropertySerializable,
159 P: Property<T>
160 {
161 self.get(property).unwrap()
162 }
163
164 pub fn with<T, P>(&self, property: &P, value: T) -> Option<&BlockState>
167 where
168 T: PropertySerializable,
169 P: Property<T>
170 {
171 let prop = self.get_block_shared_prop(&property.name())?;
172 self.with_unchecked(prop, property.encode(value)?)
173 }
174
175 pub fn with_raw(&self, prop_name: &str, prop_value: &str) -> Option<&BlockState> {
180 let prop = self.get_block_shared_prop(prop_name)?;
181 self.with_unchecked(prop, prop.prop.prop_from_string(prop_value)?)
182 }
183
184 #[inline]
185 fn with_unchecked(&self, prop: &SharedProperty, prop_value: u8) -> Option<&BlockState> {
186
187 let new_value = prop_value as isize;
188 let current_value = self.properties[prop.index] as isize;
189
190 Some(if new_value == current_value {
191 self
192 } else {
193 let value_diff = new_value - current_value;
194 let neighbor_index = (self.index as isize + value_diff * prop.period as isize) as usize;
195 self.get_block().get_storage().get_state_unchecked(neighbor_index)
196 })
197
198 }
199
200 pub fn iter_raw_states<'a>(&'a self) -> Option<impl Iterator<Item = (&'static str, String)> + 'a> {
203 self.get_block().get_storage().get_shared_props().map(move |props| {
204 props.iter().map(move |(&name, shared)| {
205 let raw_value = self.properties[shared.index];
206 (name, shared.prop.prop_to_string(raw_value).unwrap())
207 })
208 })
209 }
210
211}
212
213
214impl PartialEq for &'static BlockState {
216 fn eq(&self, other: &Self) -> bool {
217 std::ptr::eq(*self, *other)
218 }
219}
220
221impl Eq for &'static BlockState {}
222
223
224impl Debug for BlockState {
225
226 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
227
228 let reprs = match self.iter_raw_states() {
229 Some(it) => it.collect(),
230 None => Vec::with_capacity(0)
231 };
232
233 f.debug_struct("BlockState")
234 .field("block", &self.get_block().get_name())
235 .field("index", &self.index)
236 .field("properties", &reprs)
237 .field("raw_properties", &self.properties)
238 .finish()
239
240 }
241
242}