Line data Source code
1 : use serde::{Deserialize, Deserializer, Serialize, Serializer};
2 : use serde_repr::{Deserialize_repr, Serialize_repr};
3 : use std::fmt::{Display, Formatter};
4 : use std::str::FromStr;
5 :
6 : /// An enum with one variant for each major version of PostgreSQL that we support.
7 : ///
8 : #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Deserialize_repr, Serialize_repr)]
9 : #[repr(u32)]
10 : pub enum PgMajorVersion {
11 : PG14 = 14,
12 : PG15 = 15,
13 : PG16 = 16,
14 : PG17 = 17,
15 : // !!! When you add a new PgMajorVersion, don't forget to update PgMajorVersion::ALL
16 : }
17 :
18 : /// A full PostgreSQL version ID, in MMmmbb numerical format (Major/minor/bugfix)
19 : #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
20 : #[repr(transparent)]
21 : pub struct PgVersionId(u32);
22 :
23 : impl PgVersionId {
24 : pub const UNKNOWN: PgVersionId = PgVersionId(0);
25 :
26 20319 : pub fn from_full_pg_version(version: u32) -> PgVersionId {
27 20319 : match version {
28 0 : 0 => PgVersionId(version), // unknown version
29 20319 : 140000..180000 => PgVersionId(version),
30 0 : _ => panic!("Invalid full PostgreSQL version ID {version}"),
31 : }
32 20319 : }
33 : }
34 :
35 : impl Display for PgVersionId {
36 0 : fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37 0 : u32::fmt(&self.0, f)
38 0 : }
39 : }
40 :
41 : impl Serialize for PgVersionId {
42 54 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
43 54 : where
44 54 : S: Serializer,
45 : {
46 54 : u32::serialize(&self.0, serializer)
47 0 : }
48 : }
49 :
50 : impl<'de> Deserialize<'de> for PgVersionId {
51 6 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
52 6 : where
53 6 : D: Deserializer<'de>,
54 : {
55 6 : u32::deserialize(deserializer).map(PgVersionId)
56 0 : }
57 :
58 0 : fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
59 0 : where
60 0 : D: Deserializer<'de>,
61 : {
62 0 : u32::deserialize_in_place(deserializer, &mut place.0)
63 0 : }
64 : }
65 :
66 : impl PgMajorVersion {
67 : /// Get the numerical representation of the represented Major Version
68 8 : pub const fn major_version_num(&self) -> u32 {
69 8 : match self {
70 3 : PgMajorVersion::PG14 => 14,
71 0 : PgMajorVersion::PG15 => 15,
72 3 : PgMajorVersion::PG16 => 16,
73 2 : PgMajorVersion::PG17 => 17,
74 : }
75 8 : }
76 :
77 : /// Get the contents of this version's PG_VERSION file.
78 : ///
79 : /// The PG_VERSION file is used to determine the PostgreSQL version that currently
80 : /// owns the data in a PostgreSQL data directory.
81 0 : pub fn versionfile_string(&self) -> &'static str {
82 0 : match self {
83 0 : PgMajorVersion::PG14 => "14",
84 0 : PgMajorVersion::PG15 => "15",
85 0 : PgMajorVersion::PG16 => "16\x0A",
86 0 : PgMajorVersion::PG17 => "17\x0A",
87 : }
88 0 : }
89 :
90 : /// Get the v{version} string of this major PostgreSQL version.
91 : ///
92 : /// Because this was hand-coded in various places, this was moved into a shared
93 : /// implementation.
94 120 : pub fn v_str(&self) -> String {
95 120 : match self {
96 33 : PgMajorVersion::PG14 => "v14",
97 27 : PgMajorVersion::PG15 => "v15",
98 33 : PgMajorVersion::PG16 => "v16",
99 27 : PgMajorVersion::PG17 => "v17",
100 : }
101 120 : .to_string()
102 120 : }
103 :
104 : /// All currently supported major versions of PostgreSQL.
105 : pub const ALL: &'static [PgMajorVersion] = &[
106 : PgMajorVersion::PG14,
107 : PgMajorVersion::PG15,
108 : PgMajorVersion::PG16,
109 : PgMajorVersion::PG17,
110 : ];
111 : }
112 :
113 : impl Display for PgMajorVersion {
114 39 : fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
115 39 : f.write_str(match self {
116 11 : PgMajorVersion::PG14 => "PgMajorVersion::PG14",
117 8 : PgMajorVersion::PG15 => "PgMajorVersion::PG15",
118 11 : PgMajorVersion::PG16 => "PgMajorVersion::PG16",
119 9 : PgMajorVersion::PG17 => "PgMajorVersion::PG17",
120 : })
121 39 : }
122 : }
123 :
124 : #[derive(Debug, thiserror::Error)]
125 : #[allow(dead_code)]
126 : pub struct InvalidPgVersion(u32);
127 :
128 : impl Display for InvalidPgVersion {
129 0 : fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
130 0 : write!(f, "InvalidPgVersion({})", self.0)
131 0 : }
132 : }
133 :
134 : impl TryFrom<PgVersionId> for PgMajorVersion {
135 : type Error = InvalidPgVersion;
136 :
137 40655 : fn try_from(value: PgVersionId) -> Result<Self, Self::Error> {
138 40655 : Ok(match value.0 / 10000 {
139 0 : 14 => PgMajorVersion::PG14,
140 0 : 15 => PgMajorVersion::PG15,
141 0 : 16 => PgMajorVersion::PG16,
142 40655 : 17 => PgMajorVersion::PG17,
143 0 : _ => return Err(InvalidPgVersion(value.0)),
144 : })
145 40655 : }
146 : }
147 :
148 : impl From<PgMajorVersion> for PgVersionId {
149 14 : fn from(value: PgMajorVersion) -> Self {
150 14 : PgVersionId((value as u32) * 10000)
151 14 : }
152 : }
153 :
154 : #[derive(Debug, PartialEq, Eq, thiserror::Error)]
155 : pub struct PgMajorVersionParseError(String);
156 :
157 : impl Display for PgMajorVersionParseError {
158 0 : fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
159 0 : write!(f, "PgMajorVersionParseError({})", self.0)
160 0 : }
161 : }
162 :
163 : impl FromStr for PgMajorVersion {
164 : type Err = PgMajorVersionParseError;
165 :
166 0 : fn from_str(s: &str) -> Result<Self, Self::Err> {
167 0 : Ok(match s {
168 0 : "14" => PgMajorVersion::PG14,
169 0 : "15" => PgMajorVersion::PG15,
170 0 : "16" => PgMajorVersion::PG16,
171 0 : "17" => PgMajorVersion::PG17,
172 0 : _ => return Err(PgMajorVersionParseError(s.to_string())),
173 : })
174 0 : }
175 : }
|