1#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2enum State {
3 Ongoing(usize),
5 Finished(usize),
7 Empty,
9}
10
11pub const fn assert_no_intersection<const N: usize>(msgs: [&[&str]; N]) {
23 let mut states = init_states(&msgs);
24
25 while !should_end(&states) {
26 let index = get_next_alphabetical_index(&msgs, &states);
29
30 verify_no_collissions(&msgs, &states, &index);
32
33 states[index] = match states[index] {
35 State::Ongoing(wi) => {
36 if msgs[index].len() == wi + 1 {
37 State::Finished(wi)
38 } else {
39 State::Ongoing(wi + 1)
40 }
41 }
42 _ => unreachable!(),
43 };
44 }
45}
46
47const fn init_states<const N: usize>(msgs: &[&[&str]; N]) -> [State; N] {
48 let mut states = [State::Ongoing(0); N];
49 konst::for_range! {i in 0..N =>
50 if msgs[i].is_empty() {
51 states[i] = State::Empty;
52 }
53
54 }
55 states
56}
57
58const fn get_next_alphabetical_index<const N: usize>(
61 msgs: &[&[&str]; N],
62 states: &[State; N],
63) -> usize {
64 let mut output_index = 0;
65 konst::for_range! {i in 0..N =>
66 if let State::Ongoing(outer_i) = states[i] {
67 match states[output_index] {
68 State::Ongoing(inner_i) => {
69 if let std::cmp::Ordering::Greater =
70 konst::cmp_str(msgs[output_index][inner_i], msgs[i][outer_i])
71 {
72 output_index = i;
73 }
74 }
75 _ => output_index = i,
76 }
77 }
78 }
79 output_index
80}
81
82const fn verify_no_collissions<const N: usize>(
89 msgs: &[&[&str]; N],
90 states: &[State; N],
91 index: &usize,
92) {
93 let mut i = 0;
94 while i < N {
95 if i == *index {
96 i += 1;
97 continue;
98 }
99 match states[i] {
100 State::Ongoing(outer_i) | State::Finished(outer_i) => {
101 if let State::Ongoing(inner_i) = states[*index] {
102 if konst::eq_str(msgs[i][outer_i], msgs[*index][inner_i]) {
103 panic!("Message overlaps between interface and contract impl!");
104 }
105 }
106 }
107 _ => (),
108 }
109 i += 1;
110 }
111}
112
113const fn should_end<const N: usize>(states: &[State; N]) -> bool {
114 konst::for_range! {i in 0..N =>
115 if let State::Ongoing(..) = states[i] {
116 return false;
117 }
118 }
119 true
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn should_not_end() {
128 let states = [State::Empty, State::Ongoing(3), State::Finished(5)];
129 assert!(!super::should_end(&states));
130 }
131
132 #[test]
133 fn should_end() {
134 let states = [State::Empty, State::Finished(3), State::Finished(5)];
135 assert!(super::should_end(&states));
136 }
137
138 #[test]
139 fn init_states() {
140 let msgs: [&[&str]; 3] = [&["msg", "msg"], &[], &["msg"]];
141 let states = [State::Ongoing(0), State::Empty, State::Ongoing(0)];
142 assert_eq!(super::init_states(&msgs), states);
143 }
144
145 #[test]
146 fn aquire_index_when_two_states_ongoing() {
147 let msgs: [&[&str]; 3] = [&["msg_b", "msg_c"], &[], &["msg_a"]];
148 let states = [State::Ongoing(1), State::Empty, State::Ongoing(0)];
149 assert_eq!(get_next_alphabetical_index(&msgs, &states), 2);
150 }
151
152 #[test]
153 fn aquire_index_when_mixed_state() {
154 let msgs: [&[&str]; 3] = [&["msg_b", "msg_c"], &[], &["msg_a"]];
155 let states = [State::Ongoing(1), State::Empty, State::Finished(0)];
156 assert_eq!(get_next_alphabetical_index(&msgs, &states), 0);
157 }
158
159 #[test]
160 fn aquire_index_when_first_array_empty() {
161 let msgs: [&[&str]; 3] = [&[], &["msg_b", "msg_c"], &["msg_a"]];
162 let states = [State::Empty, State::Ongoing(1), State::Finished(0)];
163 assert_eq!(get_next_alphabetical_index(&msgs, &states), 1);
164 }
165
166 #[test]
167 fn verify_no_collissions() {
168 let msgs: [&[&str]; 4] = [&[], &["msg_b", "msg_c"], &["msg_a"], &["msg_d", "msg_a"]];
169 let states = [
170 State::Empty,
171 State::Ongoing(1),
172 State::Finished(0),
173 State::Ongoing(0),
174 ];
175
176 super::verify_no_collissions(&msgs, &states, &1);
177 super::verify_no_collissions(&msgs, &states, &3);
178
179 let states = [
180 State::Empty,
181 State::Ongoing(1),
182 State::Finished(0),
183 State::Ongoing(1),
184 ];
185
186 super::verify_no_collissions(&msgs, &states, &1);
187 }
188
189 #[test]
190 #[should_panic]
191 fn verify_collissions() {
192 let msgs: [&[&str]; 4] = [&[], &["msg_b", "msg_c"], &["msg_a"], &["msg_d", "msg_a"]];
193 let states = [
194 State::Empty,
195 State::Ongoing(1),
196 State::Finished(0),
197 State::Ongoing(1),
198 ];
199
200 super::verify_no_collissions(&msgs, &states, &3);
201 }
202
203 #[test]
204 fn no_intersection() {
205 let msgs: [&[&str]; 5] = [
206 &["msg_b", "msg_c"],
207 &["msg_d", "msg_e", "msg_f"],
208 &["msg_a"],
209 &["msg_g", "msg_h", "msg_i", "msg_j"],
210 &[],
211 ];
212
213 assert_no_intersection(msgs);
214 }
215
216 #[test]
217 #[should_panic]
218 fn intersection() {
219 let msgs: [&[&str]; 5] = [
220 &["msg_b", "msg_c", "msg_i"],
221 &["msg_d", "msg_e", "msg_f"],
222 &["msg_a"],
223 &["msg_g", "msg_h", "msg_i", "msg_j"],
224 &[],
225 ];
226
227 assert_no_intersection(msgs);
228 }
229
230 #[test]
231 fn single_interface_with_no_contract_msgs() {
232 let msgs: [&[&str]; 2] = [&["msg_a", "msg_b"], &[]];
233
234 assert_no_intersection(msgs);
235 }
236}