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