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