Skip to main content

pg_proto/
lib.rs

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