rh_foundation/snapshot/
generator.rs1use crate::snapshot::error::{SnapshotError, SnapshotResult};
2use crate::snapshot::merger::ElementMerger;
3use crate::snapshot::types::{Snapshot, StructureDefinition};
4use std::cell::RefCell;
5use std::collections::{HashMap, HashSet};
6use tracing::{debug, info};
7
8pub struct SnapshotGenerator {
9 structure_definitions: HashMap<String, StructureDefinition>,
10 snapshot_cache: RefCell<HashMap<String, Snapshot>>,
11}
12
13impl SnapshotGenerator {
14 pub fn new() -> Self {
15 Self {
16 structure_definitions: HashMap::new(),
17 snapshot_cache: RefCell::new(HashMap::new()),
18 }
19 }
20
21 pub fn clear_cache(&self) {
22 self.snapshot_cache.borrow_mut().clear();
23 }
24
25 pub fn cache_size(&self) -> usize {
26 self.snapshot_cache.borrow().len()
27 }
28
29 pub fn load_structure_definition(&mut self, sd: StructureDefinition) {
30 debug!("Loading StructureDefinition: {} ({})", sd.name, sd.url);
31 self.structure_definitions.insert(sd.url.clone(), sd);
32 }
33
34 pub fn load_structure_definitions(&mut self, sds: Vec<StructureDefinition>) {
35 for sd in sds {
36 self.load_structure_definition(sd);
37 }
38 }
39
40 pub fn generate_snapshot(&self, url: &str) -> SnapshotResult<Snapshot> {
41 info!("Generating snapshot for: {}", url);
42 let mut visited = HashSet::new();
43 self.generate_snapshot_internal(url, &mut visited)
44 }
45
46 fn generate_snapshot_internal(
47 &self,
48 url: &str,
49 visited: &mut HashSet<String>,
50 ) -> SnapshotResult<Snapshot> {
51 if visited.contains(url) {
52 return Err(SnapshotError::CircularDependency(format!(
53 "Circular dependency detected: {url}"
54 )));
55 }
56
57 if let Some(cached) = self.snapshot_cache.borrow().get(url) {
58 debug!("Using cached snapshot for {}", url);
59 return Ok(cached.clone());
60 }
61
62 visited.insert(url.to_string());
63
64 let sd = self
65 .structure_definitions
66 .get(url)
67 .ok_or_else(|| SnapshotError::BaseNotFound(url.to_string()))?;
68
69 debug!(
70 "Processing StructureDefinition: {} (type: {})",
71 sd.name, sd.type_
72 );
73
74 if let Some(ref snapshot) = sd.snapshot {
75 debug!(
76 "Using existing snapshot with {} elements",
77 snapshot.element.len()
78 );
79 self.snapshot_cache
80 .borrow_mut()
81 .insert(url.to_string(), snapshot.clone());
82 return Ok(snapshot.clone());
83 }
84
85 let snapshot = if let Some(base_url) = &sd.base_definition {
86 debug!("Resolving base definition: {}", base_url);
87 let base_snapshot = self.generate_snapshot_internal(base_url, visited)?;
88
89 if let Some(differential) = &sd.differential {
90 debug!(
91 "Merging {} base elements with {} differential elements",
92 base_snapshot.element.len(),
93 differential.element.len()
94 );
95 let merged =
96 ElementMerger::merge_elements(&base_snapshot.element, &differential.element)?;
97 info!("Generated snapshot with {} elements", merged.len());
98 Snapshot { element: merged }
99 } else {
100 debug!("No differential, returning base snapshot");
101 base_snapshot
102 }
103 } else if let Some(differential) = &sd.differential {
104 debug!(
105 "No base definition, using differential as snapshot ({} elements)",
106 differential.element.len()
107 );
108 Snapshot {
109 element: differential.element.clone(),
110 }
111 } else {
112 return Err(SnapshotError::InvalidStructureDefinition(format!(
113 "StructureDefinition {url} has no snapshot, differential, or base definition"
114 )));
115 };
116
117 self.snapshot_cache
118 .borrow_mut()
119 .insert(url.to_string(), snapshot.clone());
120 Ok(snapshot)
121 }
122}
123
124impl Default for SnapshotGenerator {
125 fn default() -> Self {
126 Self::new()
127 }
128}