Skip to content

Commit c96e57c

Browse files
authored
feat(s2n-quic-core): generate state reactions to events (#2221)
1 parent f23d87b commit c96e57c

File tree

7 files changed

+329
-622
lines changed

7 files changed

+329
-622
lines changed

quic/s2n-quic-core/src/state.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,89 @@ macro_rules! __state_event__ {
105105
);
106106
)*
107107

108+
#[cfg(test)]
109+
pub fn test_transitions() -> impl ::core::fmt::Debug {
110+
use $crate::state::Error;
111+
use ::core::{fmt, result::Result};
112+
113+
let mut all_states = [
114+
// collect all of the states we've observed
115+
$($(
116+
$(
117+
(stringify!($valid), Self::$valid),
118+
)*
119+
(stringify!($target), Self::$target),
120+
)*)*
121+
];
122+
123+
all_states.sort_unstable_by_key(|v| v.0);
124+
let (sorted, _) = $crate::slice::partition_dedup(&mut all_states);
125+
126+
const EVENT_LEN: usize = {
127+
let mut len = 0;
128+
$({
129+
let _ = stringify!($event);
130+
len += 1;
131+
})*
132+
len
133+
};
134+
135+
let apply = |state: &Self| {
136+
[$({
137+
let mut state = state.clone();
138+
let result = state.$event().map(|_| state);
139+
(stringify!($event), result)
140+
}),*]
141+
};
142+
143+
struct Transitions<const L: usize, T, A> {
144+
states: [(&'static str, T); L],
145+
count: usize,
146+
apply: A,
147+
}
148+
149+
impl<const L: usize, T, A> fmt::Debug for Transitions<L, T, A>
150+
where
151+
T: fmt::Debug,
152+
A: Fn(&T) -> [(&'static str, Result<T, Error<T>>); EVENT_LEN],
153+
{
154+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155+
let mut m = f.debug_map();
156+
157+
for (name, state) in self.states.iter().take(self.count) {
158+
let events = (self.apply)(state);
159+
m.entry(&format_args!("{name}"), &Entry(events));
160+
}
161+
162+
m.finish()
163+
}
164+
}
165+
166+
struct Entry<T>([(&'static str, Result<T, Error<T>>); EVENT_LEN]);
167+
168+
impl<T> fmt::Debug for Entry<T>
169+
where
170+
T: fmt::Debug
171+
{
172+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173+
let mut m = f.debug_map();
174+
175+
for (event, outcome) in self.0.iter() {
176+
m.entry(&format_args!("{event}"), outcome);
177+
}
178+
179+
m.finish()
180+
}
181+
}
182+
183+
let count = sorted.len();
184+
Transitions {
185+
states: all_states,
186+
count,
187+
apply,
188+
}
189+
}
190+
108191
/// Generates a dot graph of all state transitions
109192
pub fn dot() -> impl ::core::fmt::Display {
110193
struct Dot;
Lines changed: 35 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,86 @@
11
---
22
source: quic/s2n-quic-core/src/state/tests.rs
3-
expression: outcomes
3+
expression: "State::test_transitions()"
44
---
5-
[
6-
(
7-
Init,
8-
"on_left",
9-
Ok(
5+
{
6+
Init: {
7+
on_left: Ok(
108
Left,
119
),
12-
),
13-
(
14-
Init,
15-
"on_right",
16-
Ok(
10+
on_right: Ok(
1711
Right,
1812
),
19-
),
20-
(
21-
Left,
22-
"on_left",
23-
Ok(
13+
},
14+
Left: {
15+
on_left: Ok(
2416
LeftLeft,
2517
),
26-
),
27-
(
28-
Left,
29-
"on_right",
30-
Ok(
18+
on_right: Ok(
3119
LeftRight,
3220
),
33-
),
34-
(
35-
Right,
36-
"on_left",
37-
Ok(
38-
RightLeft,
39-
),
40-
),
41-
(
42-
Right,
43-
"on_right",
44-
Ok(
45-
RightRight,
46-
),
47-
),
48-
(
49-
LeftLeft,
50-
"on_left",
51-
Err(
21+
},
22+
LeftLeft: {
23+
on_left: Err(
5224
InvalidTransition {
5325
current: LeftLeft,
5426
event: "on_left",
5527
},
5628
),
57-
),
58-
(
59-
LeftLeft,
60-
"on_right",
61-
Err(
29+
on_right: Err(
6230
InvalidTransition {
6331
current: LeftLeft,
6432
event: "on_right",
6533
},
6634
),
67-
),
68-
(
69-
LeftRight,
70-
"on_left",
71-
Err(
35+
},
36+
LeftRight: {
37+
on_left: Err(
7238
InvalidTransition {
7339
current: LeftRight,
7440
event: "on_left",
7541
},
7642
),
77-
),
78-
(
79-
LeftRight,
80-
"on_right",
81-
Err(
43+
on_right: Err(
8244
InvalidTransition {
8345
current: LeftRight,
8446
event: "on_right",
8547
},
8648
),
87-
),
88-
(
89-
RightLeft,
90-
"on_left",
91-
Err(
49+
},
50+
Right: {
51+
on_left: Ok(
52+
RightLeft,
53+
),
54+
on_right: Ok(
55+
RightRight,
56+
),
57+
},
58+
RightLeft: {
59+
on_left: Err(
9260
InvalidTransition {
9361
current: RightLeft,
9462
event: "on_left",
9563
},
9664
),
97-
),
98-
(
99-
RightLeft,
100-
"on_right",
101-
Err(
65+
on_right: Err(
10266
InvalidTransition {
10367
current: RightLeft,
10468
event: "on_right",
10569
},
10670
),
107-
),
108-
(
109-
RightRight,
110-
"on_left",
111-
Err(
71+
},
72+
RightRight: {
73+
on_left: Err(
11274
InvalidTransition {
11375
current: RightRight,
11476
event: "on_left",
11577
},
11678
),
117-
),
118-
(
119-
RightRight,
120-
"on_right",
121-
Err(
79+
on_right: Err(
12280
InvalidTransition {
12381
current: RightRight,
12482
event: "on_right",
12583
},
12684
),
127-
),
128-
]
85+
},
86+
}

quic/s2n-quic-core/src/state/tests.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,7 @@ impl State {
3434
#[test]
3535
#[cfg_attr(miri, ignore)]
3636
fn snapshots() {
37-
let mut outcomes = vec![];
38-
let states = [
39-
State::Init,
40-
State::Left,
41-
State::Right,
42-
State::LeftLeft,
43-
State::LeftRight,
44-
State::RightLeft,
45-
State::RightRight,
46-
];
47-
for state in states {
48-
macro_rules! push {
49-
($event:ident) => {
50-
let mut target = state.clone();
51-
let result = target.$event().map(|_| target);
52-
outcomes.push((state.clone(), stringify!($event), result));
53-
};
54-
}
55-
push!(on_left);
56-
push!(on_right);
57-
}
58-
59-
assert_debug_snapshot!(outcomes);
37+
assert_debug_snapshot!(State::test_transitions());
6038
}
6139

6240
#[test]

quic/s2n-quic-core/src/stream/state/recv.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,31 +74,7 @@ mod tests {
7474
#[test]
7575
#[cfg_attr(miri, ignore)]
7676
fn snapshots() {
77-
let mut outcomes = vec![];
78-
let states = [
79-
Receiver::Recv,
80-
Receiver::SizeKnown,
81-
Receiver::DataRecvd,
82-
Receiver::DataRead,
83-
Receiver::ResetRecvd,
84-
Receiver::ResetRead,
85-
];
86-
for state in states {
87-
macro_rules! push {
88-
($event:ident) => {
89-
let mut target = state.clone();
90-
let result = target.$event().map(|_| target);
91-
outcomes.push((state.clone(), stringify!($event), result));
92-
};
93-
}
94-
push!(on_receive_fin);
95-
push!(on_receive_all_data);
96-
push!(on_app_read_all_data);
97-
push!(on_reset);
98-
push!(on_app_read_reset);
99-
}
100-
101-
assert_debug_snapshot!(outcomes);
77+
assert_debug_snapshot!(Receiver::test_transitions());
10278
}
10379

10480
#[test]

quic/s2n-quic-core/src/stream/state/send.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,33 +80,7 @@ mod tests {
8080
#[test]
8181
#[cfg_attr(miri, ignore)]
8282
fn snapshots() {
83-
let mut outcomes = vec![];
84-
let states = [
85-
Sender::Ready,
86-
Sender::Send,
87-
Sender::DataSent,
88-
Sender::DataRecvd,
89-
Sender::ResetQueued,
90-
Sender::ResetSent,
91-
Sender::ResetRecvd,
92-
];
93-
for state in states {
94-
macro_rules! push {
95-
($event:ident) => {
96-
let mut target = state.clone();
97-
let result = target.$event().map(|_| target);
98-
outcomes.push((state.clone(), stringify!($event), result));
99-
};
100-
}
101-
push!(on_send_stream);
102-
push!(on_send_fin);
103-
push!(on_queue_reset);
104-
push!(on_send_reset);
105-
push!(on_recv_all_acks);
106-
push!(on_recv_reset_ack);
107-
}
108-
109-
assert_debug_snapshot!(outcomes);
83+
assert_debug_snapshot!(Sender::test_transitions());
11084
}
11185

11286
#[test]

0 commit comments

Comments
 (0)