Quellcode durchsuchen

spec: impl `Eq`, `PartialEq`, `Ord`, `PartialOrd` for `Version`, add unit tests

Version is now declared total-order, add detailed unit test on Version.

Our implementation ignore 31 bit of Version by now for backward comptability.

Signed-off-by: Zhouqi Jiang <luojia@hust.edu.cn>
Zhouqi Jiang vor 5 Monaten
Ursprung
Commit
a853e27ca3
2 geänderte Dateien mit 110 neuen und 1 gelöschten Zeilen
  1. 1 0
      sbi-spec/CHANGELOG.md
  2. 109 1
      sbi-spec/src/base.rs

+ 1 - 0
sbi-spec/CHANGELOG.md

@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 - binary: add counter index mask type ([#71](https://github.com/rustsbi/rustsbi/pull/71))
 - pmu: add `shmem_size` module for PMU snapshot shared memory, add unit test for `pmu::shmem_size::SIZE`
 - binary: add function `is_ok_and`, `is_err_and`, `inspect` and `inspect_err` for `SbiRet` structure
+- base: impl `Eq`, `PartialEq`, `Ord`, `PartialOrd` for `Version`, add unit tests
 
 ### Modified
 

+ 109 - 1
sbi-spec/src/base.rs

@@ -9,10 +9,12 @@ pub const UNAVAILABLE_EXTENSION: usize = 0;
 
 /// SBI specification version.
 ///
+/// In RISC-V SBI specification, the bit 31 must be 0 and is reserved for future expansion.
+///
 /// Not to be confused with 'implementation version'.
 ///
 /// Declared in §4.1.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord)]
 #[repr(transparent)]
 pub struct Version {
     raw: usize,
@@ -45,6 +47,15 @@ impl core::fmt::Display for Version {
     }
 }
 
+impl core::cmp::PartialOrd for Version {
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        self.major()
+            .partial_cmp(&other.major())
+            .map(|ordering| ordering.then_with(|| self.minor().cmp(&other.minor())))
+    }
+}
+
 /// Declared in §4.8
 mod fid {
     /// Function ID to get the current SBI specification version.
@@ -104,3 +115,100 @@ pub mod impl_id {
     /// Oreboot.
     pub const OREBOOT: usize = 10;
 }
+
+#[cfg(test)]
+mod tests {
+    use super::Version;
+
+    #[test]
+    fn version_parse() {
+        let v1_0 = Version::from_raw(0x100_0000);
+        assert_eq!(v1_0.major(), 1);
+        assert_eq!(v1_0.minor(), 0);
+
+        let v2_0 = Version::from_raw(0x200_0000);
+        assert_eq!(v2_0.major(), 2);
+        assert_eq!(v2_0.minor(), 0);
+
+        let v2_1 = Version::from_raw(0x200_0001);
+        assert_eq!(v2_1.major(), 2);
+        assert_eq!(v2_1.minor(), 1);
+
+        let v2_max = Version::from_raw(0x2ff_ffff);
+        assert_eq!(v2_max.major(), 2);
+        assert_eq!(v2_max.minor(), 16777215);
+
+        let vmax_3 = Version::from_raw(0x7f00_0003);
+        assert_eq!(vmax_3.major(), 127);
+        assert_eq!(vmax_3.minor(), 3);
+
+        let vmax_max = Version::from_raw(0x7fff_ffff);
+        assert_eq!(vmax_max.major(), 127);
+        assert_eq!(vmax_max.minor(), 16777215);
+    }
+
+    #[test]
+    fn version_display() {
+        extern crate alloc;
+        use alloc::string::ToString;
+
+        assert_eq!("0.0", &Version::from_raw(0).to_string());
+        assert_eq!("0.1", &Version::from_raw(0x1).to_string());
+        assert_eq!("1.0", &Version::from_raw(0x100_0000).to_string());
+        assert_eq!("1.1", &Version::from_raw(0x100_0001).to_string());
+        assert_eq!("2.0", &Version::from_raw(0x200_0000).to_string());
+        assert_eq!("127.0", &Version::from_raw(0x7f00_0000).to_string());
+        assert_eq!("2.16777215", &Version::from_raw(0x2ff_ffff).to_string());
+        assert_eq!("127.16777215", &Version::from_raw(0x7fff_ffff).to_string());
+    }
+
+    #[test]
+    fn version_ordering() {
+        use core::cmp::Ordering;
+        let v0_0 = Version::from_raw(0x0);
+        let v0_3 = Version::from_raw(0x3);
+        let v1_0 = Version::from_raw(0x100_0000);
+        let v2_0 = Version::from_raw(0x200_0000);
+        let v2_1 = Version::from_raw(0x200_0001);
+        let v2_max = Version::from_raw(0x2ff_ffff);
+        let vmax_3 = Version::from_raw(0x7f00_0003);
+        let vmax_max = Version::from_raw(0x7fff_ffff);
+
+        assert!(v0_3 != v0_0);
+        assert!(!(v0_3 == v0_0));
+        assert!(v0_0 == v0_0);
+        assert!(vmax_max == vmax_max);
+
+        assert!(v0_3 > v0_0);
+        assert!(v0_3 >= v0_0);
+        assert!(v0_0 < v0_3);
+        assert!(v0_0 <= v0_3);
+        assert!(v0_0 >= v0_0);
+        assert!(v0_0 <= v0_0);
+
+        assert!(v0_3 > v0_0);
+        assert!(v1_0 > v0_3);
+        assert!(v2_0 > v1_0);
+        assert!(v2_1 > v2_0);
+        assert!(v2_max > v2_1);
+        assert!(vmax_3 > v2_max);
+        assert!(vmax_max > vmax_3);
+
+        assert_eq!(Version::partial_cmp(&v1_0, &v0_0), Some(Ordering::Greater));
+        assert_eq!(Version::partial_cmp(&v0_0, &v1_0), Some(Ordering::Less));
+        assert_eq!(Version::partial_cmp(&v0_0, &v0_0), Some(Ordering::Equal));
+
+        assert_eq!(Version::max(v0_0, v0_0), v0_0);
+        assert_eq!(Version::max(v1_0, v0_0), v1_0);
+        assert_eq!(Version::max(v0_0, v1_0), v1_0);
+        assert_eq!(Version::min(v0_0, v0_0), v0_0);
+        assert_eq!(Version::min(v1_0, v0_0), v0_0);
+        assert_eq!(Version::min(v0_0, v1_0), v0_0);
+
+        assert_eq!(v0_0.clamp(v0_3, v2_0), v0_3);
+        assert_eq!(v0_3.clamp(v0_3, v2_0), v0_3);
+        assert_eq!(v1_0.clamp(v0_3, v2_0), v1_0);
+        assert_eq!(v2_0.clamp(v0_3, v2_0), v2_0);
+        assert_eq!(v2_1.clamp(v0_3, v2_0), v2_0);
+    }
+}