s2n_quic_core/stream/state/send.rs
1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::state::{event, is};
5
6//= https://www.rfc-editor.org/rfc/rfc9000#section-3.1
7//# o
8//# | Create Stream (Sending)
9//# | Peer Creates Bidirectional Stream
10//# v
11//# +-------+
12//# | Ready | Send RESET_STREAM
13//# | |-----------------------.
14//# +-------+ |
15//# | |
16//# | Send STREAM / |
17//# | STREAM_DATA_BLOCKED |
18//# v |
19//# +-------+ |
20//# | Send | Send RESET_STREAM |
21//# | |---------------------->|
22//# +-------+ |
23//# | |
24//# | Send STREAM + FIN |
25//# v v
26//# +-------+ +-------+
27//# | Data | Send RESET_STREAM | Reset |
28//# | Sent |------------------>| Sent |
29//# +-------+ +-------+
30//# | |
31//# | Recv All ACKs | Recv ACK
32//# v v
33//# +-------+ +-------+
34//# | Data | | Reset |
35//# | Recvd | | Recvd |
36//# +-------+ +-------+
37
38#[derive(Clone, Debug, Default, PartialEq, Eq)]
39pub enum Sender {
40 #[default]
41 Ready,
42 Send,
43 DataSent,
44 DataRecvd,
45 /// An additional state for implementations to separate queueing a RESET_STREAM from actually
46 /// sending it
47 ResetQueued,
48 ResetSent,
49 ResetRecvd,
50}
51
52impl Sender {
53 is!(is_ready, Ready);
54 is!(is_sending, Send);
55 is!(is_data_sent, DataSent);
56 is!(is_data_received, DataRecvd);
57 is!(is_reset_queued, ResetQueued);
58 is!(is_reset_sent, ResetSent);
59 is!(is_reset_received, ResetRecvd);
60 is!(is_terminal, DataRecvd | ResetRecvd);
61
62 event! {
63 on_send_stream(Ready => Send);
64 // we can jump from Ready to DataSent even though the
65 // diagram doesn't explicitly highlight this transition
66 on_send_fin(Ready | Send => DataSent);
67 on_recv_all_acks(DataSent | ResetQueued => DataRecvd);
68
69 on_queue_reset(Ready | Send | DataSent => ResetQueued);
70 on_send_reset(Ready | Send | DataSent | ResetQueued => ResetSent);
71 on_recv_reset_ack(ResetSent => ResetRecvd);
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use insta::{assert_debug_snapshot, assert_snapshot};
79
80 #[test]
81 #[cfg_attr(miri, ignore)]
82 fn snapshots() {
83 assert_debug_snapshot!(Sender::test_transitions());
84 }
85
86 #[test]
87 #[cfg_attr(miri, ignore)]
88 fn dot_test() {
89 assert_snapshot!(Sender::dot());
90 }
91}