Correlate engine cargo sidecars

This commit is contained in:
Jan Petykiewicz 2026-04-21 23:27:12 -07:00
commit 16d04c18e4
3 changed files with 116 additions and 0 deletions

View file

@ -188,6 +188,8 @@ pub struct EngineTypesInspectionReport {
pub cgo_scalar_value_counts: BTreeMap<String, usize>,
pub cgo_scalar_ladder_counts: BTreeMap<String, usize>,
pub cgo_scalar_values_by_content_stem: BTreeMap<String, Vec<String>>,
pub cgo_content_stem_cct_value_map: BTreeMap<String, i64>,
pub cct_identifiers_without_cgo_content_stem: Vec<String>,
pub cct_identifier_counts: BTreeMap<String, usize>,
pub cct_value_counts: BTreeMap<String, usize>,
pub locomotive_display_census: EngineTypeLocomotiveDisplayCensusReport,
@ -530,6 +532,12 @@ pub fn inspect_engine_types_dir(
);
let cgo_scalar_values_by_content_stem =
build_cgo_scalar_values_by_content_stem(cgo_reports.values());
let cgo_content_stem_cct_value_map =
build_cgo_content_stem_cct_value_map(&family_entries, &cgo_scalar_values_by_content_stem);
let cct_identifiers_without_cgo_content_stem = build_cct_identifiers_without_cgo_content_stem(
&family_entries,
&cgo_scalar_values_by_content_stem,
);
let cgo_scalar_ladder_counts =
build_cgo_scalar_ladder_counts(cgo_scalar_values_by_content_stem.values());
let cct_identifier_counts = count_named_values(
@ -613,6 +621,8 @@ pub fn inspect_engine_types_dir(
cgo_scalar_value_counts,
cgo_scalar_ladder_counts,
cgo_scalar_values_by_content_stem,
cgo_content_stem_cct_value_map,
cct_identifiers_without_cgo_content_stem,
cct_identifier_counts,
cct_value_counts,
locomotive_display_census,
@ -1040,6 +1050,37 @@ fn build_cgo_scalar_ladder_counts<'a>(
count_owned_values(ladders.map(|ladder| ladder.join(" -> ")))
}
fn build_cgo_content_stem_cct_value_map(
families: &[EngineTypeFamilyEntry],
cgo_scalar_values_by_content_stem: &BTreeMap<String, Vec<String>>,
) -> BTreeMap<String, i64> {
families
.iter()
.filter_map(|family| {
let identifier = family.cct_identifier.as_ref()?;
let value = family.cct_value?;
cgo_scalar_values_by_content_stem
.contains_key(identifier)
.then_some((identifier.clone(), value))
})
.collect()
}
fn build_cct_identifiers_without_cgo_content_stem(
families: &[EngineTypeFamilyEntry],
cgo_scalar_values_by_content_stem: &BTreeMap<String, Vec<String>>,
) -> Vec<String> {
let mut identifiers = families
.iter()
.filter_map(|family| family.cct_identifier.as_ref())
.filter(|identifier| !cgo_scalar_values_by_content_stem.contains_key(*identifier))
.cloned()
.collect::<Vec<_>>();
identifiers.sort();
identifiers.dedup();
identifiers
}
fn build_lco_low_cardinality_lane_counts<'a>(
reports: impl Iterator<Item = &'a EngineTypeLcoInspectionReport>,
) -> BTreeMap<String, BTreeMap<String, usize>> {
@ -1397,6 +1438,72 @@ mod tests {
);
}
#[test]
fn maps_cgo_content_stems_to_matching_cct_values() {
let families = vec![
EngineTypeFamilyEntry {
canonical_stem: "box".to_string(),
car_file: None,
lco_file: None,
cgo_file: None,
cct_file: Some("Box.cct".to_string()),
primary_display_name: None,
content_name: None,
internal_stem: None,
auxiliary_stem: None,
side_view_resource: None,
side_view_resource_found_in_pk4: None,
companion_stem: None,
body_type_label: None,
internal_ne_profile_name: None,
internal_ne_profile_found_in_pk4: None,
cct_identifier: Some("Box".to_string()),
cct_value: Some(11),
has_matched_locomotive_pair: false,
},
EngineTypeFamilyEntry {
canonical_stem: "troop".to_string(),
cct_file: Some("Troop.cct".to_string()),
cct_identifier: Some("Troop".to_string()),
cct_value: Some(9),
..EngineTypeFamilyEntry {
canonical_stem: "box".to_string(),
car_file: None,
lco_file: None,
cgo_file: None,
cct_file: None,
primary_display_name: None,
content_name: None,
internal_stem: None,
auxiliary_stem: None,
side_view_resource: None,
side_view_resource_found_in_pk4: None,
companion_stem: None,
body_type_label: None,
internal_ne_profile_name: None,
internal_ne_profile_found_in_pk4: None,
cct_identifier: None,
cct_value: None,
has_matched_locomotive_pair: false,
}
},
];
let cgo_scalar_values_by_content_stem = BTreeMap::from([(
"Box".to_string(),
vec!["10.000000".to_string(), "20.000000".to_string()],
)]);
let mapped =
build_cgo_content_stem_cct_value_map(&families, &cgo_scalar_values_by_content_stem);
let missing = build_cct_identifiers_without_cgo_content_stem(
&families,
&cgo_scalar_values_by_content_stem,
);
assert_eq!(mapped.get("Box"), Some(&11));
assert_eq!(missing, vec!["Troop".to_string()]);
}
#[test]
fn counts_owned_value_strings() {
let counts =