/ src / lib.rs
lib.rs
  1  use raw_cpuid::CpuId;
  2  use raw_cpuid::ProcessorBrandString;
  3  use rayon::prelude::*;
  4  use std::env::consts::{ARCH, OS};
  5  use std::fs;
  6  use std::path::Path;
  7  use wgpu::{Backends, Instance};
  8  #[cfg(target_os = "windows")]
  9  use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
 10  
 11  #[derive(Debug)]
 12  pub struct OSProfile {
 13      pub os: &'static str,
 14      pub arch: &'static str,
 15      pub win_edition: Option<String>,
 16      pub is_wsl: Option<bool>,
 17      pub linux_distro: Option<String>,
 18  }
 19  
 20  #[derive(Debug)]
 21  pub struct Processor {
 22      pub model: ProcessorBrandString,
 23      pub cores: u32,
 24  }
 25  
 26  #[derive(Debug)]
 27  pub struct GPU {
 28      pub model: String,
 29      pub driver_version: String,
 30  }
 31  
 32  impl OSProfile {
 33      pub fn new() -> Self {
 34          Self {
 35              os: OS,
 36              arch: ARCH,
 37              win_edition: None,
 38              is_wsl: None,
 39              linux_distro: None,
 40          }
 41      }
 42  
 43      /// Returns the Windows edition if a Windows system is available
 44      #[cfg(target_os = "windows")]
 45      pub fn win_edition(mut self) -> Self {
 46          let sub_key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
 47          let reg = RegKey::predef(HKEY_LOCAL_MACHINE)
 48              .open_subkey(sub_key)
 49              .expect("Failed to open registry key");
 50          let edition: String = reg
 51              .get_value("EditionID")
 52              .expect("Failed to get Windows edition from registry");
 53  
 54          self.win_edition = Some(edition);
 55          self
 56      }
 57  
 58      /// Returns the Linux distro if a Linux system is available
 59      #[cfg(target_os = "linux")]
 60      pub fn linux_distro(mut self) -> Self {
 61          let text = fs::read_to_string("/etc/os-release").expect("Failed to read /etc/os-release");
 62          let tokens = text.split("\n").collect::<Vec<&str>>();
 63          let pretty_name = tokens
 64              .par_iter()
 65              .filter(|line| line.contains("PRETTY_NAME"))
 66              .collect::<Vec<&&str>>();
 67  
 68          let distro = pretty_name[0].split("=").collect::<Vec<&str>>()[1].replace("\"", "");
 69          self.linux_distro = Some(distro);
 70          self
 71      }
 72  
 73      /// Returns true if the Linux host is running on WSL
 74      #[cfg(target_os = "linux")]
 75      pub fn is_wsl(mut self) -> Self {
 76          let path = Path::new("/proc/sys/fs/binfmt_misc/WSLInterop").exists();
 77          self.is_wsl = Some(path);
 78          self
 79      }
 80  
 81      pub fn build(self) -> Self {
 82          Self {
 83              os: self.os,
 84              arch: self.arch,
 85              win_edition: self.win_edition,
 86              is_wsl: self.is_wsl,
 87              linux_distro: self.linux_distro,
 88          }
 89      }
 90  }
 91  
 92  /// Returns a `Processor` object containing the CPU model and logical core count  (x86 only)
 93  pub fn cpu() -> Processor {
 94      let cpuid = CpuId::new();
 95      let brand = cpuid.get_processor_brand_string().expect("Unsupported CPU");
 96      let cores = cpuid
 97          .get_processor_capacity_feature_info()
 98          .expect("Failed to retrieve proc cap info");
 99  
100      let cpu = Processor {
101          model: brand,
102          cores: cores.maximum_logical_processors() as u32,
103      };
104      cpu
105  }
106  
107  /// Returns a `GPU` object containing the GPU model and driver version
108  pub fn gpu() -> Option<GPU> {
109      let instance = Instance::default();
110  
111      for adapter in instance.enumerate_adapters(Backends::all()) {
112          let info = adapter.get_info();
113          let gpu = GPU {
114              model: info.name,
115              driver_version: info.driver_info,
116          };
117          return Some(gpu);
118      }
119      None
120  }
121  
122  #[cfg(test)]
123  mod tests {
124      use super::*;
125  
126      #[test]
127      fn test_profile() {
128          let profile = OSProfile::new().build();
129          assert_eq!(profile.os, OS);
130          assert_eq!(profile.arch, ARCH);
131      }
132  
133      #[test]
134      fn test_distro() {
135          let distro = OSProfile::new().linux_distro().build();
136          assert!(distro.linux_distro.unwrap().starts_with("Fedora"));
137      }
138  
139      #[test]
140      fn test_wsl() {
141          let wsl = OSProfile::new().is_wsl().build();
142          assert_eq!(wsl.is_wsl, Some(false));
143      }
144  
145      #[test]
146      fn test_cpu() {
147          let cpu = cpu();
148          assert!(cpu.model.as_str().starts_with("AMD"));
149          assert_eq!(cpu.cores, 16);
150      }
151  
152      #[test]
153      fn test_gpu() {
154          let gpu = gpu();
155          assert!(gpu.is_some());
156      }
157  }