Skip to main content

pg_proto/
grammar.rs

1//! Generated `PostgreSQL` grammars and differential-test runtime FSMs.
2//!
3//! Each generated role module embeds its railroad diagram directly in its
4//! rustdoc landing page. Open a module such as [`frontend`] or [`backend`] to
5//! review the grammar alongside its generated transition API.
6
7use pg_proto_fsm::protocol;
8
9protocol! {
10    pub mod frontend {
11        initial Ready;
12        messages {
13            internal: crate::codec::FrontendMessage,
14            external: crate::codec::BackendMessage,
15        }
16        associations {
17            interface: crate::middleware::PhaseAssociation;
18            seal: crate::middleware::phase_association_seal::Sealed;
19            inbound {
20                direction: crate::middleware::Inbound;
21                role: crate::middleware::ServerRole;
22                wire: crate::codec::BackendMessage;
23                message: crate::middleware::TypedBackendMessage<external>;
24            }
25            outbound {
26                direction: crate::middleware::Outbound;
27                role: crate::middleware::ClientRole;
28                wire: crate::codec::FrontendMessage;
29                message: internal;
30            }
31        }
32        Ready internal {
33            associate { inbound: crate::auth::Ready; outbound: crate::auth::Ready; }
34            Query(query: bytes::Bytes) => Simple [Dirty] <= crate::codec::FrontendMessage::Query(_),
35            BeginExtended(begin_extended) => Building,
36            FunctionCall(function_call: crate::codec::FunctionCall) => FunctionCalling [Dirty] <= crate::codec::FrontendMessage::FunctionCall(_),
37            Reset(reset) => Resetting [Dirty],
38            Terminate(terminate) => Terminated <= crate::codec::FrontendMessage::Terminate,
39        }
40        FunctionCalling external {
41            associate { inbound: crate::session::FunctionCalling; outbound: none; }
42            FunctionResponse(function_response: bytes::Bytes) => AwaitingReady <= crate::codec::BackendMessage::FunctionCallResponse(_),
43            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
44        }
45        Simple external {
46            associate { inbound: crate::session::SimpleQuery; outbound: none; }
47            Continue(continue_response: crate::codec::BackendMessage) => Simple <= crate::codec::BackendMessage::RowDescription(_)
48                | crate::codec::BackendMessage::DataRow(_)
49                | crate::codec::BackendMessage::CommandComplete(_)
50                | crate::codec::BackendMessage::EmptyQueryResponse,
51            CopyIn(enter_copy_in: crate::codec::CopyResponse) => CopyIn <= crate::codec::BackendMessage::CopyInResponse(_),
52            CopyOut(enter_copy_out: crate::codec::CopyResponse) => CopyOut <= crate::codec::BackendMessage::CopyOutResponse(_),
53            CopyBoth(enter_copy_both: crate::codec::CopyResponse) => CopyBoth <= crate::codec::BackendMessage::CopyBothResponse(_),
54            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
55            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
56        }
57        Building internal {
58            associate { inbound: crate::session::Building; outbound: crate::session::Building; }
59            Parse(parse: crate::codec::Parse) => Building [Dirty] <= crate::codec::FrontendMessage::Parse(_),
60            Describe(describe: crate::codec::Describe) => Building <= crate::codec::FrontendMessage::Describe(_),
61            Bind(bind: crate::codec::Bind) => BoundBuilding [Dirty] <= crate::codec::FrontendMessage::Bind(_),
62            Close(close: crate::codec::Close) => Building <= crate::codec::FrontendMessage::Close(_),
63            Flush(flush) => Building <= crate::codec::FrontendMessage::Flush,
64            Sync(sync) => AwaitingReady <= crate::codec::FrontendMessage::Sync,
65        }
66        BoundBuilding internal {
67            associate { inbound: crate::session::BoundBuilding; outbound: crate::session::BoundBuilding; }
68            Parse(parse: crate::codec::Parse) => BoundBuilding [Dirty] <= crate::codec::FrontendMessage::Parse(_),
69            Describe(describe: crate::codec::Describe) => BoundBuilding <= crate::codec::FrontendMessage::Describe(_),
70            Bind(bind: crate::codec::Bind) => BoundBuilding [Dirty] <= crate::codec::FrontendMessage::Bind(_),
71            Execute(execute: crate::codec::Execute) => BoundBuilding <= crate::codec::FrontendMessage::Execute(_),
72            Close(close: crate::codec::Close) => BoundBuilding <= crate::codec::FrontendMessage::Close(_),
73            Flush(flush) => BoundBuilding <= crate::codec::FrontendMessage::Flush,
74            Sync(sync) => AwaitingReady <= crate::codec::FrontendMessage::Sync,
75        }
76        AwaitingReady external {
77            associate { inbound: crate::session::AwaitingReady; outbound: none; }
78            Continue(continue_response: crate::codec::BackendMessage) => AwaitingReady <= crate::codec::BackendMessage::ParseComplete
79                | crate::codec::BackendMessage::BindComplete
80                | crate::codec::BackendMessage::CloseComplete
81                | crate::codec::BackendMessage::RowDescription(_)
82                | crate::codec::BackendMessage::NoData
83                | crate::codec::BackendMessage::ParameterDescription(_)
84                | crate::codec::BackendMessage::DataRow(_)
85                | crate::codec::BackendMessage::CommandComplete(_)
86                | crate::codec::BackendMessage::PortalSuspended
87                | crate::codec::BackendMessage::EmptyQueryResponse,
88            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
89            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
90        }
91        CopyIn mixed {
92            associate { inbound: crate::session::CopyIn; outbound: crate::session::CopyIn; }
93            internal CopyData(copy_data: bytes::Bytes) => CopyIn <= crate::codec::FrontendMessage::CopyData(_),
94            internal CopyDone(copy_done) => AwaitingReady <= crate::codec::FrontendMessage::CopyDone,
95            internal CopyFail(copy_fail: bytes::Bytes) => AwaitingReady <= crate::codec::FrontendMessage::CopyFail(_),
96            external Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
97        }
98        CopyOut external {
99            associate { inbound: crate::session::CopyOut; outbound: none; }
100            CopyData(copy_data: bytes::Bytes) => CopyOut <= crate::codec::BackendMessage::CopyData(_),
101            CopyDone(copy_done) => AwaitingReady <= crate::codec::BackendMessage::CopyDone,
102            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
103        }
104        CopyBoth mixed {
105            associate { inbound: crate::session::CopyBoth; outbound: crate::session::CopyBoth; }
106            internal SendCopyData(send_copy_data: bytes::Bytes) => CopyBoth <= crate::codec::FrontendMessage::CopyData(_),
107            external ReceiveCopyData(receive_copy_data: bytes::Bytes) => CopyBoth <= crate::codec::BackendMessage::CopyData(_),
108            internal SendCopyDone(send_copy_done) => CopyBothClientDone <= crate::codec::FrontendMessage::CopyDone,
109            external ReceiveCopyDone(receive_copy_done) => CopyBothServerDone <= crate::codec::BackendMessage::CopyDone,
110            external Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
111        }
112        CopyBothClientDone external {
113            associate { inbound: crate::session::CopyBothClientDone; outbound: none; }
114            ReceiveCopyData(receive_copy_data: bytes::Bytes) => CopyBothClientDone <= crate::codec::BackendMessage::CopyData(_),
115            ReceiveCopyDone(receive_copy_done) => AwaitingReady <= crate::codec::BackendMessage::CopyDone,
116            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
117        }
118        CopyBothServerDone internal {
119            associate { inbound: crate::session::CopyBothServerDone; outbound: crate::session::CopyBothServerDone; }
120            SendCopyData(send_copy_data: bytes::Bytes) => CopyBothServerDone <= crate::codec::FrontendMessage::CopyData(_),
121            SendCopyDone(send_copy_done) => AwaitingReady <= crate::codec::FrontendMessage::CopyDone,
122        }
123        Draining external {
124            associate { inbound: crate::session::Draining; outbound: none; }
125            Continue(continue_response: crate::codec::BackendMessage) => Draining <= crate::codec::BackendMessage::RowDescription(_)
126                | crate::codec::BackendMessage::DataRow(_)
127                | crate::codec::BackendMessage::CommandComplete(_)
128                | crate::codec::BackendMessage::EmptyQueryResponse
129                | crate::codec::BackendMessage::ParseComplete
130                | crate::codec::BackendMessage::BindComplete
131                | crate::codec::BackendMessage::CloseComplete
132                | crate::codec::BackendMessage::NoData
133                | crate::codec::BackendMessage::ParameterDescription(_)
134                | crate::codec::BackendMessage::PortalSuspended,
135            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
136        }
137        Resetting external {
138            associate { inbound: crate::session::Resetting; outbound: none; }
139            Continue(continue_reset: crate::codec::BackendMessage) => Resetting <= crate::codec::BackendMessage::RowDescription(_)
140                | crate::codec::BackendMessage::DataRow(_)
141                | crate::codec::BackendMessage::EmptyQueryResponse,
142            DiscardComplete(discard_complete: bytes::Bytes) => ResetComplete <= crate::codec::BackendMessage::CommandComplete(_),
143            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
144        }
145        ResetComplete external {
146            associate { inbound: crate::session::ResetComplete; outbound: none; }
147            Continue(continue_reset: crate::codec::BackendMessage) => ResetComplete <= crate::codec::BackendMessage::RowDescription(_)
148                | crate::codec::BackendMessage::DataRow(_)
149                | crate::codec::BackendMessage::CommandComplete(_)
150                | crate::codec::BackendMessage::EmptyQueryResponse,
151            ReadyClean(ready_clean: crate::codec::TransactionStatus) => Ready [Pristine] <= crate::codec::BackendMessage::ReadyForQuery(crate::codec::TransactionStatus::Idle),
152            ReadyDirty(ready_dirty: crate::codec::TransactionStatus) => Ready [Dirty] <= crate::codec::BackendMessage::ReadyForQuery(crate::codec::TransactionStatus::InTransaction | crate::codec::TransactionStatus::FailedTransaction),
153            Error(error: crate::codec::DiagnosticResponse) => Draining <= crate::codec::BackendMessage::ErrorResponse(_),
154        }
155        Terminated external {
156            associate { inbound: none; outbound: none; }
157        }
158    }
159}
160
161protocol! {
162    pub mod pre_startup {
163        initial PreStartup;
164        messages {
165            internal: crate::pre_startup::PreStartupMessage,
166            external: crate::pre_startup::EncryptionReply,
167        }
168        associations {
169            interface: crate::middleware::PhaseAssociation;
170            seal: crate::middleware::phase_association_seal::Sealed;
171            inbound {
172                direction: crate::middleware::Inbound;
173                role: crate::middleware::ServerRole;
174                wire: crate::pre_startup::EncryptionReply;
175                message: external;
176            }
177            outbound {
178                direction: crate::middleware::Outbound;
179                role: crate::middleware::ClientRole;
180                wire: crate::pre_startup::PreStartupMessage;
181                message: internal;
182            }
183        }
184        PreStartup internal {
185            associate { inbound: none; outbound: crate::pre_startup::PreStartup; }
186            SslRequest(ssl_request) => AwaitingSslReply <= crate::pre_startup::PreStartupMessage::SslRequest,
187            GssRequest(gss_request) => AwaitingGssReply <= crate::pre_startup::PreStartupMessage::GssEncRequest,
188            Cancel(cancel: (u32, bytes::Bytes)) => Terminated <= crate::pre_startup::PreStartupMessage::CancelRequest { .. },
189            Startup(startup: crate::startup::StartupMessage) => Auth <= crate::pre_startup::PreStartupMessage::Startup(_),
190        }
191        AwaitingSslReply external {
192            associate { inbound: crate::pre_startup::AwaitingSslReply; outbound: none; }
193            Accept(accept) => TlsHandshake <= crate::pre_startup::EncryptionReply::Accepted,
194            Reject(reject) => PreStartup <= crate::pre_startup::EncryptionReply::Rejected,
195            LegacyError(legacy_error) => Terminated <= crate::pre_startup::EncryptionReply::LegacyError,
196        }
197        AwaitingGssReply external {
198            associate { inbound: crate::pre_startup::AwaitingGssReply; outbound: none; }
199            Accept(accept) => GssHandshake <= crate::pre_startup::EncryptionReply::Accepted,
200            Reject(reject) => PreStartup <= crate::pre_startup::EncryptionReply::Rejected,
201            LegacyError(legacy_error) => Terminated <= crate::pre_startup::EncryptionReply::LegacyError,
202        }
203        TlsHandshake internal {
204            associate { inbound: none; outbound: none; }
205            HandshakeComplete(complete) => PreStartup,
206        }
207        GssHandshake internal {
208            associate { inbound: none; outbound: none; }
209            HandshakeComplete(complete) => PreStartup,
210        }
211        Auth external {
212            associate { inbound: none; outbound: none; }
213        }
214        Terminated external {
215            associate { inbound: none; outbound: none; }
216        }
217    }
218}
219
220protocol! {
221    pub mod server_pre_startup {
222        initial PreStartup;
223        messages {
224            internal: crate::pre_startup::EncryptionReply,
225            external: crate::pre_startup::PreStartupMessage,
226        }
227        associations {
228            interface: crate::middleware::PhaseAssociation;
229            seal: crate::middleware::phase_association_seal::Sealed;
230            inbound {
231                direction: crate::middleware::Inbound;
232                role: crate::middleware::ClientRole;
233                wire: crate::pre_startup::PreStartupMessage;
234                message: external;
235            }
236            outbound {
237                direction: crate::middleware::Outbound;
238                role: crate::middleware::ServerRole;
239                wire: crate::pre_startup::EncryptionReply;
240                message: internal;
241            }
242        }
243        PreStartup external {
244            associate { inbound: crate::pre_startup::PreStartup; outbound: none; }
245            SslRequest(ssl_request) => SslDecision <= crate::pre_startup::PreStartupMessage::SslRequest,
246            GssRequest(gss_request) => GssDecision <= crate::pre_startup::PreStartupMessage::GssEncRequest,
247            Cancel(cancel: (u32, bytes::Bytes)) => Terminated <= crate::pre_startup::PreStartupMessage::CancelRequest { .. },
248            Startup(startup: crate::startup::StartupMessage) => Auth <= crate::pre_startup::PreStartupMessage::Startup(_),
249        }
250        SslDecision internal {
251            associate { inbound: none; outbound: crate::pre_startup::ServerSslDecision; }
252            Accept(accept) => TlsHandshake <= crate::pre_startup::EncryptionReply::Accepted,
253            Reject(reject) => PreStartup <= crate::pre_startup::EncryptionReply::Rejected,
254            LegacyError(legacy_error) => Terminated <= crate::pre_startup::EncryptionReply::LegacyError,
255        }
256        GssDecision internal {
257            associate { inbound: none; outbound: crate::pre_startup::ServerGssDecision; }
258            Accept(accept) => GssHandshake <= crate::pre_startup::EncryptionReply::Accepted,
259            Reject(reject) => PreStartup <= crate::pre_startup::EncryptionReply::Rejected,
260            LegacyError(legacy_error) => Terminated <= crate::pre_startup::EncryptionReply::LegacyError,
261        }
262        TlsHandshake internal {
263            associate { inbound: none; outbound: none; }
264            HandshakeComplete(complete) => PreStartup,
265        }
266        GssHandshake internal {
267            associate { inbound: none; outbound: none; }
268            HandshakeComplete(complete) => PreStartup,
269        }
270        Auth internal {
271            associate { inbound: none; outbound: none; }
272        }
273        Terminated internal {
274            associate { inbound: none; outbound: none; }
275        }
276    }
277}
278
279protocol! {
280    pub mod authentication {
281        initial Auth;
282        messages {
283            internal: crate::codec::FrontendMessage,
284            external: crate::codec::BackendMessage,
285        }
286        associations {
287            interface: crate::middleware::PhaseAssociation;
288            seal: crate::middleware::phase_association_seal::Sealed;
289            inbound {
290                direction: crate::middleware::Inbound;
291                role: crate::middleware::ServerRole;
292                wire: crate::codec::BackendMessage;
293                message: crate::middleware::TypedBackendMessage<external>;
294            }
295            outbound {
296                direction: crate::middleware::Outbound;
297                role: crate::middleware::ClientRole;
298                wire: crate::codec::FrontendMessage;
299                message: internal;
300            }
301        }
302        Auth external {
303            associate { inbound: crate::auth::Auth; outbound: none; }
304            Negotiate(negotiate: crate::codec::NegotiateProtocolVersion) => Auth <= crate::codec::BackendMessage::NegotiateProtocolVersion(_),
305            Ok(ok) => AwaitingStartupReady <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Ok),
306            Cleartext(cleartext) => PasswordResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::CleartextPassword),
307            Md5(md5: [u8; 4]) => PasswordResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Md5Password { .. }),
308            Sasl(sasl: Vec<bytes::Bytes>) => SaslInitial <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Sasl { .. }),
309            Gss(gss) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Gss),
310            Sspi(sspi) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Sspi),
311            KerberosV5(kerberos_v5) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::KerberosV5),
312            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
313        }
314        PasswordResponse internal {
315            associate { inbound: none; outbound: crate::auth::PasswordResponse; }
316            Password(password: bytes::Bytes) => AwaitingAuthOk <= crate::codec::FrontendMessage::PasswordResponse(_),
317        }
318        TokenResponse internal {
319            associate { inbound: none; outbound: crate::auth::TokenResponse; }
320            Response(response: bytes::Bytes) => TokenChallenge <= crate::codec::FrontendMessage::PasswordResponse(_),
321        }
322        TokenChallenge external {
323            associate { inbound: crate::auth::TokenChallenge; outbound: none; }
324            Continue(continue_token: bytes::Bytes) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::GssContinue(_)),
325            Ok(ok) => AwaitingStartupReady <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Ok),
326            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
327        }
328        SaslInitial internal {
329            associate { inbound: none; outbound: crate::auth::SaslInitial; }
330            Initial(initial: crate::server_auth::SaslInitialResponse) => Sasl <= crate::codec::FrontendMessage::PasswordResponse(_),
331        }
332        Sasl external {
333            associate { inbound: crate::auth::Sasl; outbound: none; }
334            Continue(continue_response: bytes::Bytes) => SaslChallenge <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::SaslContinue(_)),
335            Final(final_response: bytes::Bytes) => SaslFinal <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::SaslFinal(_)),
336            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
337        }
338        SaslChallenge internal {
339            associate { inbound: none; outbound: crate::auth::SaslChallenge; }
340            Response(response: bytes::Bytes) => Sasl <= crate::codec::FrontendMessage::PasswordResponse(_),
341        }
342        SaslFinal internal {
343            associate { inbound: none; outbound: none; }
344            Verified(verified) => AwaitingAuthOk,
345        }
346        AwaitingAuthOk external {
347            associate { inbound: crate::auth::AwaitingAuthOk; outbound: none; }
348            Ok(ok) => AwaitingStartupReady <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Ok),
349            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
350        }
351        AwaitingStartupReady external {
352            associate { inbound: crate::auth::AwaitingStartupReady; outbound: none; }
353            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
354        }
355        Ready external {
356            associate { inbound: none; outbound: none; }
357        }
358        Terminated external {
359            associate { inbound: none; outbound: none; }
360        }
361    }
362}
363
364protocol! {
365    pub mod backend {
366        initial Ready;
367        messages {
368            internal: crate::codec::BackendMessage,
369            external: crate::codec::FrontendMessage,
370        }
371        associations {
372            interface: crate::middleware::PhaseAssociation;
373            seal: crate::middleware::phase_association_seal::Sealed;
374            inbound {
375                direction: crate::middleware::Inbound;
376                role: crate::middleware::ClientRole;
377                wire: crate::codec::FrontendMessage;
378                message: external;
379            }
380            outbound {
381                direction: crate::middleware::Outbound;
382                role: crate::middleware::ServerRole;
383                wire: crate::codec::BackendMessage;
384                message: crate::middleware::TypedBackendMessage<internal>;
385            }
386        }
387        Ready external {
388            associate { inbound: crate::auth::Ready; outbound: none; }
389            Query(query: bytes::Bytes) => Simple [Dirty] <= crate::codec::FrontendMessage::Query(_),
390            Parse(parse: crate::codec::Parse) => ParseResponse [Dirty] <= crate::codec::FrontendMessage::Parse(_),
391            Bind(bind: crate::codec::Bind) => BindResponse [Dirty] <= crate::codec::FrontendMessage::Bind(_),
392            Describe(describe: crate::codec::Describe) => DescribeResponse <= crate::codec::FrontendMessage::Describe(_),
393            Execute(execute: crate::codec::Execute) => ExecuteResponse [Dirty] <= crate::codec::FrontendMessage::Execute(_),
394            Close(close: crate::codec::Close) => CloseResponse <= crate::codec::FrontendMessage::Close(_),
395            FunctionCall(function_call: crate::codec::FunctionCall) => FunctionResponse [Dirty] <= crate::codec::FrontendMessage::FunctionCall(_),
396            Terminate(terminate) => Terminated <= crate::codec::FrontendMessage::Terminate,
397        }
398        Simple internal {
399            associate { inbound: none; outbound: crate::server_session::ServerSimpleQuery; }
400            Continue(continue_response: crate::codec::BackendMessage) => Simple <= crate::codec::BackendMessage::RowDescription(_)
401                | crate::codec::BackendMessage::DataRow(_)
402                | crate::codec::BackendMessage::CommandComplete(_)
403                | crate::codec::BackendMessage::EmptyQueryResponse,
404            CopyIn(copy_in: crate::codec::CopyResponse) => SimpleCopyIn <= crate::codec::BackendMessage::CopyInResponse(_),
405            CopyOut(copy_out: crate::codec::CopyResponse) => SimpleCopyOut <= crate::codec::BackendMessage::CopyOutResponse(_),
406            CopyBoth(copy_both: crate::codec::CopyResponse) => SimpleCopyBoth <= crate::codec::BackendMessage::CopyBothResponse(_),
407            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
408            Error(error: crate::codec::DiagnosticResponse) => SimpleError <= crate::codec::BackendMessage::ErrorResponse(_),
409        }
410        SimpleError internal {
411            associate { inbound: none; outbound: crate::server_session::ServerSimpleError; }
412            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
413        }
414        Building external {
415            associate { inbound: crate::server_session::ServerBuilding; outbound: crate::server_session::ServerBuilding; }
416            Parse(parse: crate::codec::Parse) => ParseResponse [Dirty] <= crate::codec::FrontendMessage::Parse(_),
417            Bind(bind: crate::codec::Bind) => BindResponse [Dirty] <= crate::codec::FrontendMessage::Bind(_),
418            Describe(describe: crate::codec::Describe) => DescribeResponse <= crate::codec::FrontendMessage::Describe(_),
419            Execute(execute: crate::codec::Execute) => ExecuteResponse [Dirty] <= crate::codec::FrontendMessage::Execute(_),
420            Close(close: crate::codec::Close) => CloseResponse <= crate::codec::FrontendMessage::Close(_),
421            Flush(flush) => Building <= crate::codec::FrontendMessage::Flush,
422            Sync(sync) => SyncResponse <= crate::codec::FrontendMessage::Sync,
423        }
424        ParseResponse internal {
425            associate { inbound: none; outbound: crate::server_session::ServerParse; }
426            Complete(complete) => Building <= crate::codec::BackendMessage::ParseComplete,
427            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
428        }
429        BindResponse internal {
430            associate { inbound: none; outbound: crate::server_session::ServerBind; }
431            Complete(complete) => Building <= crate::codec::BackendMessage::BindComplete,
432            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
433        }
434        DescribeResponse internal {
435            associate { inbound: none; outbound: crate::server_session::ServerDescribe; }
436            ParameterDescription(parameter_description: Vec<u32>) => DescribeResponse <= crate::codec::BackendMessage::ParameterDescription(_),
437            RowDescription(row_description: crate::codec::RowDescription) => Building <= crate::codec::BackendMessage::RowDescription(_),
438            NoData(no_data) => Building <= crate::codec::BackendMessage::NoData,
439            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
440        }
441        ExecuteResponse internal {
442            associate { inbound: none; outbound: crate::server_session::ServerExecute; }
443            Continue(continue_response: crate::codec::BackendMessage) => ExecuteResponse <= crate::codec::BackendMessage::RowDescription(_)
444                | crate::codec::BackendMessage::DataRow(_)
445                | crate::codec::BackendMessage::EmptyQueryResponse,
446            CopyIn(copy_in: crate::codec::CopyResponse) => ExtendedCopyIn <= crate::codec::BackendMessage::CopyInResponse(_),
447            CopyOut(copy_out: crate::codec::CopyResponse) => ExtendedCopyOut <= crate::codec::BackendMessage::CopyOutResponse(_),
448            CopyBoth(copy_both: crate::codec::CopyResponse) => ExtendedCopyBoth <= crate::codec::BackendMessage::CopyBothResponse(_),
449            CommandComplete(command_complete: bytes::Bytes) => Building <= crate::codec::BackendMessage::CommandComplete(_),
450            PortalSuspended(portal_suspended) => Building <= crate::codec::BackendMessage::PortalSuspended,
451            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
452        }
453        CloseResponse internal {
454            associate { inbound: none; outbound: crate::server_session::ServerClose; }
455            Complete(complete) => Building <= crate::codec::BackendMessage::CloseComplete,
456            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
457        }
458        ExtendedError external {
459            associate { inbound: crate::server_session::ServerExtendedError; outbound: crate::server_session::ServerExtendedError; }
460            Discard(discard) => ExtendedError <= crate::codec::FrontendMessage::Parse(_)
461                | crate::codec::FrontendMessage::Bind(_)
462                | crate::codec::FrontendMessage::Describe(_)
463                | crate::codec::FrontendMessage::Execute(_)
464                | crate::codec::FrontendMessage::Close(_)
465                | crate::codec::FrontendMessage::Flush
466                | crate::codec::FrontendMessage::Query(_)
467                | crate::codec::FrontendMessage::FunctionCall(_)
468                | crate::codec::FrontendMessage::Terminate
469                | crate::codec::FrontendMessage::CopyData(_)
470                | crate::codec::FrontendMessage::CopyDone
471                | crate::codec::FrontendMessage::CopyFail(_)
472                | crate::codec::FrontendMessage::PasswordResponse(_),
473            Sync(sync) => SyncResponse <= crate::codec::FrontendMessage::Sync,
474        }
475        SyncResponse internal {
476            associate { inbound: none; outbound: crate::server_session::ServerSync; }
477            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
478        }
479        FunctionResponse internal {
480            associate { inbound: none; outbound: crate::server_session::ServerFunctionCall; }
481            Result(result: bytes::Bytes) => FunctionReady <= crate::codec::BackendMessage::FunctionCallResponse(_),
482            Error(error: crate::codec::DiagnosticResponse) => FunctionReady <= crate::codec::BackendMessage::ErrorResponse(_),
483        }
484        FunctionReady internal {
485            associate { inbound: none; outbound: [crate::server_session::ServerFunctionCallDone, crate::server_session::ServerFunctionCallError]; }
486            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
487        }
488        SimpleCopyIn external {
489            associate {
490                inbound: crate::server_session::ServerCopyIn<crate::server_session::CopySimple>;
491                outbound: crate::server_session::ServerCopyIn<crate::server_session::CopySimple>;
492            }
493            Data(data: bytes::Bytes) => SimpleCopyIn <= crate::codec::FrontendMessage::CopyData(_),
494            Done(done) => SimpleCopyInDone <= crate::codec::FrontendMessage::CopyDone,
495            Fail(fail: bytes::Bytes) => SimpleCopyInFailed <= crate::codec::FrontendMessage::CopyFail(_),
496        }
497        SimpleCopyInDone internal {
498            associate { inbound: none; outbound: crate::server_session::ServerCopyInDone<crate::server_session::CopySimple>; }
499            CommandComplete(command_complete: bytes::Bytes) => SimpleCopyReady <= crate::codec::BackendMessage::CommandComplete(_),
500        }
501        SimpleCopyInFailed internal {
502            associate { inbound: none; outbound: crate::server_session::ServerCopyInFailed<crate::server_session::CopySimple>; }
503            Error(error: crate::codec::DiagnosticResponse) => SimpleCopyReady <= crate::codec::BackendMessage::ErrorResponse(_),
504        }
505        SimpleCopyOut internal {
506            associate { inbound: none; outbound: crate::server_session::ServerCopyOut<crate::server_session::CopySimple>; }
507            Data(data: bytes::Bytes) => SimpleCopyOut <= crate::codec::BackendMessage::CopyData(_),
508            Done(done) => SimpleCopyOutDone <= crate::codec::BackendMessage::CopyDone,
509            Error(error: crate::codec::DiagnosticResponse) => SimpleCopyReady <= crate::codec::BackendMessage::ErrorResponse(_),
510        }
511        SimpleCopyOutDone internal {
512            associate { inbound: none; outbound: crate::server_session::ServerCopyOutDone<crate::server_session::CopySimple>; }
513            CommandComplete(command_complete: bytes::Bytes) => SimpleCopyReady <= crate::codec::BackendMessage::CommandComplete(_),
514        }
515        SimpleCopyReady internal {
516            associate { inbound: none; outbound: none; }
517            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
518        }
519        ExtendedCopyIn external {
520            associate {
521                inbound: crate::server_session::ServerCopyIn<crate::server_session::CopyExtended>;
522                outbound: crate::server_session::ServerCopyIn<crate::server_session::CopyExtended>;
523            }
524            Data(data: bytes::Bytes) => ExtendedCopyIn <= crate::codec::FrontendMessage::CopyData(_),
525            Done(done) => ExtendedCopyInDone <= crate::codec::FrontendMessage::CopyDone,
526            Fail(fail: bytes::Bytes) => ExtendedCopyInFailed <= crate::codec::FrontendMessage::CopyFail(_),
527        }
528        ExtendedCopyInDone internal {
529            associate { inbound: none; outbound: crate::server_session::ServerCopyInDone<crate::server_session::CopyExtended>; }
530            CommandComplete(command_complete: bytes::Bytes) => Building <= crate::codec::BackendMessage::CommandComplete(_),
531        }
532        ExtendedCopyInFailed internal {
533            associate { inbound: none; outbound: crate::server_session::ServerCopyInFailed<crate::server_session::CopyExtended>; }
534            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
535        }
536        ExtendedCopyOut internal {
537            associate { inbound: none; outbound: crate::server_session::ServerCopyOut<crate::server_session::CopyExtended>; }
538            Data(data: bytes::Bytes) => ExtendedCopyOut <= crate::codec::BackendMessage::CopyData(_),
539            Done(done) => ExtendedCopyOutDone <= crate::codec::BackendMessage::CopyDone,
540            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
541        }
542        ExtendedCopyOutDone internal {
543            associate { inbound: none; outbound: crate::server_session::ServerCopyOutDone<crate::server_session::CopyExtended>; }
544            CommandComplete(command_complete: bytes::Bytes) => Building <= crate::codec::BackendMessage::CommandComplete(_),
545        }
546        SimpleCopyBoth mixed {
547            associate {
548                inbound: crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothOpen>;
549                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothOpen>;
550            }
551            internal SendData(send_data: bytes::Bytes) => SimpleCopyBoth <= crate::codec::BackendMessage::CopyData(_),
552            external ReceiveData(receive_data: bytes::Bytes) => SimpleCopyBoth <= crate::codec::FrontendMessage::CopyData(_),
553            internal SendDone(send_done) => SimpleCopyBothServerDone <= crate::codec::BackendMessage::CopyDone,
554            external ReceiveDone(receive_done) => SimpleCopyBothClientDone <= crate::codec::FrontendMessage::CopyDone,
555            external Fail(fail: bytes::Bytes) => SimpleCopyBothFailed <= crate::codec::FrontendMessage::CopyFail(_),
556            internal Error(error: crate::codec::DiagnosticResponse) => SimpleCopyReady <= crate::codec::BackendMessage::ErrorResponse(_),
557        }
558        SimpleCopyBothClientDone internal {
559            associate {
560                inbound: none;
561                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothClientDone>;
562            }
563            SendData(send_data: bytes::Bytes) => SimpleCopyBothClientDone <= crate::codec::BackendMessage::CopyData(_),
564            SendDone(send_done) => SimpleCopyBothDone <= crate::codec::BackendMessage::CopyDone,
565            Error(error: crate::codec::DiagnosticResponse) => SimpleCopyReady <= crate::codec::BackendMessage::ErrorResponse(_),
566        }
567        SimpleCopyBothServerDone external {
568            associate {
569                inbound: crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothServerDone>;
570                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothServerDone>;
571            }
572            ReceiveData(receive_data: bytes::Bytes) => SimpleCopyBothServerDone <= crate::codec::FrontendMessage::CopyData(_),
573            ReceiveDone(receive_done) => SimpleCopyBothDone <= crate::codec::FrontendMessage::CopyDone,
574            Fail(fail: bytes::Bytes) => SimpleCopyBothFailed <= crate::codec::FrontendMessage::CopyFail(_),
575        }
576        SimpleCopyBothDone internal {
577            associate {
578                inbound: none;
579                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopySimple, crate::server_session::BothDone>;
580            }
581            CommandComplete(command_complete: bytes::Bytes) => SimpleCopyReady <= crate::codec::BackendMessage::CommandComplete(_),
582        }
583        SimpleCopyBothFailed internal {
584            associate { inbound: none; outbound: crate::server_session::ServerCopyBothFailed<crate::server_session::CopySimple>; }
585            Error(error: crate::codec::DiagnosticResponse) => SimpleCopyReady <= crate::codec::BackendMessage::ErrorResponse(_),
586        }
587        ExtendedCopyBoth mixed {
588            associate {
589                inbound: crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothOpen>;
590                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothOpen>;
591            }
592            internal SendData(send_data: bytes::Bytes) => ExtendedCopyBoth <= crate::codec::BackendMessage::CopyData(_),
593            external ReceiveData(receive_data: bytes::Bytes) => ExtendedCopyBoth <= crate::codec::FrontendMessage::CopyData(_),
594            internal SendDone(send_done) => ExtendedCopyBothServerDone <= crate::codec::BackendMessage::CopyDone,
595            external ReceiveDone(receive_done) => ExtendedCopyBothClientDone <= crate::codec::FrontendMessage::CopyDone,
596            external Fail(fail: bytes::Bytes) => ExtendedCopyBothFailed <= crate::codec::FrontendMessage::CopyFail(_),
597            internal Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
598        }
599        ExtendedCopyBothClientDone internal {
600            associate {
601                inbound: none;
602                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothClientDone>;
603            }
604            SendData(send_data: bytes::Bytes) => ExtendedCopyBothClientDone <= crate::codec::BackendMessage::CopyData(_),
605            SendDone(send_done) => ExtendedCopyBothDone <= crate::codec::BackendMessage::CopyDone,
606            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
607        }
608        ExtendedCopyBothServerDone external {
609            associate {
610                inbound: crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothServerDone>;
611                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothServerDone>;
612            }
613            ReceiveData(receive_data: bytes::Bytes) => ExtendedCopyBothServerDone <= crate::codec::FrontendMessage::CopyData(_),
614            ReceiveDone(receive_done) => ExtendedCopyBothDone <= crate::codec::FrontendMessage::CopyDone,
615            Fail(fail: bytes::Bytes) => ExtendedCopyBothFailed <= crate::codec::FrontendMessage::CopyFail(_),
616        }
617        ExtendedCopyBothDone internal {
618            associate {
619                inbound: none;
620                outbound: crate::server_session::ServerCopyBoth<crate::server_session::CopyExtended, crate::server_session::BothDone>;
621            }
622            CommandComplete(command_complete: bytes::Bytes) => Building <= crate::codec::BackendMessage::CommandComplete(_),
623        }
624        ExtendedCopyBothFailed internal {
625            associate { inbound: none; outbound: crate::server_session::ServerCopyBothFailed<crate::server_session::CopyExtended>; }
626            Error(error: crate::codec::DiagnosticResponse) => ExtendedError <= crate::codec::BackendMessage::ErrorResponse(_),
627        }
628        Terminated external {
629            associate { inbound: none; outbound: none; }
630        }
631    }
632}
633
634protocol! {
635    pub mod server_authentication {
636        initial Startup;
637        messages {
638            internal: crate::codec::BackendMessage,
639            external: crate::codec::FrontendMessage,
640        }
641        associations {
642            interface: crate::middleware::PhaseAssociation;
643            seal: crate::middleware::phase_association_seal::Sealed;
644            inbound {
645                direction: crate::middleware::Inbound;
646                role: crate::middleware::ClientRole;
647                wire: crate::codec::FrontendMessage;
648                message: external;
649            }
650            outbound {
651                direction: crate::middleware::Outbound;
652                role: crate::middleware::ServerRole;
653                wire: crate::codec::BackendMessage;
654                message: crate::middleware::TypedBackendMessage<internal>;
655            }
656        }
657        Startup internal {
658            associate { inbound: none; outbound: crate::server_auth::ServerStartupRejected; }
659            Begin(begin) => Auth,
660            Reject(reject: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
661        }
662        Auth internal {
663            associate { inbound: crate::server_auth::ServerAuth; outbound: crate::server_auth::ServerAuth; }
664            Negotiate(negotiate: crate::codec::NegotiateProtocolVersion) => Auth <= crate::codec::BackendMessage::NegotiateProtocolVersion(_),
665            Cleartext(cleartext) => PasswordResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::CleartextPassword),
666            Md5(md5: [u8; 4]) => PasswordResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Md5Password { .. }),
667            Sasl(sasl: Vec<bytes::Bytes>) => SaslInitial <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Sasl { .. }),
668            Gss(gss) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Gss),
669            Sspi(sspi) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Sspi),
670            KerberosV5(kerberos_v5) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::KerberosV5),
671            Ok(ok) => StartupReady <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::Ok),
672            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
673        }
674        PasswordResponse external {
675            associate { inbound: crate::server_auth::ServerPassword; outbound: crate::server_auth::ServerPassword; }
676            Response(response: bytes::Bytes) => Auth <= crate::codec::FrontendMessage::PasswordResponse(_),
677        }
678        SaslInitial external {
679            associate { inbound: crate::server_auth::ServerSaslInitial; outbound: crate::server_auth::ServerSaslInitial; }
680            Initial(initial: crate::server_auth::SaslInitialResponse) => Sasl <= crate::codec::FrontendMessage::PasswordResponse(_),
681        }
682        Sasl internal {
683            associate { inbound: none; outbound: crate::server_auth::ServerSasl; }
684            Continue(continue_response: bytes::Bytes) => SaslResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::SaslContinue(_)),
685            Final(final_response: bytes::Bytes) => Auth <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::SaslFinal(_)),
686            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
687        }
688        SaslResponse external {
689            associate { inbound: crate::server_auth::ServerSaslResponse; outbound: crate::server_auth::ServerSaslResponse; }
690            Response(response: bytes::Bytes) => Sasl <= crate::codec::FrontendMessage::PasswordResponse(_),
691        }
692        TokenResponse external {
693            associate { inbound: crate::server_auth::ServerAuthResponse; outbound: crate::server_auth::ServerAuthResponse; }
694            Response(response: bytes::Bytes) => TokenPolicy <= crate::codec::FrontendMessage::PasswordResponse(_),
695        }
696        TokenPolicy internal {
697            associate { inbound: none; outbound: crate::server_auth::ServerAuthPolicy; }
698            Continue(continue_token: bytes::Bytes) => TokenResponse <= crate::codec::BackendMessage::Authentication(crate::codec::Authentication::GssContinue(_)),
699            Verified(verified) => Auth,
700            Error(error: crate::codec::DiagnosticResponse) => Terminated <= crate::codec::BackendMessage::ErrorResponse(_),
701        }
702        StartupReady internal {
703            associate { inbound: crate::server_auth::ServerStartupReady; outbound: crate::server_auth::ServerStartupReady; }
704            ParameterStatus(parameter_status: (bytes::Bytes, bytes::Bytes)) => StartupReady <= crate::codec::BackendMessage::ParameterStatus { .. },
705            BackendKeyData(backend_key_data: (u32, bytes::Bytes)) => StartupReady <= crate::codec::BackendMessage::BackendKeyData { .. },
706            Ready(ready: crate::codec::TransactionStatus) => Ready <= crate::codec::BackendMessage::ReadyForQuery(_),
707        }
708        Ready external {
709            associate { inbound: none; outbound: none; }
710        }
711        Terminated external {
712            associate { inbound: none; outbound: none; }
713        }
714    }
715}
716
717#[cfg(test)]
718mod tests {
719    use std::collections::BTreeMap;
720
721    use bytes::Bytes;
722
723    use super::{
724        authentication, backend, frontend, pre_startup, server_authentication, server_pre_startup,
725    };
726    use crate::{
727        Conn,
728        auth::AuthOffer,
729        codec::{
730            Authentication, BackendMessage, Bind, Execute, FrontendMessage, Parse,
731            TransactionStatus,
732        },
733        demux::SessionItem,
734        session::{AwaitingReadyTransition, ReadyState},
735        startup::{ProtocolVersion, StartupMessage},
736    };
737    use frontend::{Event, RuntimeFsm, RuntimeState, Session};
738
739    #[test]
740    fn railroad_labels_use_variant_syntax_and_link_payload_types() {
741        let svg = frontend::FRONTEND_RAILROAD_SVG;
742        assert!(svg.contains("◁ ReceiveCopyData(</tspan>"));
743        assert!(svg.contains("bytes::Bytes</tspan>"));
744        assert!(svg.contains(")</tspan>"));
745        assert!(svg.contains("xlink:href=\"https://docs.rs/bytes/1/bytes/struct.Bytes.html\""));
746        assert!(svg.contains("class=\"link\""));
747        assert!(svg.contains("▷ Query(</tspan>"));
748        assert!(svg.contains(") [Dirty]</tspan>"));
749        assert!(!svg.contains("class=\"link\"> <g class=\"terminal\""));
750        assert!(!svg.contains("&amp; ReceiveCopyData"));
751    }
752
753    macro_rules! exhaust_generated_runtime {
754        ($module:ident, $depth:expr) => {{
755            fn visit(runtime: $module::RuntimeFsm, depth: usize) {
756                for &event in $module::ALL_EVENTS {
757                    let state = runtime.state();
758                    let mut next = runtime;
759                    match next.step(event) {
760                        Ok(()) if depth > 0 => visit(next, depth - 1),
761                        Ok(()) => {}
762                        Err(error) => {
763                            assert_eq!(error.state, state);
764                            assert_eq!(error.event, event);
765                            assert_eq!(next.state(), state);
766                        }
767                    }
768                }
769            }
770            visit($module::RuntimeFsm::new(), $depth);
771        }};
772    }
773
774    #[test]
775    fn every_generated_protocol_exhausts_reachable_valid_and_invalid_events() {
776        exhaust_generated_runtime!(frontend, 5);
777        exhaust_generated_runtime!(backend, 5);
778        exhaust_generated_runtime!(pre_startup, 5);
779        exhaust_generated_runtime!(server_pre_startup, 5);
780        exhaust_generated_runtime!(authentication, 6);
781        exhaust_generated_runtime!(server_authentication, 6);
782    }
783
784    #[test]
785    fn generated_backend_projection_is_state_aware() {
786        let parse = FrontendMessage::Parse(Parse {
787            statement: Bytes::from_static(b"statement"),
788            query: Bytes::from_static(b"select 1"),
789            parameter_types: Vec::new(),
790        });
791        assert_eq!(
792            backend::project_external(backend::RuntimeState::Ready, &parse),
793            Some(backend::Event::Parse)
794        );
795        assert_eq!(
796            backend::project_external(backend::RuntimeState::SimpleCopyIn, &parse),
797            None
798        );
799        assert_eq!(
800            backend::project_external(backend::RuntimeState::ExtendedError, &FrontendMessage::Sync,),
801            Some(backend::Event::Sync)
802        );
803        assert_eq!(
804            backend::project_external(
805                backend::RuntimeState::ExtendedError,
806                &FrontendMessage::Flush,
807            ),
808            Some(backend::Event::Discard)
809        );
810        assert_eq!(
811            backend::project_internal(
812                backend::RuntimeState::Simple,
813                &BackendMessage::ReadyForQuery(TransactionStatus::Idle),
814            ),
815            Some(backend::Event::Ready)
816        );
817        assert_eq!(
818            backend::project_internal(
819                backend::RuntimeState::ExtendedCopyOut,
820                &BackendMessage::CopyDone,
821            ),
822            Some(backend::Event::Done)
823        );
824    }
825
826    #[test]
827    fn generated_frontend_projection_covers_wire_messages_only() {
828        assert_eq!(
829            frontend::project_internal(frontend::RuntimeState::Building, &FrontendMessage::Sync,),
830            Some(frontend::Event::Sync)
831        );
832        assert_eq!(
833            frontend::project_external(
834                frontend::RuntimeState::Simple,
835                &BackendMessage::ReadyForQuery(TransactionStatus::Idle),
836            ),
837            Some(frontend::Event::Ready)
838        );
839        assert_eq!(
840            frontend::project_external(
841                frontend::RuntimeState::ResetComplete,
842                &BackendMessage::ReadyForQuery(TransactionStatus::FailedTransaction),
843            ),
844            Some(frontend::Event::ReadyDirty)
845        );
846        assert_eq!(
847            frontend::project_external(
848                frontend::RuntimeState::CopyIn,
849                &BackendMessage::CopyData(Bytes::from_static(b"illegal direction")),
850            ),
851            None
852        );
853    }
854
855    #[test]
856    fn codec_messages_drive_generated_extended_and_copy_sequences() {
857        let parse = FrontendMessage::Parse(Parse {
858            statement: Bytes::new(),
859            query: Bytes::from_static(b"select $1"),
860            parameter_types: vec![23],
861        });
862        let mut extended = backend::RuntimeFsm::new();
863        extended
864            .step_projected(&parse, backend::project_external)
865            .unwrap();
866        extended
867            .step_projected(&BackendMessage::ParseComplete, backend::project_internal)
868            .unwrap();
869        extended
870            .step_projected(&FrontendMessage::Sync, backend::project_external)
871            .unwrap();
872        extended
873            .step_projected(
874                &BackendMessage::ReadyForQuery(TransactionStatus::Idle),
875                backend::project_internal,
876            )
877            .unwrap();
878        assert_eq!(extended.state(), backend::RuntimeState::Ready);
879
880        let mut copy = backend::RuntimeFsm::new();
881        copy.step_projected(
882            &FrontendMessage::Query(Bytes::from_static(b"copy t from stdin")),
883            backend::project_external,
884        )
885        .unwrap();
886        copy.step_projected(
887            &BackendMessage::CopyInResponse(crate::codec::CopyResponse {
888                overall_format: 0,
889                column_formats: vec![0],
890            }),
891            backend::project_internal,
892        )
893        .unwrap();
894        assert_eq!(copy.state(), backend::RuntimeState::SimpleCopyIn);
895        assert!(
896            copy.step_projected(
897                &FrontendMessage::Query(Bytes::from_static(b"select 1")),
898                backend::project_external,
899            )
900            .is_err()
901        );
902        assert_eq!(copy.state(), backend::RuntimeState::SimpleCopyIn);
903    }
904
905    #[test]
906    fn generated_typestate_and_runtime_accept_the_extended_loop() {
907        let _typed = Session::new()
908            .begin_extended()
909            .parse()
910            .bind()
911            .execute()
912            .sync()
913            .ready();
914
915        let mut runtime = RuntimeFsm::new();
916        for event in [
917            Event::BeginExtended,
918            Event::Parse,
919            Event::Bind,
920            Event::Execute,
921            Event::Sync,
922            Event::Ready,
923        ] {
924            runtime.step(event).unwrap();
925        }
926        assert_eq!(runtime.state(), RuntimeState::Ready);
927    }
928
929    #[test]
930    fn generated_backend_discards_failed_pipeline_until_sync() {
931        let _typed = backend::Session::new()
932            .parse()
933            .error()
934            .discard()
935            .discard()
936            .sync()
937            .ready()
938            .terminate();
939
940        let mut runtime = backend::RuntimeFsm::new();
941        for event in [
942            backend::Event::Parse,
943            backend::Event::Error,
944            backend::Event::Discard,
945            backend::Event::Discard,
946            backend::Event::Sync,
947            backend::Event::Ready,
948            backend::Event::Terminate,
949        ] {
950            runtime.step(event).unwrap();
951        }
952        assert_eq!(runtime.state(), backend::RuntimeState::Terminated);
953    }
954
955    #[test]
956    fn generated_backend_copy_resumes_its_enclosing_session() {
957        let _simple = backend::Session::new()
958            .query()
959            .copy_in()
960            .data()
961            .done()
962            .command_complete()
963            .ready();
964        let _extended = backend::Session::new()
965            .execute()
966            .copy_out()
967            .data()
968            .done()
969            .command_complete()
970            .sync()
971            .ready();
972
973        let mut runtime = backend::RuntimeFsm::new();
974        for event in [
975            backend::Event::Execute,
976            backend::Event::CopyOut,
977            backend::Event::Data,
978            backend::Event::Done,
979            backend::Event::CommandComplete,
980        ] {
981            runtime.step(event).unwrap();
982        }
983        assert_eq!(runtime.state(), backend::RuntimeState::Building);
984        runtime.step(backend::Event::Sync).unwrap();
985        runtime.step(backend::Event::Ready).unwrap();
986        assert_eq!(runtime.state(), backend::RuntimeState::Ready);
987    }
988
989    #[test]
990    fn generated_backend_copy_both_tracks_independent_half_closes() {
991        let _server_first = backend::Session::new()
992            .query()
993            .copy_both()
994            .send_data()
995            .receive_data()
996            .send_done()
997            .receive_data()
998            .receive_done()
999            .command_complete()
1000            .ready();
1001        let _client_first = backend::Session::new()
1002            .execute()
1003            .copy_both()
1004            .receive_done()
1005            .send_data()
1006            .send_done()
1007            .command_complete()
1008            .sync()
1009            .ready();
1010
1011        let mut runtime = backend::RuntimeFsm::new();
1012        runtime.step(backend::Event::Query).unwrap();
1013        runtime.step(backend::Event::CopyBoth).unwrap();
1014        assert_eq!(runtime.choice(), backend::ChoiceKind::Mixed);
1015        assert_eq!(
1016            runtime.event_choice(backend::Event::SendData),
1017            Some(backend::ChoiceKind::Internal)
1018        );
1019        assert_eq!(
1020            runtime.event_choice(backend::Event::ReceiveData),
1021            Some(backend::ChoiceKind::External)
1022        );
1023        runtime.step(backend::Event::SendDone).unwrap();
1024        assert!(runtime.step(backend::Event::SendData).is_err());
1025        runtime.step(backend::Event::ReceiveDone).unwrap();
1026        runtime.step(backend::Event::CommandComplete).unwrap();
1027        runtime.step(backend::Event::Ready).unwrap();
1028        assert_eq!(runtime.state(), backend::RuntimeState::Ready);
1029    }
1030
1031    #[test]
1032    fn generated_runtime_rejects_query_during_copy() {
1033        let mut runtime = RuntimeFsm::new();
1034        runtime.step(Event::Query).unwrap();
1035        runtime.step(Event::CopyIn).unwrap();
1036        assert!(runtime.step(Event::Query).is_err());
1037        assert_eq!(
1038            runtime.event_choice(Event::Error),
1039            Some(frontend::ChoiceKind::External)
1040        );
1041        runtime.step(Event::Error).unwrap();
1042        assert_eq!(runtime.state(), RuntimeState::Draining);
1043    }
1044
1045    #[test]
1046    fn generated_copy_both_waits_for_both_half_closes() {
1047        let mut directions = RuntimeFsm::new();
1048        directions.step(Event::Query).unwrap();
1049        directions.step(Event::CopyBoth).unwrap();
1050        assert_eq!(directions.choice(), frontend::ChoiceKind::Mixed);
1051        assert_eq!(
1052            directions.event_choice(Event::SendCopyData),
1053            Some(frontend::ChoiceKind::Internal)
1054        );
1055        assert_eq!(
1056            directions.event_choice(Event::ReceiveCopyData),
1057            Some(frontend::ChoiceKind::External)
1058        );
1059
1060        let mut client_first = RuntimeFsm::new();
1061        for event in [
1062            Event::Query,
1063            Event::CopyBoth,
1064            Event::SendCopyDone,
1065            Event::ReceiveCopyData,
1066            Event::ReceiveCopyDone,
1067        ] {
1068            client_first.step(event).unwrap();
1069        }
1070        assert_eq!(client_first.state(), RuntimeState::AwaitingReady);
1071
1072        let mut server_first = RuntimeFsm::new();
1073        for event in [
1074            Event::Query,
1075            Event::CopyBoth,
1076            Event::ReceiveCopyDone,
1077            Event::SendCopyData,
1078            Event::SendCopyDone,
1079        ] {
1080            server_first.step(event).unwrap();
1081        }
1082        assert_eq!(server_first.state(), RuntimeState::AwaitingReady);
1083    }
1084
1085    #[test]
1086    fn generated_function_call_and_termination_match_typed_paths() {
1087        let _function = Session::new()
1088            .function_call()
1089            .function_response()
1090            .ready()
1091            .terminate();
1092
1093        let mut runtime = RuntimeFsm::new();
1094        for event in [
1095            Event::FunctionCall,
1096            Event::FunctionResponse,
1097            Event::Ready,
1098            Event::Terminate,
1099        ] {
1100            runtime.step(event).unwrap();
1101        }
1102        assert_eq!(runtime.state(), RuntimeState::Terminated);
1103    }
1104
1105    #[test]
1106    fn generated_pool_reset_requires_discard_and_ready_evidence() {
1107        let _typed = Session::new()
1108            .reset()
1109            .continue_reset()
1110            .discard_complete()
1111            .continue_reset()
1112            .ready_clean();
1113
1114        let mut runtime = RuntimeFsm::new();
1115        runtime.step(Event::Reset).unwrap();
1116        assert!(runtime.step(Event::ReadyClean).is_err());
1117        runtime.step(Event::DiscardComplete).unwrap();
1118        runtime.step(Event::ReadyClean).unwrap();
1119        assert_eq!(runtime.state(), RuntimeState::Ready);
1120
1121        let dirty: Conn<(), crate::auth::Ready, crate::Dirty> =
1122            Conn::new(()).transition().mark_dirty();
1123        let (resetting, _) = dirty.begin_reset().unwrap();
1124        let crate::session::ResettingTransition::Complete(complete) =
1125            resetting.offer(SessionItem::CommandComplete {
1126                tag: Bytes::from_static(b"DISCARD ALL"),
1127                command: crate::demux::CommandIndex(1),
1128                notices: Vec::new(),
1129            })
1130        else {
1131            panic!("DISCARD ALL did not advance reset recovery")
1132        };
1133        let crate::session::ResetCompleteTransition::Ready(ready) =
1134            complete.offer(SessionItem::ReadyForQuery {
1135                status: TransactionStatus::Idle,
1136                parameters_changed: false,
1137            })
1138        else {
1139            panic!("idle readiness did not restore pristine evidence")
1140        };
1141        ready.release();
1142    }
1143
1144    #[test]
1145    fn generated_transport_session_tracks_cleanliness_effects() {
1146        #[derive(Debug)]
1147        struct InitiallyClean;
1148
1149        let ready: frontend::TypedSession<(), frontend::Ready, InitiallyClean> =
1150            frontend::TypedSession::with_transport(());
1151        let (dirty, query): (
1152            frontend::TypedSession<(), frontend::Simple, frontend::Dirty>,
1153            Bytes,
1154        ) = ready
1155            .query(Bytes::from_static(b"select 1"), |(), query| {
1156                Ok::<_, std::convert::Infallible>(query)
1157            })
1158            .expect("query handler is infallible");
1159        assert_eq!(query, Bytes::from_static(b"select 1"));
1160        let (dirty, _status): (
1161            frontend::TypedSession<(), frontend::Ready, frontend::Dirty>,
1162            TransactionStatus,
1163        ) = dirty
1164            .ready(TransactionStatus::Idle, |(), status| {
1165                Ok::<_, std::convert::Infallible>(status)
1166            })
1167            .expect("readiness handler is infallible");
1168        assert_eq!(dirty.into_transport(), ());
1169
1170        let dirty: frontend::TypedSession<(), frontend::Ready, frontend::Dirty> =
1171            frontend::TypedSession::with_transport(());
1172        let (reset_complete, _tag) = dirty
1173            .reset()
1174            .discard_complete(Bytes::from_static(b"DISCARD ALL"), |(), tag| {
1175                Ok::<_, std::convert::Infallible>(tag)
1176            })
1177            .expect("command handler is infallible");
1178        let (clean, _status): (
1179            frontend::TypedSession<(), frontend::Ready, frontend::Pristine>,
1180            TransactionStatus,
1181        ) = reset_complete
1182            .ready_clean(TransactionStatus::Idle, |(), status| {
1183                Ok::<_, std::convert::Infallible>(status)
1184            })
1185            .expect("readiness handler is infallible");
1186        assert_eq!(clean.into_transport(), ());
1187    }
1188
1189    #[test]
1190    fn generated_frontend_parse_payload_is_inspectable_and_fallible() {
1191        #[derive(Debug)]
1192        struct Clean;
1193
1194        let ready: frontend::TypedSession<Vec<crate::codec::Frame>, frontend::Ready, Clean> =
1195            frontend::TypedSession::with_transport(Vec::new());
1196        let parse = Parse {
1197            statement: Bytes::from_static(b"statement"),
1198            query: Bytes::from_static(b"select encrypted_column"),
1199            parameter_types: vec![23],
1200        };
1201        let (building, query): (
1202            frontend::TypedSession<Vec<crate::codec::Frame>, frontend::Building, frontend::Dirty>,
1203            Bytes,
1204        ) = ready
1205            .begin_extended()
1206            .parse(parse, |frames, message| {
1207                let query = message.query.clone();
1208                frames.push(message.to_frame()?);
1209                Ok::<_, std::io::Error>(query)
1210            })
1211            .unwrap();
1212        assert_eq!(query, Bytes::from_static(b"select encrypted_column"));
1213        assert_eq!(building.into_transport()[0].tag, b'P');
1214
1215        let ready: frontend::TypedSession<Vec<crate::codec::Frame>, frontend::Ready, Clean> =
1216            frontend::TypedSession::with_transport(Vec::new());
1217        let invalid = Parse {
1218            statement: Bytes::from_static(b"bad\0statement"),
1219            query: Bytes::from_static(b"select 1"),
1220            parameter_types: vec![],
1221        };
1222        let (building, error) = ready
1223            .begin_extended()
1224            .parse(invalid, |frames, message| {
1225                frames.push(message.to_frame()?);
1226                Ok::<_, std::io::Error>(())
1227            })
1228            .unwrap_err();
1229        assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
1230        assert!(building.into_transport().is_empty());
1231    }
1232
1233    #[test]
1234    fn generated_pre_startup_requires_handshake_before_startup() {
1235        struct Clean;
1236        struct Tcp;
1237        struct Tls(Tcp);
1238
1239        let _typed = pre_startup::Session::new()
1240            .ssl_request()
1241            .accept()
1242            .complete()
1243            .startup();
1244
1245        let mut runtime = pre_startup::RuntimeFsm::new();
1246        runtime.step(pre_startup::Event::SslRequest).unwrap();
1247        assert!(runtime.step(pre_startup::Event::Startup).is_err());
1248        runtime.step(pre_startup::Event::Accept).unwrap();
1249        runtime.step(pre_startup::Event::HandshakeComplete).unwrap();
1250        runtime.step(pre_startup::Event::Startup).unwrap();
1251
1252        let pre_startup: pre_startup::TypedSession<Tcp, pre_startup::PreStartup, Clean> =
1253            pre_startup::TypedSession::with_transport(Tcp);
1254        let startup = crate::startup::StartupMessage {
1255            version: crate::startup::ProtocolVersion::V3_0,
1256            parameters: BTreeMap::new(),
1257        };
1258        let auth = pre_startup
1259            .ssl_request()
1260            .accept()
1261            .map_transport(Tls)
1262            .complete()
1263            .startup(startup, |_, startup| {
1264                Ok::<_, std::convert::Infallible>(startup)
1265            });
1266        let (auth, _startup): (
1267            pre_startup::TypedSession<Tls, pre_startup::Auth, Clean>,
1268            crate::startup::StartupMessage,
1269        ) = match auth {
1270            Ok(success) => success,
1271            Err((_session, never)) => match never {},
1272        };
1273        let Tls(_tcp) = auth.into_transport();
1274
1275        assert_eq!(
1276            pre_startup::project_internal(
1277                pre_startup::RuntimeState::PreStartup,
1278                &crate::pre_startup::PreStartupMessage::SslRequest,
1279            ),
1280            Some(pre_startup::Event::SslRequest)
1281        );
1282        assert_eq!(
1283            pre_startup::project_external(
1284                pre_startup::RuntimeState::AwaitingSslReply,
1285                &crate::pre_startup::EncryptionReply::Accepted,
1286            ),
1287            Some(pre_startup::Event::Accept)
1288        );
1289    }
1290
1291    #[test]
1292    fn generated_server_pre_startup_is_the_client_facing_dual() {
1293        let _plaintext = server_pre_startup::Session::new()
1294            .ssl_request()
1295            .reject()
1296            .startup();
1297        let _encrypted = server_pre_startup::Session::new()
1298            .ssl_request()
1299            .accept()
1300            .complete()
1301            .startup();
1302
1303        let mut runtime = server_pre_startup::RuntimeFsm::new();
1304        assert_eq!(runtime.choice(), server_pre_startup::ChoiceKind::External);
1305        runtime.step(server_pre_startup::Event::SslRequest).unwrap();
1306        assert_eq!(runtime.choice(), server_pre_startup::ChoiceKind::Internal);
1307        assert!(runtime.step(server_pre_startup::Event::Startup).is_err());
1308        runtime.step(server_pre_startup::Event::Reject).unwrap();
1309        runtime.step(server_pre_startup::Event::Startup).unwrap();
1310        assert_eq!(runtime.state(), server_pre_startup::RuntimeState::Auth);
1311
1312        assert_eq!(
1313            pre_startup::RuntimeFsm::new().dual_event_choice(pre_startup::Event::SslRequest),
1314            Some(pre_startup::ChoiceKind::External)
1315        );
1316    }
1317
1318    #[test]
1319    fn generated_sasl_continuation_is_recursive() {
1320        let _typed = authentication::Session::new()
1321            .sasl()
1322            .initial()
1323            .continue_response()
1324            .response()
1325            .continue_response()
1326            .response()
1327            .final_response()
1328            .verified()
1329            .ok()
1330            .ready();
1331
1332        let mut runtime = authentication::RuntimeFsm::new();
1333        for event in [
1334            authentication::Event::Sasl,
1335            authentication::Event::Initial,
1336            authentication::Event::Continue,
1337            authentication::Event::Response,
1338            authentication::Event::Continue,
1339            authentication::Event::Response,
1340            authentication::Event::Final,
1341            authentication::Event::Verified,
1342            authentication::Event::Ok,
1343            authentication::Event::Ready,
1344        ] {
1345            runtime.step(event).unwrap();
1346        }
1347        assert_eq!(runtime.state(), authentication::RuntimeState::Ready);
1348        assert_eq!(
1349            authentication::project_external(
1350                authentication::RuntimeState::Sasl,
1351                &BackendMessage::Authentication(Authentication::SaslContinue(Bytes::from_static(
1352                    b"challenge"
1353                ),)),
1354            ),
1355            Some(authentication::Event::Continue)
1356        );
1357        assert_eq!(
1358            authentication::project_internal(
1359                authentication::RuntimeState::SaslChallenge,
1360                &FrontendMessage::PasswordResponse(Bytes::from_static(b"response")),
1361            ),
1362            Some(authentication::Event::Response)
1363        );
1364    }
1365
1366    #[test]
1367    fn generated_token_authentication_is_recursive() {
1368        let _typed = authentication::Session::new()
1369            .gss()
1370            .response()
1371            .continue_token()
1372            .response()
1373            .ok()
1374            .ready();
1375
1376        let mut runtime = authentication::RuntimeFsm::new();
1377        for event in [
1378            authentication::Event::Gss,
1379            authentication::Event::Response,
1380            authentication::Event::Continue,
1381            authentication::Event::Response,
1382            authentication::Event::Ok,
1383            authentication::Event::Ready,
1384        ] {
1385            runtime.step(event).unwrap();
1386        }
1387        assert_eq!(runtime.state(), authentication::RuntimeState::Ready);
1388    }
1389
1390    #[test]
1391    fn generated_server_authentication_keeps_mechanisms_independent() {
1392        let _typed = server_authentication::Session::new()
1393            .begin()
1394            .negotiate()
1395            .sasl()
1396            .initial()
1397            .continue_response()
1398            .response()
1399            .final_response()
1400            .ok()
1401            .parameter_status()
1402            .backend_key_data()
1403            .ready();
1404
1405        let mut runtime = server_authentication::RuntimeFsm::new();
1406        for event in [
1407            server_authentication::Event::Begin,
1408            server_authentication::Event::Negotiate,
1409            server_authentication::Event::Gss,
1410            server_authentication::Event::Response,
1411            server_authentication::Event::Continue,
1412            server_authentication::Event::Response,
1413            server_authentication::Event::Verified,
1414            server_authentication::Event::Ok,
1415            server_authentication::Event::Ready,
1416        ] {
1417            runtime.step(event).unwrap();
1418        }
1419        assert_eq!(runtime.state(), server_authentication::RuntimeState::Ready);
1420    }
1421
1422    #[test]
1423    fn runtime_fsm_tracks_the_handwritten_extended_typestate() {
1424        let message = StartupMessage {
1425            version: ProtocolVersion::V3_2,
1426            parameters: BTreeMap::new(),
1427        };
1428        let (startup, _) = Conn::new(()).startup(&message).unwrap();
1429        let AuthOffer::Ok(awaiting_ready) =
1430            startup.authentication().offer(Authentication::Ok).unwrap()
1431        else {
1432            panic!("authentication projected to the wrong branch")
1433        };
1434        let ready = awaiting_ready
1435            .offer_ready(SessionItem::ReadyForQuery {
1436                status: TransactionStatus::Idle,
1437                parameters_changed: false,
1438            })
1439            .unwrap();
1440        let mut runtime = RuntimeFsm::new();
1441
1442        let building = ready.begin_extended();
1443        runtime.step(Event::BeginExtended).unwrap();
1444        let (building, _) = building
1445            .push_parse(&Parse {
1446                statement: Bytes::from_static(b"s"),
1447                query: Bytes::from_static(b"select $1"),
1448                parameter_types: vec![23],
1449            })
1450            .unwrap();
1451        runtime.step(Event::Parse).unwrap();
1452        let (bound, _) = building
1453            .push_bind(&Bind {
1454                portal: Bytes::new(),
1455                statement: Bytes::from_static(b"s"),
1456                parameter_formats: vec![],
1457                parameters: vec![Some(Bytes::from_static(b"42"))],
1458                result_formats: vec![],
1459            })
1460            .unwrap();
1461        runtime.step(Event::Bind).unwrap();
1462        let (bound, _) = bound
1463            .push_execute(&Execute {
1464                portal: Bytes::new(),
1465                max_rows: 0,
1466            })
1467            .unwrap();
1468        runtime.step(Event::Execute).unwrap();
1469        let (awaiting_ready, _) = bound.push_sync();
1470        runtime.step(Event::Sync).unwrap();
1471        let AwaitingReadyTransition::Ready(ReadyState::Clean(ready)) =
1472            awaiting_ready.offer(SessionItem::ReadyForQuery {
1473                status: TransactionStatus::Idle,
1474                parameters_changed: false,
1475            })
1476        else {
1477            panic!("ready evidence projected to the wrong branch")
1478        };
1479        runtime.step(Event::Ready).unwrap();
1480
1481        assert_eq!(runtime.state(), RuntimeState::Ready);
1482        ready.into_transport();
1483    }
1484}