1use alloc::vec::Vec;
2use core::{
3 convert::TryFrom,
4 fmt::{self, Display, Formatter},
5 num::ParseIntError,
6};
7
8#[cfg(feature = "datasize")]
9use datasize::DataSize;
10use serde::{Deserialize, Serialize};
11
12use crate::bytesrepr::{self, Error, FromBytes, ToBytes, U32_SERIALIZED_LENGTH};
13
14pub const SEM_VER_SERIALIZED_LENGTH: usize = 3 * U32_SERIALIZED_LENGTH;
16
17#[derive(
19 Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
20)]
21#[cfg_attr(feature = "datasize", derive(DataSize))]
22pub struct SemVer {
23 pub major: u32,
25 pub minor: u32,
27 pub patch: u32,
29}
30
31impl SemVer {
32 pub const V1_0_0: SemVer = SemVer {
34 major: 1,
35 minor: 0,
36 patch: 0,
37 };
38
39 pub const fn new(major: u32, minor: u32, patch: u32) -> SemVer {
41 SemVer {
42 major,
43 minor,
44 patch,
45 }
46 }
47}
48
49impl ToBytes for SemVer {
50 fn to_bytes(&self) -> Result<Vec<u8>, Error> {
51 let mut ret = bytesrepr::unchecked_allocate_buffer(self);
52 ret.append(&mut self.major.to_bytes()?);
53 ret.append(&mut self.minor.to_bytes()?);
54 ret.append(&mut self.patch.to_bytes()?);
55 Ok(ret)
56 }
57
58 fn serialized_length(&self) -> usize {
59 SEM_VER_SERIALIZED_LENGTH
60 }
61}
62
63impl FromBytes for SemVer {
64 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
65 let (major, rem): (u32, &[u8]) = FromBytes::from_bytes(bytes)?;
66 let (minor, rem): (u32, &[u8]) = FromBytes::from_bytes(rem)?;
67 let (patch, rem): (u32, &[u8]) = FromBytes::from_bytes(rem)?;
68 Ok((SemVer::new(major, minor, patch), rem))
69 }
70}
71
72impl Display for SemVer {
73 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
74 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
80pub enum ParseSemVerError {
81 InvalidVersionFormat,
83 ParseIntError(ParseIntError),
85}
86
87impl Display for ParseSemVerError {
88 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
89 match self {
90 ParseSemVerError::InvalidVersionFormat => formatter.write_str("invalid version format"),
91 ParseSemVerError::ParseIntError(error) => error.fmt(formatter),
92 }
93 }
94}
95
96impl From<ParseIntError> for ParseSemVerError {
97 fn from(error: ParseIntError) -> ParseSemVerError {
98 ParseSemVerError::ParseIntError(error)
99 }
100}
101
102impl TryFrom<&str> for SemVer {
103 type Error = ParseSemVerError;
104 fn try_from(value: &str) -> Result<SemVer, Self::Error> {
105 let tokens: Vec<&str> = value.split('.').collect();
106 if tokens.len() != 3 {
107 return Err(ParseSemVerError::InvalidVersionFormat);
108 }
109
110 Ok(SemVer {
111 major: tokens[0].parse()?,
112 minor: tokens[1].parse()?,
113 patch: tokens[2].parse()?,
114 })
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use core::convert::TryInto;
122
123 #[test]
124 fn should_compare_semver_versions() {
125 assert!(SemVer::new(0, 0, 0) < SemVer::new(1, 2, 3));
126 assert!(SemVer::new(1, 1, 0) < SemVer::new(1, 2, 0));
127 assert!(SemVer::new(1, 0, 0) < SemVer::new(1, 2, 0));
128 assert!(SemVer::new(1, 0, 0) < SemVer::new(1, 2, 3));
129 assert!(SemVer::new(1, 2, 0) < SemVer::new(1, 2, 3));
130 assert!(SemVer::new(1, 2, 3) == SemVer::new(1, 2, 3));
131 assert!(SemVer::new(1, 2, 3) >= SemVer::new(1, 2, 3));
132 assert!(SemVer::new(1, 2, 3) <= SemVer::new(1, 2, 3));
133 assert!(SemVer::new(2, 0, 0) >= SemVer::new(1, 99, 99));
134 assert!(SemVer::new(2, 0, 0) > SemVer::new(1, 99, 99));
135 }
136
137 #[test]
138 fn parse_from_string() {
139 let ver1: SemVer = "100.20.3".try_into().expect("should parse");
140 assert_eq!(ver1, SemVer::new(100, 20, 3));
141 let ver2: SemVer = "0.0.1".try_into().expect("should parse");
142 assert_eq!(ver2, SemVer::new(0, 0, 1));
143
144 assert!(SemVer::try_from("1.a.2.3").is_err());
145 assert!(SemVer::try_from("1. 2.3").is_err());
146 assert!(SemVer::try_from("12345124361461.0.1").is_err());
147 assert!(SemVer::try_from("1.2.3.4").is_err());
148 assert!(SemVer::try_from("1.2").is_err());
149 assert!(SemVer::try_from("1").is_err());
150 assert!(SemVer::try_from("0").is_err());
151 }
152}