1#[macro_export]
5macro_rules! impl_registry_ext {
6 ($Registry:ty, $Entry:ty, $id_field:ident, $key_field:ident) => {
7 impl $crate::RegistryExt for $Registry {
8 type Entry = $Entry;
9
10 fn freeze(&mut self) {
11 self.allows_registering = false;
12 }
13
14 fn by_id(&self, id: usize) -> Option<&'static $Entry> {
15 self.$id_field.get(id).copied()
16 }
17
18 fn by_key(&self, key: &steel_utils::Identifier) -> Option<&'static $Entry> {
19 self.$key_field
20 .get(key)
21 .and_then(|&id| self.$id_field.get(id).copied())
22 }
23
24 fn id_from_key(&self, key: &steel_utils::Identifier) -> Option<usize> {
25 self.$key_field.get(key).copied()
26 }
27
28 fn len(&self) -> usize {
29 self.$id_field.len()
30 }
31
32 fn is_empty(&self) -> bool {
33 self.$id_field.is_empty()
34 }
35 }
36 };
37}
38
39#[macro_export]
41macro_rules! impl_registry_entry_eq {
42 ($Entry:ty) => {
43 impl ::core::cmp::PartialEq for $Entry {
44 fn eq(&self, other: &Self) -> bool {
45 self.key == other.key
46 }
47 }
48
49 impl ::core::cmp::Eq for $Entry {}
50 };
51}
52
53#[macro_export]
55macro_rules! impl_registry_entry {
56 ($Entry:ty, $global_field:ident) => {
57 $crate::impl_registry_entry_eq!($Entry);
58
59 impl $crate::RegistryEntry for $Entry {
60 fn key(&self) -> &steel_utils::Identifier {
61 &self.key
62 }
63
64 fn try_id(&self) -> Option<usize> {
65 use $crate::RegistryExt;
66 $crate::REGISTRY.$global_field.id_from_key(&self.key)
67 }
68 }
69 };
70}
71
72#[macro_export]
77macro_rules! impl_standard_methods {
78 (
79 $Registry:ty,
80 $Entry:ty,
81 $id_field:ident,
82 $key_field:ident,
83 $allow_registering:ident
84 $(, $duplicate_key_error:literal)?
85 ) => {
86 impl $Registry {
87 pub fn register(&mut self, entry: $Entry) -> usize {
88 assert!(
89 self.$allow_registering,
90 concat!(
91 "Cannot register ",
92 stringify!($Entry),
93 " after registry has been frozen"
94 )
95 );
96 $(
97 assert!(
98 !self.$key_field.contains_key(&entry.key),
99 $duplicate_key_error,
100 entry.key
101 );
102 )?
103 let id = self.$id_field.len();
104 self.$id_field.push(entry);
105 self.$key_field.insert(entry.key.clone(), id);
106 id
107 }
108
109 pub fn iter(&self) -> impl Iterator<Item = (usize, $Entry)> + '_ {
110 self.$id_field
111 .iter()
112 .enumerate()
113 .map(|(id, &entry)| (id, entry))
114 }
115 }
116
117 impl Default for $Registry {
118 fn default() -> Self {
119 Self::new()
120 }
121 }
122 };
123}
124
125#[macro_export]
127macro_rules! impl_registry {
128 ($Registry:ty, $Entry:ty, $id_field:ident, $key_field:ident, $global_field:ident) => {
129 $crate::impl_registry_ext!($Registry, $Entry, $id_field, $key_field);
130 $crate::impl_registry_entry!($Entry, $global_field);
131 };
132}
133
134#[macro_export]
136macro_rules! impl_tagged_registry {
137 ($Registry:ty, $key_field:ident, $entity_name:literal) => {
138 impl $crate::TaggedRegistryExt for $Registry {
139 fn register_tag(&mut self, tag: steel_utils::Identifier, keys: &[&'static str]) {
140 assert!(
141 self.allows_registering,
142 "Cannot register tags after registry has been frozen"
143 );
144
145 let entry_keys = keys
146 .iter()
147 .filter_map(|key| {
148 let ident = steel_utils::registry::registry_vanilla_or_custom_tag(key);
149 $crate::RegistryExt::by_key(self, &ident).map($crate::RegistryEntry::key)
150 })
151 .collect();
152
153 self.tags.insert(tag, entry_keys);
154 }
155
156 fn modify_tag(
157 &mut self,
158 tag: &steel_utils::Identifier,
159 f: impl FnOnce(Vec<steel_utils::Identifier>) -> Vec<steel_utils::Identifier>,
160 ) {
161 let existing = self
162 .tags
163 .remove(tag)
164 .unwrap_or_default()
165 .into_iter()
166 .cloned()
167 .collect();
168 let entry_keys = f(existing)
169 .into_iter()
170 .filter_map(|key| {
171 let Some(entry) = $crate::RegistryExt::by_key(self, &key) else {
172 tracing::error!(
173 "{} {} not found in registry, skipping from tag {}",
174 $entity_name,
175 key,
176 tag,
177 );
178 return None;
179 };
180 Some($crate::RegistryEntry::key(entry))
181 })
182 .collect();
183 self.tags.insert(tag.clone(), entry_keys);
184 }
185
186 fn is_in_tag(&self, entry: &Self::Entry, tag: &steel_utils::Identifier) -> bool {
187 self.tags.contains(tag, $crate::RegistryEntry::key(entry))
188 }
189
190 fn get_tag(&self, tag: &steel_utils::Identifier) -> Option<Vec<&'static Self::Entry>> {
191 self.tags.get(tag).map(|entry_keys| {
192 entry_keys
193 .iter()
194 .filter_map(|key| $crate::RegistryExt::by_key(self, key))
195 .collect()
196 })
197 }
198
199 fn iter_tag(
200 &self,
201 tag: &steel_utils::Identifier,
202 ) -> impl Iterator<Item = &'static Self::Entry> + '_ {
203 self.tags.get(tag).into_iter().flat_map(|entry_keys| {
204 entry_keys
205 .iter()
206 .filter_map(|key| $crate::RegistryExt::by_key(self, key))
207 })
208 }
209
210 fn tag_keys(&self) -> impl Iterator<Item = &steel_utils::Identifier> + '_ {
211 self.tags.keys()
212 }
213 }
214 };
215}