1#![doc = include_str!("../readme.md")]
2#![cfg(windows)]
3#![cfg_attr(not(test), no_std)]
4#![allow(non_snake_case, clippy::upper_case_acronyms)]
5
6mod bindings;
7use bindings::*;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
11pub struct OsVersion {
12 pub major: u32,
14
15 pub minor: u32,
17
18 pub pack: u32,
20
21 pub build: u32,
23}
24
25impl OsVersion {
26 pub const fn new(major: u32, minor: u32, pack: u32, build: u32) -> Self {
28 Self {
29 major,
30 minor,
31 pack,
32 build,
33 }
34 }
35
36 #[cfg(not(test))]
38 pub fn current() -> Self {
39 let mut info = OSVERSIONINFOEXW::new();
40
41 unsafe {
42 RtlGetVersion(&mut info as *mut _ as *mut _);
43 }
44
45 Self {
46 major: info.dwMajorVersion,
47 minor: info.dwMinorVersion,
48 pack: info.wServicePackMajor as u32,
49 build: info.dwBuildNumber,
50 }
51 }
52
53 #[cfg(test)]
55 fn current() -> Self {
56 test::test_current()
57 }
58}
59
60pub fn is_server() -> bool {
62 let mut info = OSVERSIONINFOEXW::new();
63
64 unsafe {
65 RtlGetVersion(&mut info as *mut _ as *mut _);
66 }
67
68 info.wProductType as u32 != VER_NT_WORKSTATION
69}
70
71impl OSVERSIONINFOEXW {
72 fn new() -> Self {
73 Self {
74 dwOSVersionInfoSize: core::mem::size_of::<Self>() as u32,
75 ..Default::default()
76 }
77 }
78}
79
80#[cfg(test)]
81#[allow(clippy::nonminimal_bool)] mod test {
83 use super::OsVersion;
84 use std::sync::RwLock;
85
86 static TEST_CURRENT: RwLock<OsVersion> = RwLock::new(OsVersion::new(0, 0, 0, 0));
87
88 pub fn test_current() -> OsVersion {
89 *TEST_CURRENT.read().unwrap()
90 }
91
92 fn set_current(version: OsVersion) {
93 *TEST_CURRENT.write().unwrap() = version;
94 }
95
96 #[test]
97 fn test() {
98 assert_eq!(OsVersion::current(), OsVersion::new(0, 0, 0, 0));
99
100 set_current(OsVersion::new(1, 2, 3, 4));
101 assert_eq!(OsVersion::current(), OsVersion::new(1, 2, 3, 4));
102
103 set_current(OsVersion::new(10, 0, 0, 0));
104 assert!(OsVersion::current() >= OsVersion::new(9, 0, 0, 0));
105 assert!(OsVersion::current() >= OsVersion::new(10, 0, 0, 0));
106 assert!(!(OsVersion::current() >= OsVersion::new(11, 0, 0, 0)));
107
108 set_current(OsVersion::new(10, 100, 0, 0));
109 assert!(OsVersion::current() >= OsVersion::new(10, 99, 0, 0));
110 assert!(OsVersion::current() >= OsVersion::new(10, 100, 0, 0));
111 assert!(!(OsVersion::current() >= OsVersion::new(10, 101, 0, 0)));
112
113 set_current(OsVersion::new(10, 100, 1000, 0));
114 assert!(OsVersion::current() >= OsVersion::new(10, 100, 999, 0));
115 assert!(OsVersion::current() >= OsVersion::new(10, 100, 1000, 0));
116 assert!(!(OsVersion::current() >= OsVersion::new(10, 100, 1001, 0)));
117
118 set_current(OsVersion::new(10, 100, 1_000, 10_000));
119 assert!(OsVersion::current() >= OsVersion::new(10, 100, 1_000, 9_999));
120 assert!(OsVersion::current() >= OsVersion::new(10, 100, 1_000, 10_000));
121 assert!(!(OsVersion::current() >= OsVersion::new(10, 100, 1_000, 10_001)));
122 }
123}