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