1#[warn(missing_docs, missing_debug_implementations)]
2#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3use raw_cpuid::CpuId;
4#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
5use raw_cpuid::ProcessorBrandString;
6#[cfg(target_os = "linux")]
7use rayon::prelude::*;
8#[cfg(target_os = "linux")]
9use std::fs;
10#[cfg(target_os = "linux")]
11use std::path::Path;
12#[cfg(target_os = "macos")]
13use std::process::Command;
14use std::env::consts::{ARCH, OS};
15use wgpu::{Backends, Instance};
16#[cfg(target_os = "windows")]
17use windows_registry::LOCAL_MACHINE;
18
19mod constants;
20#[cfg(target_os = "linux")]
21use constants::WSL_INTEROP_PATH;
22#[cfg(target_os = "windows")]
23use constants::{COMPUTER_NAME_PATH, WIN_EDITION_PATH};
24mod display;
25#[cfg(test)]
26mod tests;
27
28#[derive(Debug)]
29pub struct OSProfile<'o, 'a> {
30 pub os: &'o str,
31 pub arch: &'a str,
32 pub win_edition: Option<String>,
33 pub computer_name: Option<String>,
34 pub is_wsl: Option<bool>,
35 pub distro: Option<String>,
36 pub hostname: Option<String>,
37}
38
39#[derive(Debug)]
40pub struct Processor<M, C> {
41 pub model: M,
42 pub cores: C,
43}
44
45#[derive(Debug)]
46pub struct GraphicsCard {
47 pub model: String,
48 pub driver_version: String,
49}
50
51display_profile!(OSProfile);
53display_graphics!(GraphicsCard);
54display_processor!(Processor<M, C>);
55
56impl<'o, 'a> OSProfile<'o, 'a> {
57 pub fn new() -> Self {
58 Self {
59 os: OS,
60 arch: ARCH,
61 win_edition: None,
62 computer_name: None,
63 is_wsl: None,
64 distro: None,
65 hostname: None,
66 }
67 }
68
69 #[cfg(target_os = "windows")]
71 pub fn win_edition(mut self) -> Self {
72 let key = LOCAL_MACHINE;
73 let sub_key = key
74 .open(WIN_EDITION_PATH)
75 .expect("Failed to find registry entry for: CurrentVersion");
76 let edition = sub_key
77 .get_string("EditionID")
78 .expect("Failed to identify Windows Edition");
79
80 self.win_edition = Some(edition);
81 self
82 }
83
84 #[cfg(target_os = "windows")]
86 pub fn computer_name(mut self) -> Self {
87 let key = LOCAL_MACHINE;
88 let sub_key = key
89 .open(COMPUTER_NAME_PATH)
90 .expect("Failed to find registry entry for: ComputerName");
91 let name = sub_key
92 .get_string("ComputerName")
93 .expect("Failed to find key: ComputerName");
94
95 self.computer_name = Some(name);
96 self
97 }
98
99 #[cfg(target_os = "linux")]
101 pub fn distro(mut self) -> Self {
102 let text = fs::read_to_string("/etc/os-release").expect("Failed to read /etc/os-release");
103 let tokens = text.split("\n").collect::<Vec<&str>>();
104 let pretty_name = tokens
105 .par_iter()
106 .filter(|line| line.contains("PRETTY_NAME"))
107 .collect::<Vec<&&str>>();
108
109 let distro = pretty_name[0].split("=").collect::<Vec<&str>>()[1].replace("\"", "");
110 self.distro = Some(distro);
111 self
112 }
113
114 #[cfg(target_os = "linux")]
116 pub fn hostname(mut self) -> Self {
117 let name = fs::read_to_string("/etc/hostname").expect("Failed to read /etc/hostname");
118 self.hostname = Some(name.split("\n").collect::<String>());
119 self
120 }
121
122 #[cfg(target_os = "linux")]
124 pub fn is_wsl(mut self) -> Self {
125 let path = Path::new(WSL_INTEROP_PATH).exists();
126 self.is_wsl = Some(path);
127 self
128 }
129
130 pub fn build(self) -> Self {
131 Self {
132 os: self.os,
133 arch: self.arch,
134 win_edition: self.win_edition,
135 computer_name: self.computer_name,
136 is_wsl: self.is_wsl,
137 distro: self.distro,
138 hostname: self.hostname,
139 }
140 }
141}
142
143#[cfg(target_os = "macos")]
145pub fn sysctl_cpu() -> Processor<String, String> {
146 let get_sysctl_output = |arg: &str| -> String {
147 let output = Command::new("sysctl")
148 .arg(arg)
149 .output()
150 .expect("Failed to execute sysctl command");
151 String::from_utf8(output.stdout)
152 .unwrap()
153 .split(": ")
154 .nth(1)
155 .unwrap()
156 .trim()
157 .to_string()
158 };
159
160 Processor {
161 model: get_sysctl_output("machdep.cpu.brand_string"),
162 cores: get_sysctl_output("hw.logicalcpu"),
163 }
164}
165
166#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
168pub fn x86_cpu() -> Processor<ProcessorBrandString, u32> {
169 let cpuid = CpuId::new();
170 let brand = cpuid.get_processor_brand_string().unwrap();
171 let cores = cpuid.get_processor_capacity_feature_info().unwrap();
172
173 Processor {
174 model: brand,
175 cores: cores.maximum_logical_processors() as u32,
176 }
177}
178
179pub fn gpu() -> Option<GraphicsCard> {
181 let instance = Instance::default();
182 for adapter in instance.enumerate_adapters(Backends::all()) {
183 let info = adapter.get_info();
184 let gpu = GraphicsCard {
185 model: info.name,
186 driver_version: info.driver_info,
187 };
188 return Some(gpu);
189 }
190 None
191}