Skip to main content

pg_proto/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(
3    clippy::doc_markdown,
4    clippy::enum_variant_names,
5    clippy::redundant_pub_crate
6)]
7#![deny(private_bounds, private_interfaces, unreachable_pub)]
8
9#[allow(dead_code)]
10mod auth;
11mod backend_hold;
12#[allow(dead_code)]
13mod cancel;
14#[allow(dead_code)]
15mod cleanliness;
16mod client_component;
17#[allow(dead_code)]
18mod codec;
19#[allow(dead_code)]
20mod credentials;
21#[allow(dead_code)]
22mod demux;
23#[allow(dead_code)]
24mod erased;
25#[allow(dead_code)]
26mod grammar;
27#[allow(dead_code)]
28mod integrations;
29#[allow(dead_code)]
30mod intermediary;
31mod intermediary_component;
32#[allow(dead_code)]
33mod middleware;
34#[allow(dead_code)]
35mod net;
36#[allow(dead_code)]
37mod pipeline;
38#[allow(dead_code)]
39mod pre_startup;
40#[allow(dead_code)]
41mod replication;
42#[allow(dead_code)]
43mod resources;
44mod runtime_middleware;
45#[allow(dead_code)]
46mod scram;
47#[allow(dead_code)]
48mod server_auth;
49mod server_component;
50#[allow(dead_code)]
51mod server_session;
52#[allow(dead_code)]
53mod session;
54#[allow(dead_code)]
55mod startup;
56#[allow(dead_code)]
57mod tls;
58#[allow(dead_code)]
59mod transport;
60
61pub use client_component::{
62    BuildError, CancelError, Client, ClientAuthentication, ClientAuthenticationChallenge,
63    ClientAuthenticationError, ClientAuthenticationFuture, ClientAuthenticationResponse,
64    ClientAuthenticationSession, ClientBuilder, ClientConnection, ClientConnectionContext,
65    ClientInitialContext, ClientTlsConfig, ClientTlsConfiguration, ClientTlsError, ClientTlsPolicy,
66    ClientTlsProvider, ClientTlsStatus, ClientTransport, ConnectError, ConnectTarget,
67    ConnectionChanged, ConnectionClean, IdentityHandler, ProtocolLimitError, ProtocolLimits,
68    QueryError, ReloadableClientTls, StartupParameterError, StartupParameters,
69    TrustClientAuthentication,
70};
71pub use codec::{
72    Authentication, BackendMessage, Bind, Close, CopyResponse, DataRow, Describe, DescribeTarget,
73    DiagnosticField, DiagnosticResponse, Execute, FieldDescription, FrontendMessage, FunctionCall,
74    NegotiateProtocolVersion, Parse, RowDescription, TransactionStatus,
75};
76pub use demux::CancelKey;
77pub use intermediary_component::{
78    AllowAuthenticatedRoute, AuthenticatedRouteContext, AuthenticatedRoutePolicy,
79    BackendBatchForwarding, BackendBatchOutput, BackendBatchProjectionError, BackendFlushReason,
80    BackendForwarding, BackendHoldConfigError, BackendHoldLimits, BackendMiddlewareOutput,
81    CancellationPolicy, CancellationRoute, EstablishmentFailurePolicy, ForwardError,
82    ForwardedMessage, FrontendForwarding, FrontendMiddlewareOutput, HeldBackendMessages,
83    IdentityIntermediaryMiddleware, InitialServerContext, Intermediary, IntermediaryAccept,
84    IntermediaryAcceptError, IntermediaryBuildError, IntermediaryBuilder,
85    IntermediaryCancellationRegistry, IntermediaryConnection, IntermediaryContexts,
86    IntermediaryMiddleware, IntermediaryMiddlewareFactory, RejectCancellation,
87    StartupResolutionError, StartupRouteResolver,
88};
89pub use pipeline::{
90    BackendProjectionError, BoundedPipeline, FrontendProjectionError, NoPipeline,
91    PipelineConfigError, PipelinePolicy,
92};
93pub use pre_startup::{CertificateVerification, PreStartupMessage, SslMode, SslStrategy};
94pub use runtime_middleware::{
95    ClientMiddleware, IdentityMiddleware, MiddlewareChain, MiddlewareFactory, ServerMiddleware,
96};
97pub use server_component::{
98    AcceptError, AcceptedServerTransport, BuildServerError, CancellationRequest, DisabledServerTls,
99    IdentityServerHandler, NegotiatedServerTls, NoServerIdentity, NoServerIdentityProvider,
100    OptionalServerTls, RequiredServerTls, Server, ServerAccept, ServerAcceptFuture,
101    ServerAuthentication, ServerAuthenticationAction, ServerAuthenticationFuture,
102    ServerAuthenticationProvider, ServerAuthenticationRequest, ServerAuthenticationResponse,
103    ServerBuilder, ServerCancellation, ServerConnection, ServerConnectionContext, ServerIdentity,
104    ServerIdentityProvider, ServerProtocolLimits, ServerTlsConfiguration, ServerTlsPolicy,
105    TrustIdentity, TrustServerAuthentication,
106};
107pub use startup::{ProtocolVersion, StartupMessage};
108
109#[cfg(test)]
110extern crate self as pg_proto;
111
112#[cfg(test)]
113mod internal_tests;
114
115use std::marker::PhantomData;
116
117/// A connection whose legal operations are selected by `Phase` and `Cleanliness`.
118#[must_use = "dropping a connection abandons the PostgreSQL session"]
119#[derive(Debug)]
120pub(crate) struct Conn<Transport, Phase, Cleanliness = Pristine> {
121    transport: Option<Transport>,
122    _state: PhantomData<(Phase, Cleanliness)>,
123}
124
125impl<Transport, Phase, Cleanliness> Conn<Transport, Phase, Cleanliness> {
126    pub(crate) fn transition<NextPhase, NextCleanliness>(
127        mut self,
128    ) -> Conn<Transport, NextPhase, NextCleanliness> {
129        Conn {
130            transport: self.transport.take(),
131            _state: PhantomData,
132        }
133    }
134
135    /// Returns the underlying transport when deliberately leaving the typed API.
136    ///
137    /// # Panics
138    ///
139    /// Panics only if an internal transition has already moved the transport.
140    pub(crate) fn into_transport(mut self) -> Transport {
141        self.transport
142            .take()
143            .expect("live connection has a transport")
144    }
145
146    /// Changes transport representation without changing either state index.
147    ///
148    /// # Panics
149    ///
150    /// Panics only if an internal transition has already moved the transport.
151    pub(crate) fn map_transport<Next>(
152        mut self,
153        map: impl FnOnce(Transport) -> Next,
154    ) -> Conn<Next, Phase, Cleanliness> {
155        Conn {
156            transport: Some(map(self
157                .transport
158                .take()
159                .expect("live connection has a transport"))),
160            _state: PhantomData,
161        }
162    }
163
164    pub(crate) const fn transport(&self) -> &Transport {
165        match &self.transport {
166            Some(transport) => transport,
167            None => panic!("connection transport has already moved"),
168        }
169    }
170
171    pub(crate) const fn transport_mut(&mut self) -> &mut Transport {
172        match &mut self.transport {
173            Some(transport) => transport,
174            None => panic!("connection transport has already moved"),
175        }
176    }
177}
178
179impl<Transport> Conn<Transport, pre_startup::PreStartup, Pristine> {
180    /// Starts a new connection before any startup packet has been sent.
181    pub(crate) const fn new(transport: Transport) -> Self {
182        Self {
183            transport: Some(transport),
184            _state: PhantomData,
185        }
186    }
187}
188
189#[cfg(debug_assertions)]
190impl<Transport, Phase, Cleanliness> Drop for Conn<Transport, Phase, Cleanliness> {
191    fn drop(&mut self) {
192        assert!(
193            self.transport.is_none() || std::thread::panicking(),
194            "live PostgreSQL connection dropped before a terminal transition; call into_transport() to abort deliberately"
195        );
196    }
197}
198
199/// The connection has no known session-local changes.
200#[derive(Debug)]
201pub(crate) enum Pristine {}
202
203/// The connection has state which prevents unconditional pool release.
204#[derive(Debug)]
205pub(crate) enum Dirty {}