Skip to main content

libc_abi_tools/
version.rs

1use std::{fmt, str::FromStr};
2
3/// Numeric ABI version. Historical symbol versions may precede our target floor.
4#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
5pub struct Version {
6    pub major: u32,
7    pub minor: u32,
8    pub patch: u32,
9}
10
11impl Version {
12    /// Validate a glibc release directory (as opposed to a symbol version).
13    pub fn validate_release(self) -> Result<Self, String> {
14        if self.major != 2 || self.minor < 17 || self.patch != 0 {
15            return Err(
16                "expected a glibc 2.x release starting at 2.17, without a patch component".into(),
17            );
18        }
19        Ok(self)
20    }
21}
22
23impl FromStr for Version {
24    type Err = String;
25
26    fn from_str(text: &str) -> Result<Self, String> {
27        let parts: Vec<_> = text.split('.').collect();
28        if !(2..=3).contains(&parts.len()) {
29            return Err(format!("invalid numeric version {text:?}"));
30        }
31        let number = |s: &str| -> Result<u32, String> {
32            if s.is_empty() || !s.bytes().all(|b| b.is_ascii_digit()) {
33                return Err(format!("invalid numeric version {text:?}"));
34            }
35            s.parse()
36                .map_err(|_| format!("version component too large: {text:?}"))
37        };
38        Ok(Self {
39            major: number(parts[0])?,
40            minor: number(parts[1])?,
41            patch: if parts.len() == 3 {
42                number(parts[2])?
43            } else {
44                0
45            },
46        })
47    }
48}
49
50impl fmt::Display for Version {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "{}.{}", self.major, self.minor)?;
53        if self.patch != 0 {
54            write!(f, ".{}", self.patch)?;
55        }
56        Ok(())
57    }
58}