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