automapper_validation/generated/fv2610/mscons_conditions_fv2610.rs
1// <auto-generated>
2// Delegating condition evaluator for MSCONS FV2610.
3// Source AHB: MSCONS_AHB_3_2_20260401.xml
4//
5// Strategy: FV2610's AHB (3.2) preserves 153 of 157 conditions from FV2604
6// (AHB 3.1g) byte-for-byte in their description text. This evaluator holds a
7// `MsconsConditionEvaluatorFV2604` and delegates unchanged conditions to it,
8// overriding only those that are new or semantically different in 3.2.
9//
10// Rationale: sharing FV2604's bodies — rather than re-stubbing 157 methods —
11// means bug fixes applied to FV2604 propagate automatically, and the override
12// list is the canonical diff between the two AHB versions.
13// </auto-generated>
14
15// LLM-produced bodies aren't idiomatic Rust — silence stylistic lints at
16// file scope so `cargo clippy -D warnings` stays green. Correctness,
17// suspicious, and perf categories stay on so real bugs still surface.
18#![allow(clippy::style, clippy::complexity)]
19
20#[allow(unused_imports)]
21use crate::eval::format_validators::*;
22use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
23use crate::generated::fv2604::MsconsConditionEvaluatorFV2604;
24
25/// Condition evaluator for MSCONS FV2610.
26///
27/// Delegates to [`MsconsConditionEvaluatorFV2604`] for conditions whose AHB
28/// description didn't change between FV2604 and FV2610. Overrides cover:
29/// - [38], [119] — corrected format validators (see `mscons_location_id_test`)
30/// - [155] — new in AHB 3.2 (UNB test-indicator check)
31///
32/// Conditions [502] and [2002] have minor cardinality wording deltas in 3.2
33/// but FV2604 returns `True` for both (informational "Hinweis" conditions);
34/// the wording change doesn't affect the boolean evaluation, so delegation
35/// stays correct.
36pub struct MsconsConditionEvaluatorFV2610 {
37 fallback: MsconsConditionEvaluatorFV2604,
38}
39
40impl Default for MsconsConditionEvaluatorFV2610 {
41 fn default() -> Self {
42 Self {
43 fallback: MsconsConditionEvaluatorFV2604::default(),
44 }
45 }
46}
47
48/// Condition IDs whose FV2610 implementation differs from the FV2604 fallback.
49/// Keep this list as the single source of truth for overrides — `evaluate` and
50/// `is_known` both consult it.
51const FV2610_OVERRIDES: &[u32] = &[38, 119, 155];
52
53impl ConditionEvaluator for MsconsConditionEvaluatorFV2610 {
54 fn message_type(&self) -> &str {
55 "MSCONS"
56 }
57
58 fn format_version(&self) -> &str {
59 "FV2610"
60 }
61
62 fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
63 match condition {
64 38 => self.evaluate_38(ctx),
65 119 => self.evaluate_119(ctx),
66 155 => self.evaluate_155(ctx),
67 other => self.fallback.evaluate(other, ctx),
68 }
69 }
70
71 fn is_external(&self, condition: u32) -> bool {
72 // No FV2610-specific externals yet — the overridden conditions (38,
73 // 119, 155) are all evaluated from segment data.
74 self.fallback.is_external(condition)
75 }
76
77 fn is_known(&self, condition: u32) -> bool {
78 FV2610_OVERRIDES.contains(&condition) || self.fallback.is_known(condition)
79 }
80}
81
82impl MsconsConditionEvaluatorFV2610 {
83 /// [38] wenn in SG6 LOC+172 DE3225 die ID der Messlokation angegeben ist
84 fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
85 // Messlokation = 33-char alphanumeric Zählpunktbezeichnung. A non-empty
86 // value that doesn't match (e.g. an 11-digit MaLo-ID) must be False so
87 // the AHB's XOR branches against condition [119] stay mutually exclusive.
88 let loc_segments = ctx.find_segments_with_qualifier("LOC", 0, "172");
89 match loc_segments.first() {
90 Some(loc) => match loc.elements.get(1).and_then(|e| e.first()) {
91 Some(v) if !v.is_empty() => validate_zahlpunkt(v),
92 _ => ConditionResult::False,
93 },
94 None => ConditionResult::False,
95 }
96 }
97
98 /// [119] wenn in SG6 LOC+172 DE3225 die ID der Marktlokation angegeben ist
99 fn evaluate_119(&self, ctx: &EvaluationContext) -> ConditionResult {
100 // Marktlokation = 11-digit MaLo-ID with BDEW check digit. A non-empty
101 // value that doesn't match (e.g. a 33-char Zählpunkt) must be False so
102 // the AHB's XOR branches against condition [38] stay mutually exclusive.
103 let locs = ctx.find_segments_with_qualifier("LOC", 0, "172");
104 match locs.first() {
105 Some(loc) => match loc.elements.get(1).and_then(|e| e.first()) {
106 Some(v) if !v.is_empty() => validate_malo_id(v),
107 _ => ConditionResult::False,
108 },
109 None => ConditionResult::False,
110 }
111 }
112
113 /// [155] Wenn Übertragungsdatei zu Testzwecken ausgetauscht wird.
114 fn evaluate_155(&self, ctx: &EvaluationContext) -> ConditionResult {
115 // UNB element 11 (0-indexed 10) is D0035 "Test indicator".
116 // Value "1" marks the interchange as a test exchange. Absence means
117 // production traffic — False, not Unknown (explicit semantics).
118 match ctx.find_segment("UNB") {
119 Some(unb) => {
120 let test_flag = unb.elements.get(10).and_then(|e| e.first());
121 ConditionResult::from(test_flag.is_some_and(|v| v == "1"))
122 }
123 None => ConditionResult::False,
124 }
125 }
126}