Skip to main content

pg_proto/
lib.rs

1//! Session-typed `PostgreSQL` wire protocol primitives.
2
3pub mod auth;
4pub mod cancel;
5pub mod cleanliness;
6pub mod codec;
7pub mod credentials;
8pub mod demux;
9pub mod erased;
10pub mod grammar;
11pub mod integrations;
12pub mod intermediary;
13pub mod pre_startup;
14pub mod replication;
15pub mod resources;
16pub mod scram;
17pub mod server_auth;
18pub mod server_session;
19pub mod session;
20pub mod startup;
21pub mod tls;
22pub mod transport;
23
24use std::marker::PhantomData;
25
26/// A connection whose legal operations are selected by `Phase` and `Cleanliness`.
27#[must_use = "dropping a connection abandons the PostgreSQL session"]
28#[derive(Debug)]
29pub struct Conn<Transport, Phase, Cleanliness = Pristine> {
30    transport: Option<Transport>,
31    _state: PhantomData<(Phase, Cleanliness)>,
32}
33
34impl<Transport, Phase, Cleanliness> Conn<Transport, Phase, Cleanliness> {
35    pub(crate) fn transition<NextPhase, NextCleanliness>(
36        mut self,
37    ) -> Conn<Transport, NextPhase, NextCleanliness> {
38        Conn {
39            transport: self.transport.take(),
40            _state: PhantomData,
41        }
42    }
43
44    /// Returns the underlying transport when deliberately leaving the typed API.
45    ///
46    /// # Panics
47    ///
48    /// Panics only if an internal transition has already moved the transport.
49    pub fn into_transport(mut self) -> Transport {
50        self.transport
51            .take()
52            .expect("live connection has a transport")
53    }
54
55    /// Changes transport representation without changing either state index.
56    ///
57    /// # Panics
58    ///
59    /// Panics only if an internal transition has already moved the transport.
60    pub fn map_transport<Next>(
61        mut self,
62        map: impl FnOnce(Transport) -> Next,
63    ) -> Conn<Next, Phase, Cleanliness> {
64        Conn {
65            transport: Some(map(self
66                .transport
67                .take()
68                .expect("live connection has a transport"))),
69            _state: PhantomData,
70        }
71    }
72
73    pub(crate) const fn transport(&self) -> &Transport {
74        match &self.transport {
75            Some(transport) => transport,
76            None => panic!("connection transport has already moved"),
77        }
78    }
79
80    pub(crate) const fn transport_mut(&mut self) -> &mut Transport {
81        match &mut self.transport {
82            Some(transport) => transport,
83            None => panic!("connection transport has already moved"),
84        }
85    }
86}
87
88impl<Transport> Conn<Transport, pre_startup::PreStartup, Pristine> {
89    /// Starts a new connection before any startup packet has been sent.
90    pub const fn new(transport: Transport) -> Self {
91        Self {
92            transport: Some(transport),
93            _state: PhantomData,
94        }
95    }
96}
97
98#[cfg(debug_assertions)]
99impl<Transport, Phase, Cleanliness> Drop for Conn<Transport, Phase, Cleanliness> {
100    fn drop(&mut self) {
101        assert!(
102            self.transport.is_none() || std::thread::panicking(),
103            "live PostgreSQL connection dropped before a terminal transition; call into_transport() to abort deliberately"
104        );
105    }
106}
107
108/// The connection has no known session-local changes.
109#[derive(Debug)]
110pub enum Pristine {}
111
112/// The connection has state which prevents unconditional pool release.
113#[derive(Debug)]
114pub enum Dirty {}