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 {
42 ($Entry:ty, $global_field:ident) => {
43 impl $crate::RegistryEntry for $Entry {
44 fn key(&self) -> &steel_utils::Identifier {
45 &self.key
46 }
47
48 fn try_id(&self) -> Option<usize> {
49 use $crate::RegistryExt;
50 $crate::REGISTRY.$global_field.id_from_key(&self.key)
51 }
52 }
53 };
54}
55
56#[macro_export]
58macro_rules! impl_standard_methods {
59 ($Registry:ty, $Entry:ty, $id_field:ident, $key_field:ident, $allow_registering:ident) => {
60 impl $Registry {
61 pub fn register(&mut self, entry: $Entry) -> usize {
62 assert!(
63 self.$allow_registering,
64 concat!(
65 "Cannot register ",
66 stringify!($Entry),
67 " after registry has been frozen"
68 )
69 );
70 let id = self.$id_field.len();
71 self.$id_field.push(entry);
72 self.$key_field.insert(entry.key.clone(), id);
73 id
74 }
75
76 pub fn iter(&self) -> impl Iterator<Item = (usize, $Entry)> + '_ {
77 self.$id_field
78 .iter()
79 .enumerate()
80 .map(|(id, &entry)| (id, entry))
81 }
82 }
83
84 impl Default for $Registry {
85 fn default() -> Self {
86 Self::new()
87 }
88 }
89 };
90}
91
92#[macro_export]
94macro_rules! impl_registry {
95 ($Registry:ty, $Entry:ty, $id_field:ident, $key_field:ident, $global_field:ident) => {
96 $crate::impl_registry_ext!($Registry, $Entry, $id_field, $key_field);
97 $crate::impl_registry_entry!($Entry, $global_field);
98 };
99}
100
101#[macro_export]
103macro_rules! impl_tagged_registry {
104 ($Registry:ty, $key_field:ident, $entity_name:literal) => {
105 impl $crate::TaggedRegistryExt for $Registry {
106 fn register_tag(&mut self, tag: steel_utils::Identifier, keys: &[&'static str]) {
107 assert!(
108 self.allows_registering,
109 "Cannot register tags after registry has been frozen"
110 );
111
112 let identifiers: Vec<steel_utils::Identifier> = keys
113 .iter()
114 .filter_map(|key| {
115 let ident = steel_utils::registry::registry_vanilla_or_custom_tag(key);
116 if self.$key_field.contains_key(&ident) {
117 Some(ident)
118 } else {
119 None
120 }
121 })
122 .collect();
123
124 self.tags.insert(tag, identifiers);
125 }
126
127 fn modify_tag(
128 &mut self,
129 tag: &steel_utils::Identifier,
130 f: impl FnOnce(Vec<steel_utils::Identifier>) -> Vec<steel_utils::Identifier>,
131 ) {
132 let existing = self.tags.remove(tag).unwrap_or_default();
133 let entries = f(existing)
134 .into_iter()
135 .filter(|key| {
136 let exists = self.$key_field.contains_key(key);
137 if !exists {
138 tracing::error!(
139 "{} {} not found in registry, skipping from tag {}",
140 $entity_name,
141 key,
142 tag,
143 );
144 }
145 exists
146 })
147 .collect();
148 self.tags.insert(tag.clone(), entries);
149 }
150
151 fn is_in_tag(&self, entry: &Self::Entry, tag: &steel_utils::Identifier) -> bool {
152 self.tags
153 .get(tag)
154 .is_some_and(|entries| entries.contains(&entry.key))
155 }
156
157 fn get_tag(&self, tag: &steel_utils::Identifier) -> Option<Vec<&'static Self::Entry>> {
158 use $crate::RegistryExt;
159 self.tags.get(tag).map(|idents| {
160 idents
161 .iter()
162 .filter_map(|ident| self.by_key(ident))
163 .collect()
164 })
165 }
166
167 fn iter_tag(
168 &self,
169 tag: &steel_utils::Identifier,
170 ) -> impl Iterator<Item = &'static Self::Entry> + '_ {
171 use $crate::RegistryExt;
172 self.tags
173 .get(tag)
174 .into_iter()
175 .flat_map(|v| v.iter().filter_map(|ident| self.by_key(ident)))
176 }
177
178 fn tag_keys(&self) -> impl Iterator<Item = &steel_utils::Identifier> + '_ {
179 self.tags.keys()
180 }
181 }
182 };
183}