ddex_builder/linker/
reference_generator.rs

1//! Deterministic reference generation with configurable styles
2
3use super::types::{EntityType, ReferenceStyle};
4use indexmap::IndexMap;
5
6/// Generates deterministic references for DDEX entities
7#[derive(Debug, Clone)]
8pub struct ReferenceGenerator {
9    /// Style configuration for references
10    style: ReferenceStyle,
11    
12    /// Counters for each entity type (deterministic ordering with IndexMap)
13    counters: IndexMap<EntityType, u32>,
14    
15    /// Custom prefixes for entity types
16    prefixes: IndexMap<EntityType, String>,
17}
18
19impl ReferenceGenerator {
20    /// Create a new reference generator
21    pub fn new(style: ReferenceStyle) -> Self {
22        let mut prefixes = IndexMap::new();
23        
24        // Default DDEX prefixes
25        prefixes.insert(EntityType::Release, "R".to_string());
26        prefixes.insert(EntityType::Resource, "A".to_string());
27        prefixes.insert(EntityType::Party, "P".to_string());
28        prefixes.insert(EntityType::Deal, "D".to_string());
29        prefixes.insert(EntityType::TechnicalDetails, "T".to_string());
30        prefixes.insert(EntityType::RightsController, "RC".to_string());
31        
32        Self {
33            style,
34            counters: IndexMap::new(),
35            prefixes,
36        }
37    }
38    
39    /// Generate a new reference for an entity type
40    pub fn generate(&mut self, entity_type: EntityType) -> String {
41        match self.style.clone() {  // Clone the style to avoid borrow issues
42            ReferenceStyle::Sequential => self.generate_sequential(entity_type),
43            ReferenceStyle::Custom(formatter) => formatter(entity_type, self.next_counter(entity_type)),
44            ReferenceStyle::Prefixed { separator } => self.generate_prefixed(entity_type, &separator),
45        }
46    }
47    
48    /// Generate sequential reference (e.g., "A1", "A2", "R1", "R2")
49    fn generate_sequential(&mut self, entity_type: EntityType) -> String {
50        let prefix = self.prefixes.get(&entity_type)
51            .expect("Unknown entity type")
52            .clone();  // Clone to avoid borrow issues
53        let counter = self.next_counter(entity_type);
54        format!("{}{}", prefix, counter)
55    }
56    
57    /// Generate prefixed reference with custom separator
58    fn generate_prefixed(&mut self, entity_type: EntityType, separator: &str) -> String {
59        let prefix = self.prefixes.get(&entity_type)
60            .expect("Unknown entity type")
61            .clone();  // Clone to avoid borrow issues
62        let counter = self.next_counter(entity_type);
63        format!("{}{}{}", prefix, separator, counter)
64    }
65    
66    /// Get next counter value for entity type
67    fn next_counter(&mut self, entity_type: EntityType) -> u32 {
68        let counter = self.counters.entry(entity_type).or_insert(0);
69        *counter += 1;
70        *counter
71    }
72    
73    /// Set custom prefix for an entity type
74    pub fn set_prefix(&mut self, entity_type: EntityType, prefix: String) {
75        self.prefixes.insert(entity_type, prefix);
76    }
77    
78    /// Reset counter for an entity type
79    pub fn reset_counter(&mut self, entity_type: EntityType) {
80        self.counters.insert(entity_type, 0);
81    }
82    
83    /// Reset all counters
84    pub fn reset_all_counters(&mut self) {
85        self.counters.clear();
86    }
87    
88    /// Get current counter value for entity type
89    pub fn get_counter(&self, entity_type: EntityType) -> u32 {
90        self.counters.get(&entity_type).copied().unwrap_or(0)
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    
98    #[test]
99    fn test_sequential_generation() {
100        let mut gen = ReferenceGenerator::new(ReferenceStyle::Sequential);
101        
102        assert_eq!(gen.generate(EntityType::Resource), "A1");
103        assert_eq!(gen.generate(EntityType::Resource), "A2");
104        assert_eq!(gen.generate(EntityType::Release), "R1");
105        assert_eq!(gen.generate(EntityType::Resource), "A3");
106        assert_eq!(gen.generate(EntityType::Release), "R2");
107    }
108    
109    #[test]
110    fn test_deterministic_ordering() {
111        let mut gen1 = ReferenceGenerator::new(ReferenceStyle::Sequential);
112        let mut gen2 = ReferenceGenerator::new(ReferenceStyle::Sequential);
113        
114        // Same sequence should produce same results
115        for _ in 0..5 {
116            assert_eq!(
117                gen1.generate(EntityType::Resource),
118                gen2.generate(EntityType::Resource)
119            );
120        }
121    }
122}