azalea_registry/tags/
mod.rs

1use std::{collections::HashSet, ops::Deref};
2
3use crate::Registry;
4
5pub mod blocks;
6pub mod entities;
7pub mod fluids;
8pub mod items;
9
10/// A set of registry items.
11#[derive(Clone, Debug)]
12pub struct RegistryTag<R: Registry + 'static> {
13    // yes, this *could* be a Box<[R]>, but there are cases in which the user may want to cheaply
14    // mutate this.
15    // yes, it could also be a [R; N] using a const generic, but that makes RegistryTag annoying if
16    // the user wants to put it in their own code.
17    // yes, if the aforementioned issues are ignored then we could even avoid a LazyLock. but that
18    // would provide nearly no benefit and result in wasted memory for unused tags.
19    // having it be a vec is fine.
20    entries: Vec<R>,
21}
22impl<R: Registry + 'static> RegistryTag<R> {
23    pub(crate) fn new(entries: Vec<R>) -> Self {
24        // must be sorted for binary search
25        debug_assert!(entries.is_sorted());
26
27        Self { entries }
28    }
29}
30impl<R: Registry + 'static> RegistryTag<R> {
31    /// Returns whether the given item is contained in this registry.
32    pub fn contains(&self, value: &R) -> bool {
33        self.find(value).is_some()
34    }
35
36    pub fn remove(&mut self, value: &R) -> Option<R> {
37        self.find(value).map(|index| self.entries.remove(index))
38    }
39
40    fn find(&self, value: &R) -> Option<usize> {
41        // TODO: tune this number; when does binary search actually start making a
42        // difference?
43        if self.entries.len() > 64 {
44            self.linear_search_find(value)
45        } else {
46            self.binary_search_find(value)
47        }
48    }
49    fn linear_search_find(&self, value: &R) -> Option<usize> {
50        self.entries.iter().position(|e| e == value)
51    }
52    fn binary_search_find(&self, value: &R) -> Option<usize> {
53        self.entries.binary_search(value).ok()
54    }
55
56    // this exists for convenience since we can't always do HashSet::from if it's a
57    // LazyLock
58    pub fn into_hashset(&self) -> HashSet<R> {
59        self.clone().into_iter().collect()
60    }
61}
62impl<R: Registry> IntoIterator for RegistryTag<R> {
63    type Item = R;
64
65    type IntoIter = std::vec::IntoIter<R>;
66
67    fn into_iter(self) -> Self::IntoIter {
68        self.entries.into_iter()
69    }
70}
71
72impl<R: Registry> From<RegistryTag<R>> for HashSet<R> {
73    fn from(tag: RegistryTag<R>) -> Self {
74        tag.into_hashset()
75    }
76}
77
78impl<R: Registry> Deref for RegistryTag<R> {
79    type Target = [R];
80
81    fn deref(&self) -> &Self::Target {
82        &self.entries
83    }
84}
85
86impl<R: Registry> FromIterator<R> for RegistryTag<R> {
87    fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
88        let mut entries = iter.into_iter().collect::<Vec<_>>();
89        entries.sort();
90        Self::new(entries)
91    }
92}