wowlab_engine_application/
conflicts.rs1use wowlab_engine_ports::{ContentCatalog, EngineError};
4use wowlab_types::sim::FastMap;
5
6use crate::{ApplicationError, ApplicationStage, error::EngineResultExt as _};
7
8pub fn check_conflicts(catalog: &ContentCatalog) -> Result<(), ApplicationError> {
10 fn check_names<'a>(
11 kind: &str,
12 pairs: impl Iterator<Item = (&'a str, u32)>,
13 display_name: &str,
14 ) -> Result<(), EngineError> {
15 let mut seen: FastMap<&'a str, u32> = FastMap::default();
16
17 for (name, id) in pairs {
19 if let Some(&first_id) = seen.get(&name) {
20 if first_id != id {
21 return Err(EngineError::spec_construction(format!(
22 "{kind} name conflict in '{display_name}': '{name}' bound to both ids {first_id} and {id}"
23 )));
24 }
25 } else {
26 seen.insert(name, id);
27 }
28 }
29
30 Ok(())
31 }
32
33 for descriptor in catalog.descriptors() {
34 let intro = crate::introspect_spec(catalog, descriptor.spec_id)?;
35
36 check_names(
37 "spell",
38 intro.spells.iter().map(|s| (s.slug.as_str(), s.spell_id)),
39 descriptor.display_name,
40 )
41 .in_application_stage(ApplicationStage::ConflictCheck)?;
42 check_names(
43 "aura",
44 intro.auras.iter().map(|a| (a.slug.as_str(), a.aura_id)),
45 descriptor.display_name,
46 )
47 .in_application_stage(ApplicationStage::ConflictCheck)?;
48 }
49
50 Ok(())
51}