chrome_for_testing/api/
version.rs

1use serde::de::{self, Visitor};
2use serde::{Deserialize, Deserializer};
3use std::cmp::PartialOrd;
4use std::fmt::{Display, Formatter};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct Version {
8    pub major: u32,
9    pub minor: u32,
10    pub patch: u32,
11    pub build: u32,
12}
13
14impl Display for Version {
15    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
16        f.write_fmt(format_args!(
17            "{}.{}.{}.{}",
18            self.major, self.minor, self.patch, self.build
19        ))
20    }
21}
22
23impl PartialOrd for Version {
24    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
25        if self.major != other.major {
26            return self.major.partial_cmp(&other.major);
27        }
28        if self.minor != other.minor {
29            return self.minor.partial_cmp(&other.minor);
30        }
31        if self.patch != other.patch {
32            return self.patch.partial_cmp(&other.patch);
33        }
34        if self.build != other.build {
35            return self.build.partial_cmp(&other.build);
36        }
37        Some(std::cmp::Ordering::Equal)
38    }
39
40    fn lt(&self, other: &Self) -> bool {
41        self.partial_cmp(other) == Some(std::cmp::Ordering::Less)
42    }
43
44    fn le(&self, other: &Self) -> bool {
45        self.partial_cmp(other) != Some(std::cmp::Ordering::Greater)
46    }
47
48    fn gt(&self, other: &Self) -> bool {
49        self.partial_cmp(other) == Some(std::cmp::Ordering::Greater)
50    }
51
52    fn ge(&self, other: &Self) -> bool {
53        self.partial_cmp(other) != Some(std::cmp::Ordering::Less)
54    }
55}
56
57// Thanks chatgpt
58impl<'de> Deserialize<'de> for Version {
59    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60    where
61        D: Deserializer<'de>,
62    {
63        struct VersionVisitor;
64
65        impl Visitor<'_> for VersionVisitor {
66            type Value = Version;
67
68            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
69                formatter.write_str("a version string in dot format")
70            }
71
72            fn visit_str<E>(self, value: &str) -> Result<Version, E>
73            where
74                E: de::Error,
75            {
76                let parts: Vec<&str> = value.split('.').collect();
77
78                if parts.len() == 4 {
79                    let major: Result<u32, E> = parts[0].parse().map_err(de::Error::custom);
80                    let minor: Result<u32, E> = parts[1].parse().map_err(de::Error::custom);
81                    let patch: Result<u32, E> = parts[2].parse().map_err(de::Error::custom);
82                    let build: Result<u32, E> = parts[3].parse().map_err(de::Error::custom);
83
84                    Ok(Version {
85                        major: major?,
86                        minor: minor?,
87                        patch: patch?,
88                        build: build?,
89                    })
90                } else {
91                    Err(de::Error::custom("Invalid version string format"))
92                }
93            }
94        }
95
96        deserializer.deserialize_str(VersionVisitor)
97    }
98}