|
2 | 2 | use std::collections::HashMap; |
3 | 3 | use std::sync::Arc; |
4 | 4 |
|
5 | | - |
6 | 5 | use super::collection::{UnresolvedContainer, UnresolvedParameter, UnresolvedParameterType}; |
7 | 6 | use super::conversion::convert_restriction_criteria; |
8 | 7 | use super::resolution::{resolve_container_reference, resolve_parameter_type_name}; |
9 | 8 | use crate::de::{RestrictionCriteria, SequenceContainerType}; |
10 | | -use crate::{Item, Parameter}; |
11 | 9 | use crate::xtce::container::convert_entry; |
12 | 10 | use crate::xtce::types::{ |
13 | 11 | convert_parameter_type_set, convert_parameter_type_set_with_context, |
14 | 12 | convert_parameter_type_set_with_parameters, |
15 | 13 | }; |
16 | 14 | use crate::{Error, Result}; |
| 15 | +use crate::{Item, Parameter}; |
17 | 16 |
|
18 | 17 | /// Construct parameter types in multiple passes: |
19 | 18 | /// Pass 1: Simple types (int, float, string, bool, enum, time) - no dependencies |
@@ -70,35 +69,68 @@ pub(crate) fn construct_parameter_types_pass1( |
70 | 69 | } |
71 | 70 |
|
72 | 71 | /// Pass 2: Construct Aggregate types (after simple types are available) |
| 72 | +/// This uses multi-pass construction to handle dependencies between aggregate types. |
73 | 73 | pub(crate) fn construct_parameter_types_pass2_aggregates( |
74 | 74 | deferred_aggregate_types: Vec<(String, UnresolvedParameterType)>, |
75 | 75 | completed: &mut HashMap<String, Arc<crate::Type>>, |
76 | 76 | ) -> Result<()> { |
77 | | - for (qualified_name, unresolved_type) in deferred_aggregate_types { |
78 | | - match convert_parameter_type_set_with_context( |
79 | | - &unresolved_type.xml, |
80 | | - &unresolved_type.space_system_path, |
81 | | - &completed, |
82 | | - ) { |
83 | | - Ok(type_) => { |
84 | | - completed.insert(qualified_name, Arc::new(type_)); |
85 | | - } |
86 | | - Err(Error::NotImplemented(msg)) => { |
87 | | - tracing::warn!( |
88 | | - "Skipping unsupported parameter type '{}': {}", |
89 | | - qualified_name, |
90 | | - msg |
91 | | - ); |
| 77 | + let mut remaining = deferred_aggregate_types; |
| 78 | + let mut failed_permanently = Vec::new(); |
| 79 | + |
| 80 | + // Keep trying until we make no more progress |
| 81 | + while !remaining.is_empty() { |
| 82 | + let mut still_deferred = Vec::new(); |
| 83 | + let mut made_progress = false; |
| 84 | + |
| 85 | + for (qualified_name, unresolved_type) in remaining { |
| 86 | + match convert_parameter_type_set_with_context( |
| 87 | + &unresolved_type.xml, |
| 88 | + &unresolved_type.space_system_path, |
| 89 | + &completed, |
| 90 | + ) { |
| 91 | + Ok(type_) => { |
| 92 | + completed.insert(qualified_name, Arc::new(type_)); |
| 93 | + made_progress = true; |
| 94 | + } |
| 95 | + Err(Error::NotImplemented(msg)) => { |
| 96 | + // These are permanently unsupported types |
| 97 | + tracing::warn!( |
| 98 | + "Skipping unsupported parameter type '{}': {}", |
| 99 | + qualified_name, |
| 100 | + msg |
| 101 | + ); |
| 102 | + failed_permanently.push(qualified_name); |
| 103 | + } |
| 104 | + Err(Error::InvalidXtce(ref msg)) if msg.contains("not found") => { |
| 105 | + // This is likely a missing dependency - defer for next pass |
| 106 | + still_deferred.push((qualified_name, unresolved_type)); |
| 107 | + } |
| 108 | + Err(e) => { |
| 109 | + // Other errors should be logged but not retried |
| 110 | + tracing::warn!( |
| 111 | + "Failed to construct aggregate type '{}': {}", |
| 112 | + qualified_name, |
| 113 | + e |
| 114 | + ); |
| 115 | + failed_permanently.push(qualified_name); |
| 116 | + } |
92 | 117 | } |
93 | | - Err(e) => { |
| 118 | + } |
| 119 | + |
| 120 | + // If we didn't make progress and still have deferred types, they must have unresolvable dependencies |
| 121 | + if !made_progress && !still_deferred.is_empty() { |
| 122 | + for (qualified_name, _) in still_deferred { |
94 | 123 | tracing::warn!( |
95 | | - "Failed to construct aggregate type '{}': {}", |
96 | | - qualified_name, |
97 | | - e |
| 124 | + "Failed to construct aggregate type '{}': unresolvable type dependencies", |
| 125 | + qualified_name |
98 | 126 | ); |
99 | 127 | } |
| 128 | + break; |
100 | 129 | } |
| 130 | + |
| 131 | + remaining = still_deferred; |
101 | 132 | } |
| 133 | + |
102 | 134 | Ok(()) |
103 | 135 | } |
104 | 136 |
|
|
0 commit comments