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    CancellationPolicy, CancellationRoute, EstablishmentFailurePolicy, ForwardError,
79    ForwardedMessage, IdentityIntermediaryMiddleware, InitialServerContext, Intermediary,
80    IntermediaryAccept, IntermediaryAcceptError, IntermediaryBuildError, IntermediaryBuilder,
81    IntermediaryCancellationRegistry, IntermediaryConnection, IntermediaryContexts,
82    IntermediaryMiddleware, IntermediaryMiddlewareFactory, RejectCancellation,
83    StartupResolutionError, StartupRouteResolver,
84};
85pub use pipeline::{
86    BackendProjectionError, BoundedPipeline, FrontendProjectionError, NoPipeline,
87    PipelineConfigError, PipelinePolicy,
88};
89pub use pre_startup::{CertificateVerification, PreStartupMessage, SslMode, SslStrategy};
90pub use runtime_middleware::{
91    ClientMiddleware, IdentityMiddleware, MiddlewareChain, MiddlewareFactory, ServerMiddleware,
92};
93pub use server_component::{
94    AcceptError, AcceptedServerTransport, BuildServerError, CancellationRequest, DisabledServerTls,
95    IdentityServerHandler, NegotiatedServerTls, NoServerIdentity, NoServerIdentityProvider,
96    OptionalServerTls, RequiredServerTls, Server, ServerAccept, ServerAcceptFuture,
97    ServerAuthentication, ServerAuthenticationAction, ServerAuthenticationFuture,
98    ServerAuthenticationProvider, ServerAuthenticationRequest, ServerAuthenticationResponse,
99    ServerBuilder, ServerCancellation, ServerConnection, ServerConnectionContext, ServerIdentity,
100    ServerIdentityProvider, ServerProtocolLimits, ServerTlsConfiguration, ServerTlsPolicy,
101    TrustIdentity, TrustServerAuthentication,
102};
103pub use startup::{ProtocolVersion, StartupMessage};
104
105#[cfg(test)]
106extern crate self as pg_proto;
107
108#[cfg(test)]
109mod internal_tests;
110
111use std::marker::PhantomData;
112
113/// A connection whose legal operations are selected by `Phase` and `Cleanliness`.
114#[must_use = "dropping a connection abandons the PostgreSQL session"]
115#[derive(Debug)]
116pub(crate) struct Conn<Transport, Phase, Cleanliness = Pristine> {
117    transport: Option<Transport>,
118    _state: PhantomData<(Phase, Cleanliness)>,
119}
120
121impl<Transport, Phase, Cleanliness> Conn<Transport, Phase, Cleanliness> {
122    pub(crate) fn transition<NextPhase, NextCleanliness>(
123        mut self,
124    ) -> Conn<Transport, NextPhase, NextCleanliness> {
125        Conn {
126            transport: self.transport.take(),
127            _state: PhantomData,
128        }
129    }
130
131    /// Returns the underlying transport when deliberately leaving the typed API.
132    ///
133    /// # Panics
134    ///
135    /// Panics only if an internal transition has already moved the transport.
136    pub(crate) fn into_transport(mut self) -> Transport {
137        self.transport
138            .take()
139            .expect("live connection has a transport")
140    }
141
142    /// Changes transport representation without changing either state index.
143    ///
144    /// # Panics
145    ///
146    /// Panics only if an internal transition has already moved the transport.
147    pub(crate) fn map_transport<Next>(
148        mut self,
149        map: impl FnOnce(Transport) -> Next,
150    ) -> Conn<Next, Phase, Cleanliness> {
151        Conn {
152            transport: Some(map(self
153                .transport
154                .take()
155                .expect("live connection has a transport"))),
156            _state: PhantomData,
157        }
158    }
159
160    pub(crate) const fn transport(&self) -> &Transport {
161        match &self.transport {
162            Some(transport) => transport,
163            None => panic!("connection transport has already moved"),
164        }
165    }
166
167    pub(crate) const fn transport_mut(&mut self) -> &mut Transport {
168        match &mut self.transport {
169            Some(transport) => transport,
170            None => panic!("connection transport has already moved"),
171        }
172    }
173}
174
175impl<Transport> Conn<Transport, pre_startup::PreStartup, Pristine> {
176    /// Starts a new connection before any startup packet has been sent.
177    pub(crate) const fn new(transport: Transport) -> Self {
178        Self {
179            transport: Some(transport),
180            _state: PhantomData,
181        }
182    }
183}
184
185#[cfg(debug_assertions)]
186impl<Transport, Phase, Cleanliness> Drop for Conn<Transport, Phase, Cleanliness> {
187    fn drop(&mut self) {
188        assert!(
189            self.transport.is_none() || std::thread::panicking(),
190            "live PostgreSQL connection dropped before a terminal transition; call into_transport() to abort deliberately"
191        );
192    }
193}
194
195/// The connection has no known session-local changes.
196#[derive(Debug)]
197pub(crate) enum Pristine {}
198
199/// The connection has state which prevents unconditional pool release.
200#[derive(Debug)]
201pub(crate) enum Dirty {}