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