1use std::{
2 fmt::{self, Display, Formatter},
3 str::FromStr,
4};
5
6#[derive(Debug, Error)]
7pub enum CodenameParseError {
8 #[error("unknown codename string")]
9 NotFound,
10}
11
12#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub enum Codename {
15 Bionic,
16 Cosmic,
17 Disco,
18 Eoan,
19 Focal,
20 Groovy,
21 Hirsute,
22 Impish,
23 Jammy,
24}
25
26impl Codename {
27 pub fn eol_date(self) -> (u32, u32, u32) {
29 let (y, m, d) = self.release_date();
30
31 if y % 2 == 0 && m == 4 {
32 (y + 10, m, d)
33 } else {
34 (y + 1, if m == 4 { 1 } else { 7 }, d)
35 }
36 }
37
38 pub fn release_date(self) -> (u32, u32, u32) {
40 match self {
41 Codename::Bionic => (2018, 4, 26),
42 Codename::Cosmic => (2018, 10, 18),
43 Codename::Disco => (2019, 4, 18),
44 Codename::Eoan => (2019, 10, 17),
45 Codename::Focal => (2020, 4, 23),
46 Codename::Groovy => (2020, 10, 22),
47 Codename::Hirsute => (2021, 4, 22),
48 Codename::Impish => (2021, 10, 14),
49 Codename::Jammy => (2022, 4, 21),
50 }
51 }
52
53 pub fn release_timestamp(self) -> u64 {
55 match self {
57 Codename::Bionic => 1_524_700_800,
58 Codename::Cosmic => 1_539_820_800,
59 Codename::Disco => 1_555_545_600,
60 Codename::Eoan => 1_571_270_400,
61 Codename::Focal => 1_587_600_000,
62 Codename::Groovy => 1_603_324_800,
63 Codename::Hirsute => 1_619_071_200,
64 Codename::Impish => 1_634_191_200,
65 Codename::Jammy => 1_650_492_000,
66 }
67 }
68}
69
70impl Display for Codename {
71 fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
72 fmt.write_str(<&'static str>::from(*self))
73 }
74}
75
76impl FromStr for Codename {
77 type Err = CodenameParseError;
78
79 fn from_str(input: &str) -> Result<Self, Self::Err> {
80 let release = match input {
81 "bionic" => Codename::Bionic,
82 "cosmic" => Codename::Cosmic,
83 "disco" => Codename::Disco,
84 "eoan" => Codename::Eoan,
85 "focal" => Codename::Focal,
86 "groovy" => Codename::Groovy,
87 "hirsute" => Codename::Hirsute,
88 "impish" => Codename::Impish,
89 "jammy" => Codename::Jammy,
90 _ => return Err(CodenameParseError::NotFound),
91 };
92
93 Ok(release)
94 }
95}
96
97impl From<Codename> for &'static str {
98 fn from(codename: Codename) -> Self {
99 match codename {
100 Codename::Bionic => "bionic",
101 Codename::Cosmic => "cosmic",
102 Codename::Disco => "disco",
103 Codename::Eoan => "eoan",
104 Codename::Focal => "focal",
105 Codename::Groovy => "groovy",
106 Codename::Hirsute => "hirsute",
107 Codename::Impish => "impish",
108 Codename::Jammy => "jammy",
109 }
110 }
111}