Skip to main content

zerodds_rpc/
evolution_rules.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Service-Evolution-Compatibility-Regeln (Spec §7.7).
5//!
6//! Pro Mapping (Basic + Enhanced) definiert die Spec, welche
7//! Service-Evolutionen (add/remove/reorder operation, change
8//! signature, etc.) backward-compatible sind. Dieses Modul kodiert
9//! diese Regeln als Const-Tabellen und liefert Helper-Funktionen,
10//! die ein Codegen-/Audit-Tool gegen evolved Service-Definitions
11//! prueft.
12
13extern crate alloc;
14
15use alloc::vec::Vec;
16
17/// Service-Evolution-Operation.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum Evolution {
20    /// Spec §7.7.1.1 / §7.7.2.1.
21    AddOperation,
22    /// Spec §7.7.1.1 / §7.7.2.2.
23    RemoveOperation,
24    /// Spec §7.7.1.2 / §7.7.2.3.
25    ReorderOperations,
26    /// Spec §7.7.1.2.
27    ReorderBaseInterfaces,
28    /// Spec §7.7.1.3 — Operation-Signatur aendert sich.
29    ChangeSignature,
30    /// Spec §7.7.2.4 — Duck-Typing.
31    DuckTyping,
32    /// Spec §7.7.2.5.1.
33    AddRemoveParameter,
34    /// Spec §7.7.2.5.2.
35    ReorderParameters,
36    /// Spec §7.7.2.5.3.
37    ChangeParameterType,
38    /// Spec §7.7.2.5.4.
39    AddRemoveReturnType,
40    /// Spec §7.7.2.5.5.
41    ChangeReturnType,
42}
43
44/// Mapping-Profil.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum Mapping {
47    /// Basic-Mapping (Spec §7.7.1).
48    Basic,
49    /// Enhanced-Mapping (Spec §7.7.2).
50    Enhanced,
51}
52
53/// Spec §7.7: Compatibility-Tabelle pro (Mapping, Evolution).
54///
55/// Liefert `true` wenn die Evolution unter dem gegebenen Mapping
56/// backward-compatible ist (Old-Client kann mit New-Service reden).
57#[must_use]
58pub fn is_compatible(mapping: Mapping, evolution: Evolution) -> bool {
59    match (mapping, evolution) {
60        // Basic-Mapping: jede Strukturaenderung ist breaking
61        // (Spec §7.7.1.x).
62        (Mapping::Basic, _) => false,
63
64        // Enhanced-Mapping (Spec §7.7.2.x): die meisten
65        // Strukturaenderungen sind compat-by-default.
66        (Mapping::Enhanced, Evolution::AddOperation) => true,
67        (Mapping::Enhanced, Evolution::RemoveOperation) => true, // mit Caveat (§7.7.2.2)
68        (Mapping::Enhanced, Evolution::ReorderOperations) => true,
69        (Mapping::Enhanced, Evolution::ReorderBaseInterfaces) => true,
70        (Mapping::Enhanced, Evolution::DuckTyping) => true,
71        (Mapping::Enhanced, Evolution::AddRemoveParameter) => true,
72        (Mapping::Enhanced, Evolution::ReorderParameters) => true,
73        (Mapping::Enhanced, Evolution::AddRemoveReturnType) => true,
74
75        // Aenderung des Typs (auch in Enhanced) ist breaking.
76        (Mapping::Enhanced, Evolution::ChangeSignature) => false,
77        (Mapping::Enhanced, Evolution::ChangeParameterType) => false,
78        (Mapping::Enhanced, Evolution::ChangeReturnType) => false,
79    }
80}
81
82/// Liefert alle Evolutionen, die unter dem gegebenen Mapping
83/// **kompatibel** sind.
84#[must_use]
85pub fn compatible_evolutions(mapping: Mapping) -> Vec<Evolution> {
86    [
87        Evolution::AddOperation,
88        Evolution::RemoveOperation,
89        Evolution::ReorderOperations,
90        Evolution::ReorderBaseInterfaces,
91        Evolution::ChangeSignature,
92        Evolution::DuckTyping,
93        Evolution::AddRemoveParameter,
94        Evolution::ReorderParameters,
95        Evolution::ChangeParameterType,
96        Evolution::AddRemoveReturnType,
97        Evolution::ChangeReturnType,
98    ]
99    .iter()
100    .copied()
101    .filter(|e| is_compatible(mapping, *e))
102    .collect()
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    // ---- Spec §7.7.1.1-3 Basic-Mapping (alle breaking) -------------
110
111    #[test]
112    fn basic_mapping_add_remove_operation_is_breaking() {
113        // Spec §7.7.1.1.
114        assert!(!is_compatible(Mapping::Basic, Evolution::AddOperation));
115        assert!(!is_compatible(Mapping::Basic, Evolution::RemoveOperation));
116    }
117
118    #[test]
119    fn basic_mapping_reorder_operations_is_breaking() {
120        // Spec §7.7.1.2.
121        assert!(!is_compatible(Mapping::Basic, Evolution::ReorderOperations));
122        assert!(!is_compatible(
123            Mapping::Basic,
124            Evolution::ReorderBaseInterfaces
125        ));
126    }
127
128    #[test]
129    fn basic_mapping_change_signature_is_breaking() {
130        // Spec §7.7.1.3.
131        assert!(!is_compatible(Mapping::Basic, Evolution::ChangeSignature));
132    }
133
134    #[test]
135    fn basic_mapping_has_no_compatible_evolutions() {
136        assert!(compatible_evolutions(Mapping::Basic).is_empty());
137    }
138
139    // ---- Spec §7.7.2.1-5 Enhanced-Mapping (compat by default) -----
140
141    #[test]
142    fn enhanced_mapping_add_operation_is_compatible() {
143        // Spec §7.7.2.1.
144        assert!(is_compatible(Mapping::Enhanced, Evolution::AddOperation));
145    }
146
147    #[test]
148    fn enhanced_mapping_remove_operation_is_compatible_with_caveat() {
149        // Spec §7.7.2.2.
150        assert!(is_compatible(Mapping::Enhanced, Evolution::RemoveOperation));
151    }
152
153    #[test]
154    fn enhanced_mapping_reorder_operations_is_compatible() {
155        // Spec §7.7.2.3.
156        assert!(is_compatible(
157            Mapping::Enhanced,
158            Evolution::ReorderOperations
159        ));
160        assert!(is_compatible(
161            Mapping::Enhanced,
162            Evolution::ReorderBaseInterfaces
163        ));
164    }
165
166    #[test]
167    fn enhanced_mapping_duck_typing_is_compatible() {
168        // Spec §7.7.2.4.
169        assert!(is_compatible(Mapping::Enhanced, Evolution::DuckTyping));
170    }
171
172    #[test]
173    fn enhanced_mapping_add_remove_param_is_compatible() {
174        // Spec §7.7.2.5.1.
175        assert!(is_compatible(
176            Mapping::Enhanced,
177            Evolution::AddRemoveParameter
178        ));
179    }
180
181    #[test]
182    fn enhanced_mapping_reorder_params_is_compatible() {
183        // Spec §7.7.2.5.2.
184        assert!(is_compatible(
185            Mapping::Enhanced,
186            Evolution::ReorderParameters
187        ));
188    }
189
190    #[test]
191    fn enhanced_mapping_change_param_type_is_breaking() {
192        // Spec §7.7.2.5.3 — Type-Aenderungen sind auch in Enhanced
193        // breaking, weil das Wire-Format nicht kompatibel ist.
194        assert!(!is_compatible(
195            Mapping::Enhanced,
196            Evolution::ChangeParameterType
197        ));
198    }
199
200    #[test]
201    fn enhanced_mapping_add_remove_return_type_is_compatible() {
202        // Spec §7.7.2.5.4.
203        assert!(is_compatible(
204            Mapping::Enhanced,
205            Evolution::AddRemoveReturnType
206        ));
207    }
208
209    #[test]
210    fn enhanced_mapping_change_return_type_is_breaking() {
211        // Spec §7.7.2.5.5.
212        assert!(!is_compatible(
213            Mapping::Enhanced,
214            Evolution::ChangeReturnType
215        ));
216    }
217
218    #[test]
219    fn enhanced_compatible_evolutions_includes_8_of_11() {
220        let compats = compatible_evolutions(Mapping::Enhanced);
221        // Add/Remove/Reorder-Op + Reorder-Bases + DuckTyping +
222        // Add/Remove-Param + Reorder-Params + Add/Remove-Return = 8.
223        assert_eq!(compats.len(), 8);
224    }
225}