1use std::collections::HashMap;
2use std::ptr::NonNull;
3use std::fmt::Debug;
4
5use once_cell::sync::OnceCell;
6use bit_vec::BitVec;
7
8use crate::tag::{TagType, TagTypeKey};
9use crate::util::OpaquePtr;
10
11mod state;
12mod property;
13mod util;
14
15pub use state::*;
16pub use property::*;
17pub use util::*;
18
19
20#[derive(Debug)]
24pub struct Block {
25 name: &'static str,
26 spec: BlockSpec,
27 states: OnceCell<BlockStorage>,
28}
29
30
31pub type BlockKey = OpaquePtr<Block>;
34
35
36#[derive(Debug)]
39enum BlockStorage {
40 Single(BlockState),
42 Complex {
46 states: Vec<BlockState>,
47 properties: HashMap<&'static str, SharedProperty>,
48 default_state_index: usize
49 }
50}
51
52
53#[derive(Debug)]
55pub enum BlockSpec {
56 Single,
58 Complex(&'static [&'static dyn UntypedProperty]),
61 }
64
65
66impl Block {
67
68 pub const fn new(name: &'static str, spec: BlockSpec) -> Self {
71 Self {
72 name,
73 spec,
74 states: OnceCell::new()
75 }
76 }
77
78 #[inline]
79 pub fn get_name(&self) -> &'static str {
80 self.name
81 }
82
83 #[inline]
84 pub fn get_key(&'static self) -> BlockKey {
85 OpaquePtr::new(self)
86 }
87
88 fn get_storage(&'static self) -> &'static BlockStorage {
89 self.states.get_or_init(|| self.make_storage())
90 }
91
92 fn make_storage(&'static self) -> BlockStorage {
93
94 fn new_storage(properties: &'static [&'static dyn UntypedProperty]) -> BlockStorage {
97 if properties.is_empty() {
98 BlockStorage::Single(BlockState::build_singleton())
99 } else {
100
101 let (
102 properties,
103 states
104 ) = BlockState::build_complex(properties);
105
106 BlockStorage::Complex {
107 states,
108 properties,
109 default_state_index: 0
110 }
111
112 }
113 }
114
115 let mut storage = match self.spec {
118 BlockSpec::Single => BlockStorage::Single(BlockState::build_singleton()),
119 BlockSpec::Complex(properties) => new_storage(properties),
120 };
125
126 let block_ptr = NonNull::from(self);
127
128 match &mut storage {
129 BlockStorage::Single( state) => {
130 state.set_block(block_ptr);
131 },
132 BlockStorage::Complex {
133 states,
134 ..
135 } => {
136 for state in states {
137 state.set_block(block_ptr);
138 }
139 }
143 }
144
145 storage
146
147 }
148
149 #[inline]
150 pub fn get_default_state(&'static self) -> &'static BlockState {
151 self.get_storage().get_default_state()
152 }
153
154 #[inline]
155 pub fn get_states(&'static self) -> &'static [BlockState] {
156 self.get_storage().get_states()
157 }
158
159}
160
161
162impl PartialEq for &'static Block {
163 fn eq(&self, other: &Self) -> bool {
164 std::ptr::eq(*self, *other)
165 }
166}
167
168impl Eq for &'static Block {}
169
170
171impl BlockStorage {
172
173 pub fn get_default_state(&self) -> &BlockState {
174 match self {
175 BlockStorage::Single(state) => state,
176 BlockStorage::Complex {
177 states,
178 default_state_index, ..
179 } => &states[*default_state_index]
180 }
181 }
182
183 pub fn get_states(&self) -> &[BlockState] {
184 match self {
185 BlockStorage::Single(state) => std::slice::from_ref(state),
186 BlockStorage::Complex { states, .. } => &states[..]
187 }
188 }
189
190 fn get_shared_prop(&self, name: &str) -> Option<&SharedProperty> {
192 match self {
193 BlockStorage::Single(_) => None,
194 BlockStorage::Complex {
195 properties, ..
196 } => properties.get(name)
197 }
198 }
199
200 fn get_shared_props(&self) -> Option<&HashMap<&'static str, SharedProperty>> {
203 match self {
204 BlockStorage::Single(_) => None,
205 BlockStorage::Complex {
206 properties, ..
207 } => Some(properties)
208 }
209 }
210
211 fn get_state_unchecked(&self, index: usize) -> &BlockState {
213 match self {
214 BlockStorage::Single(state) => {
215 debug_assert!(index == 0, "index != 0 with BlockStorage::Single");
216 state
217 },
218 BlockStorage::Complex { states, .. } => &states[index]
219 }
220 }
221
222}
223
224
225pub struct GlobalBlocks {
229 next_sid: u32,
230 block_to_indices: HashMap<BlockKey, (usize, u32)>,
233 ordered_states: Vec<&'static BlockState>,
236 name_to_blocks: HashMap<&'static str, &'static Block>,
238 tag_stores: HashMap<TagTypeKey, TagStore>
240}
241
242impl GlobalBlocks {
243
244 pub fn new() -> Self {
245 Self {
246 next_sid: 0,
247 block_to_indices: HashMap::new(),
248 ordered_states: Vec::new(),
249 name_to_blocks: HashMap::new(),
250 tag_stores: HashMap::new()
251 }
252 }
253
254 pub fn with_all(slice: &[&'static Block]) -> Result<Self, ()> {
256 let mut blocks = Self::new();
257 blocks.register_all(slice)?;
258 Ok(blocks)
259 }
260
261 pub fn register(&mut self, block: &'static Block) -> Result<(), ()> {
265
266 let states = block.get_states();
267 let states_count = states.len();
268
269 let sid = self.next_sid;
270 let idx = self.block_to_indices.len();
271 let next_sid = sid.checked_add(states_count as u32).ok_or(())?;
272
273 for store in self.tag_stores.values_mut() {
274 if let TagStore::Big(store) = store {
275 store.push(false);
276 }
277 }
278
279 if self.block_to_indices.insert(block.get_key(), (idx, sid)).is_none() {
280
281 self.next_sid = next_sid;
282
283 self.name_to_blocks.insert(block.name, block);
284 self.ordered_states.reserve(states_count);
285 for state in states {
286 self.ordered_states.push(state);
287 }
288
289 }
290
291 Ok(())
292
293 }
294
295 pub fn register_all(&mut self, slice: &[&'static Block]) -> Result<(), ()> {
299 let count = slice.len();
300 self.block_to_indices.reserve(count);
301 self.name_to_blocks.reserve(count);
302 for store in self.tag_stores.values_mut() {
303 if let TagStore::Big(store) = store {
304 store.reserve(count);
305 }
306 }
307 for &block in slice {
308 self.register(block)?;
309 }
310 Ok(())
311 }
312
313 pub fn get_sid_from(&self, state: &'static BlockState) -> Option<u32> {
315 let (_, block_offset) = *self.block_to_indices.get(&state.get_block().get_key())?;
316 Some(block_offset + state.get_index() as u32)
317 }
318
319 pub fn get_state_from(&self, sid: u32) -> Option<&'static BlockState> {
321 self.ordered_states.get(sid as usize).copied()
322 }
323
324 pub fn get_block_from_name(&self, name: &str) -> Option<&'static Block> {
326 self.name_to_blocks.get(name).cloned()
327 }
328
329 pub fn has_block(&self, block: &'static Block) -> bool {
331 self.block_to_indices.contains_key(&block.get_key())
332 }
333
334 pub fn has_state(&self, state: &'static BlockState) -> bool {
336 self.has_block(state.get_block())
337 }
338
339 pub fn check_state<E>(&self, state: &'static BlockState, err: impl FnOnce() -> E) -> Result<&'static BlockState, E> {
342 if self.has_state(state) { Ok(state) } else { Err(err()) }
343 }
344
345 pub fn register_tag_type(&mut self, tag_type: &'static TagType) {
347 self.tag_stores.insert(tag_type.get_key(), TagStore::Small(Vec::new()));
348 }
349
350 pub fn set_blocks_tag<I>(&mut self, tag_type: &'static TagType, enabled: bool, blocks: I) -> Result<(), ()>
352 where
353 I: IntoIterator<Item = &'static Block>
354 {
355
356 const MAX_SMALL_LEN: usize = 8;
357
358 let store = self.tag_stores.get_mut(&tag_type.get_key()).ok_or(())?;
359
360 for block in blocks {
361
362 if let TagStore::Small(vec) = store {
363 let idx = vec.iter().position(move |&b| b == block);
364 if enabled {
365 if idx.is_none() {
366 if vec.len() >= MAX_SMALL_LEN {
367 let mut new_vec = BitVec::from_elem(self.block_to_indices.len(), false);
369 for old_block in vec {
370 let (idx, _) = *self.block_to_indices.get(&old_block.get_key()).ok_or(())?;
371 new_vec.set(idx, true);
372 }
373 *store = TagStore::Big(new_vec);
374 } else {
375 vec.push(block);
376 }
377 }
378 } else if let Some(idx) = idx {
379 vec.swap_remove(idx);
380 }
381 }
382
383 if let TagStore::Big(vec) = store {
384 let (idx, _) = *self.block_to_indices.get(&block.get_key()).ok_or(())?;
385 vec.set(idx, enabled);
386 }
387
388 }
389
390 Ok(())
391
392 }
393
394 pub fn has_block_tag(&self, block: &'static Block, tag_type: &'static TagType) -> bool {
396 match self.tag_stores.get(&tag_type.get_key()) {
397 None => false,
398 Some(store) => {
399 match store {
400 TagStore::Small(vec) => vec.iter().any(move |&b| b == block),
401 TagStore::Big(vec) => match self.block_to_indices.get(&block.get_key()) {
402 None => false,
403 Some(&(idx, _)) => vec.get(idx).unwrap()
404 }
405 }
406 }
407 }
408 }
409
410 pub fn blocks_count(&self) -> usize {
411 self.block_to_indices.len()
412 }
413
414 pub fn states_count(&self) -> usize {
415 self.ordered_states.len()
416 }
417
418 pub fn tags_count(&self) -> usize {
419 self.tag_stores.len()
420 }
421
422}
423
424#[derive(Debug)]
425enum TagStore {
426 Small(Vec<&'static Block>),
427 Big(BitVec)
428}
429
430#[macro_export]
431macro_rules! blocks_specs {
432 ($($v:vis $id:ident: [$($prop_const:ident),+];)*) => {
433 $(
434 $v static $id: [&'static dyn $crate::block::UntypedProperty; $crate::count!($($prop_const)+)] = [
435 $(&$prop_const),+
436 ];
437 )*
438 };
439}
440
441#[macro_export]
442macro_rules! blocks {
443 ($global_vis:vis $static_id:ident $namespace:literal [
444 $($block_id:ident $block_name:literal $($spec_id:ident)?),*
445 $(,)?
446 ]) => {
447
448 $($global_vis static $block_id: $crate::block::Block = $crate::block::Block::new(
449 concat!($namespace, ':', $block_name),
450 $crate::_blocks_spec!($($spec_id)?)
451 );)*
452
453 $global_vis static $static_id: [&'static $crate::block::Block; $crate::count!($($block_id)*)] = [
454 $(&$block_id),*
455 ];
456
457 };
458}
459
460#[macro_export]
461macro_rules! _blocks_spec {
462 () => { $crate::block::BlockSpec::Single };
463 ($spec_id:ident) => { $crate::block::BlockSpec::Complex(&$spec_id) }
464}