Add engine type aggregate parser views

This commit is contained in:
Jan Petykiewicz 2026-04-21 22:55:52 -07:00
commit 4942824526

View file

@ -150,6 +150,8 @@ pub struct EngineTypesInspectionReport {
pub lco_body_type_label_counts: BTreeMap<String, usize>, pub lco_body_type_label_counts: BTreeMap<String, usize>,
pub cgo_scalar_value_counts: BTreeMap<String, usize>, pub cgo_scalar_value_counts: BTreeMap<String, usize>,
pub cgo_scalar_values_by_content_stem: BTreeMap<String, Vec<String>>, pub cgo_scalar_values_by_content_stem: BTreeMap<String, Vec<String>>,
pub cct_identifier_counts: BTreeMap<String, usize>,
pub cct_value_counts: BTreeMap<String, usize>,
pub locomotive_display_census: EngineTypeLocomotiveDisplayCensusReport, pub locomotive_display_census: EngineTypeLocomotiveDisplayCensusReport,
pub families: Vec<EngineTypeFamilyEntry>, pub families: Vec<EngineTypeFamilyEntry>,
} }
@ -371,6 +373,16 @@ pub fn inspect_engine_types_dir(
); );
let cgo_scalar_values_by_content_stem = let cgo_scalar_values_by_content_stem =
build_cgo_scalar_values_by_content_stem(cgo_reports.values()); build_cgo_scalar_values_by_content_stem(cgo_reports.values());
let cct_identifier_counts = count_named_values(
family_entries
.iter()
.filter_map(|family| family.cct_identifier.as_deref()),
);
let cct_value_counts = count_owned_values(
family_entries
.iter()
.filter_map(|family| family.cct_value.map(|value| value.to_string())),
);
let locomotive_display_census = let locomotive_display_census =
build_locomotive_display_census(path, &family_entries, &car_reports)?; build_locomotive_display_census(path, &family_entries, &car_reports)?;
@ -420,6 +432,8 @@ pub fn inspect_engine_types_dir(
lco_body_type_label_counts, lco_body_type_label_counts,
cgo_scalar_value_counts, cgo_scalar_value_counts,
cgo_scalar_values_by_content_stem, cgo_scalar_values_by_content_stem,
cct_identifier_counts,
cct_value_counts,
locomotive_display_census, locomotive_display_census,
families: family_entries, families: family_entries,
}) })
@ -586,14 +600,15 @@ fn read_lco_companion_stem(bytes: &[u8]) -> Option<String> {
slot_is_padded(bytes, LCO_INTERNAL_STEM_OFFSET, 0x08) slot_is_padded(bytes, LCO_INTERNAL_STEM_OFFSET, 0x08)
.then(|| read_ascii_slot(bytes, LCO_COMPANION_STEM_OFFSET, LCO_COMPANION_STEM_LEN)) .then(|| read_ascii_slot(bytes, LCO_COMPANION_STEM_OFFSET, LCO_COMPANION_STEM_LEN))
.flatten() .flatten()
.filter(|value| value.len() >= 4)
} }
fn read_lco_body_type_label(bytes: &[u8]) -> Option<String> { fn read_lco_body_type_label(bytes: &[u8]) -> Option<String> {
let companion_slot_is_padded = let _companion_stem = read_lco_companion_stem(bytes)?;
slot_is_padded(bytes, LCO_COMPANION_STEM_OFFSET, LCO_COMPANION_STEM_LEN); slot_is_padded(bytes, LCO_COMPANION_STEM_OFFSET, LCO_COMPANION_STEM_LEN)
companion_slot_is_padded
.then(|| read_ascii_slot(bytes, LCO_BODY_TYPE_LABEL_OFFSET, LCO_BODY_TYPE_LABEL_LEN)) .then(|| read_ascii_slot(bytes, LCO_BODY_TYPE_LABEL_OFFSET, LCO_BODY_TYPE_LABEL_LEN))
.flatten() .flatten()
.filter(|value| value.len() >= 4)
} }
fn parse_cct_row(line: &str) -> (Option<String>, Option<i64>) { fn parse_cct_row(line: &str) -> (Option<String>, Option<i64>) {
@ -853,6 +868,13 @@ mod tests {
); );
} }
#[test]
fn counts_owned_value_strings() {
let counts = count_owned_values(["13".to_string(), "13".to_string(), "4".to_string()].into_iter());
assert_eq!(counts.get("13"), Some(&2));
assert_eq!(counts.get("4"), Some(&1));
}
#[test] #[test]
fn builds_locomotive_display_census() { fn builds_locomotive_display_census() {
let mut car_reports = BTreeMap::new(); let mut car_reports = BTreeMap::new();