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 }