use core::fmt;
const MAJOR_SHIFT: u32 = 22;
const MINOR_SHIFT: u32 = 12;
const MINOR_MASK: u32 = 0x3FF;
const PATCH_MASK: u32 = 0xFFF;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Version {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
impl Version {
pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
Self {
major,
minor,
patch,
}
}
pub const fn from_raw(raw: u32) -> Self {
Self {
major: raw >> MAJOR_SHIFT,
minor: (raw >> MINOR_SHIFT) & MINOR_MASK,
patch: raw & PATCH_MASK,
}
}
pub const fn to_raw(self) -> u32 {
(self.major << MAJOR_SHIFT) | (self.minor << MINOR_SHIFT) | self.patch
}
}
impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip() {
let v = Version {
major: 1,
minor: 3,
patch: 250,
};
assert_eq!(Version::from_raw(v.to_raw()), v);
}
#[test]
fn from_raw_known_versions() {
let v10 = Version::from_raw(Version::new(1, 0, 0).to_raw());
assert_eq!(
v10,
Version {
major: 1,
minor: 0,
patch: 0
}
);
let v13 = Version::from_raw(0x00403000);
assert_eq!(
v13,
Version {
major: 1,
minor: 3,
patch: 0
}
);
}
#[test]
fn display_format() {
let v = Version {
major: 1,
minor: 2,
patch: 195,
};
assert_eq!(v.to_string(), "1.2.195");
}
#[test]
fn ordering() {
let v10 = Version {
major: 1,
minor: 0,
patch: 0,
};
let v12 = Version {
major: 1,
minor: 2,
patch: 0,
};
let v13 = Version {
major: 1,
minor: 3,
patch: 0,
};
assert!(v10 < v12);
assert!(v12 < v13);
}
#[test]
fn to_raw_known_versions() {
let v13 = Version {
major: 1,
minor: 3,
patch: 0,
};
assert_eq!(v13.to_raw(), 0x00403000);
}
}