1use std::{
2 fmt,
3 str::FromStr,
4};
5
6pub(crate) mod app;
7pub mod cmd;
8
9#[derive(Clone)]
10pub enum VersionField {
11 Major,
12 Minor,
13 Patch,
14}
15
16#[derive(Clone, PartialEq)]
17pub struct Version {
18 major: u32,
19 minor: u32,
20 patch: u32,
21 tag: Option<String>,
22}
23
24impl Version {
25 pub fn bump_major(&mut self) {
26 self.major += 1;
27 self.minor = 0;
28 self.patch = 0;
29 }
30
31 pub fn bump_minor(&mut self) {
32 self.minor += 1;
33 self.patch = 0;
34 }
35
36 pub fn bump_patch(&mut self) {
37 self.patch += 1;
38 }
39}
40
41impl fmt::Display for Version {
42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43 write!(
44 f,
45 "{major}.{minor}.{patch}{tag}",
46 major = self.major,
47 minor = self.minor,
48 patch = self.patch,
49 tag = self.tag.as_deref().unwrap_or("")
50 )
51 }
52}
53
54impl FromStr for Version {
55 type Err = &'static str;
56
57 fn from_str(s: &str) -> Result<Self, &'static str> {
58 let mut fields = s.splitn(4, '.');
59 let major = fields
60 .next()
61 .ok_or("the `major` field is missing")?
62 .parse::<u32>()
63 .map_err(|_| "the `major` field must be a non-negative integer")?;
64
65 let minor = fields
66 .next()
67 .ok_or("the `minor` field is missing")?
68 .parse::<u32>()
69 .map_err(|_| "the `minor` field must be a non-negative integer")?;
70
71 let patch = fields
72 .next()
73 .ok_or("the `patch` field is missing")?
74 .parse::<u32>()
75 .map_err(|_| "the `patch` field must be a non-negative integer")?;
76
77 let tag = fields.next().map(String::from);
78
79 Ok(Self {
80 major,
81 minor,
82 patch,
83 tag,
84 })
85 }
86}