os_info/info.rs
1// spell-checker:ignore itertools, iproduct, bitnesses
2
3use std::fmt::{self, Display, Formatter};
4
5use super::{Bitness, Type, Version};
6
7/// Holds information about operating system (type, version, etc.).
8///
9/// The best way to get string representation of the operation system information is to use its
10/// `Display` implementation.
11///
12/// # Examples
13///
14/// ```
15/// use os_info;
16///
17/// let info = os_info::get();
18/// println!("OS information: {info}");
19/// ```
20#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Info {
23 /// Operating system type. See `Type` for details.
24 pub(crate) os_type: Type,
25 /// Operating system version. See `Version` for details.
26 pub(crate) version: Version,
27 /// Operating system edition.
28 pub(crate) edition: Option<String>,
29 /// Operating system codename.
30 pub(crate) codename: Option<String>,
31 /// Operating system architecture in terms of how many bits compose the basic values it can deal
32 /// with. See `Bitness` for details.
33 pub(crate) bitness: Bitness,
34 /// Processor architecture.
35 pub(crate) architecture: Option<String>,
36}
37
38impl Info {
39 /// Constructs a new `Info` instance with unknown type, version and bitness.
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use os_info::{Info, Type, Version, Bitness};
45 ///
46 /// let info = Info::unknown();
47 /// assert_eq!(Type::Unknown, info.os_type());
48 /// assert_eq!(&Version::Unknown, info.version());
49 /// assert_eq!(None, info.edition());
50 /// assert_eq!(None, info.codename());
51 /// assert_eq!(Bitness::Unknown, info.bitness());
52 /// assert_eq!(None, info.architecture());
53 /// ```
54 pub fn unknown() -> Self {
55 Self {
56 os_type: Type::Unknown,
57 version: Version::Unknown,
58 edition: None,
59 codename: None,
60 bitness: Bitness::Unknown,
61 architecture: None,
62 }
63 }
64
65 /// Constructs a new `Info` instance with the specified operating system type.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use os_info::{Info, Type, Version, Bitness};
71 ///
72 /// let os_type = Type::Linux;
73 /// let info = Info::with_type(os_type);
74 /// assert_eq!(os_type, info.os_type());
75 /// assert_eq!(&Version::Unknown, info.version());
76 /// assert_eq!(None, info.edition());
77 /// assert_eq!(None, info.codename());
78 /// assert_eq!(Bitness::Unknown, info.bitness());
79 /// assert_eq!(None, info.architecture());
80 /// ```
81 pub fn with_type(os_type: Type) -> Self {
82 Self {
83 os_type,
84 ..Default::default()
85 }
86 }
87
88 /// Returns operating system type. See `Type` for details.
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// use os_info::{Info, Type};
94 ///
95 /// let info = Info::unknown();
96 /// assert_eq!(Type::Unknown, info.os_type());
97 /// ```
98 pub fn os_type(&self) -> Type {
99 self.os_type
100 }
101
102 /// Returns operating system version. See `Version` for details.
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// use os_info::{Info, Version};
108 ///
109 /// let info = Info::unknown();
110 /// assert_eq!(&Version::Unknown, info.version());
111 /// ```
112 pub fn version(&self) -> &Version {
113 &self.version
114 }
115
116 /// Returns optional operation system edition.
117 ///
118 /// # Examples
119 ///
120 /// ```
121 /// use os_info::Info;
122 ///
123 /// let info = Info::unknown();
124 /// assert_eq!(None, info.edition());
125 pub fn edition(&self) -> Option<&str> {
126 self.edition.as_ref().map(String::as_ref)
127 }
128
129 /// Returns optional operation system 'codename'.
130 ///
131 /// # Examples
132 ///
133 /// ```
134 /// use os_info::Info;
135 ///
136 /// let info = Info::unknown();
137 /// assert_eq!(None, info.codename());
138 pub fn codename(&self) -> Option<&str> {
139 self.codename.as_ref().map(String::as_ref)
140 }
141
142 /// Returns operating system bitness. See `Bitness` for details.
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use os_info::{Info, Bitness};
148 ///
149 /// let info = Info::unknown();
150 /// assert_eq!(Bitness::Unknown, info.bitness());
151 /// ```
152 pub fn bitness(&self) -> Bitness {
153 self.bitness
154 }
155
156 /// Returns operating system architecture.
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// use os_info::Info;
162 ///
163 /// let info = Info::unknown();
164 /// assert_eq!(None, info.architecture());
165 pub fn architecture(&self) -> Option<&str> {
166 self.architecture.as_ref().map(String::as_ref)
167 }
168}
169
170impl Default for Info {
171 fn default() -> Self {
172 Self::unknown()
173 }
174}
175
176impl Display for Info {
177 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
178 write!(f, "{}", self.os_type)?;
179 if self.version != Version::Unknown {
180 write!(f, " {}", self.version)?;
181 }
182 if let Some(ref edition) = self.edition {
183 write!(f, " ({edition})")?;
184 }
185 if let Some(ref codename) = self.codename {
186 write!(f, " ({codename})")?;
187 }
188 write!(f, " [{}]", self.bitness)
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use pretty_assertions::assert_eq;
196
197 #[test]
198 fn unknown() {
199 let info = Info::unknown();
200 assert_eq!(Type::Unknown, info.os_type());
201 assert_eq!(&Version::Unknown, info.version());
202 assert_eq!(None, info.edition());
203 assert_eq!(None, info.codename());
204 assert_eq!(Bitness::Unknown, info.bitness());
205 assert_eq!(None, info.architecture());
206 }
207
208 #[test]
209 fn with_type() {
210 let types = [
211 Type::AIX,
212 Type::Redox,
213 Type::Alpaquita,
214 Type::Alpine,
215 Type::Amazon,
216 Type::Android,
217 Type::Arch,
218 Type::Artix,
219 Type::Bluefin,
220 Type::CachyOS,
221 Type::CentOS,
222 Type::Debian,
223 Type::Emscripten,
224 Type::EndeavourOS,
225 Type::Fedora,
226 Type::Gentoo,
227 Type::Linux,
228 Type::Macos,
229 Type::Manjaro,
230 Type::Mariner,
231 Type::NixOS,
232 Type::Nobara,
233 Type::Uos,
234 Type::OpenCloudOS,
235 Type::openEuler,
236 Type::openSUSE,
237 Type::OracleLinux,
238 Type::Pop,
239 Type::Redhat,
240 Type::RedHatEnterprise,
241 Type::Redox,
242 Type::Solus,
243 Type::SUSE,
244 Type::Ubuntu,
245 Type::Ultramarine,
246 Type::Void,
247 Type::Mint,
248 Type::Unknown,
249 Type::Windows,
250 ];
251
252 for t in &types {
253 let info = Info::with_type(*t);
254 assert_eq!(t, &info.os_type());
255 }
256 }
257
258 #[test]
259 fn default() {
260 assert_eq!(Info::default(), Info::unknown());
261 }
262
263 #[test]
264 fn display() {
265 let data = [
266 // All unknown.
267 (Info::unknown(), "Unknown [unknown bitness]"),
268 // Type.
269 (
270 Info {
271 os_type: Type::Redox,
272 ..Default::default()
273 },
274 "Redox [unknown bitness]",
275 ),
276 // Type and version.
277 (
278 Info {
279 os_type: Type::Linux,
280 version: Version::Semantic(2, 3, 4),
281 ..Default::default()
282 },
283 "Linux 2.3.4 [unknown bitness]",
284 ),
285 (
286 Info {
287 os_type: Type::Arch,
288 version: Version::Rolling(None),
289 ..Default::default()
290 },
291 "Arch Linux Rolling Release [unknown bitness]",
292 ),
293 (
294 Info {
295 os_type: Type::Artix,
296 version: Version::Rolling(None),
297 ..Default::default()
298 },
299 "Artix Linux Rolling Release [unknown bitness]",
300 ),
301 (
302 Info {
303 os_type: Type::Manjaro,
304 version: Version::Rolling(Some("2020.05.24".to_owned())),
305 ..Default::default()
306 },
307 "Manjaro Rolling Release (2020.05.24) [unknown bitness]",
308 ),
309 (
310 Info {
311 os_type: Type::Windows,
312 version: Version::Custom("Special Version".to_owned()),
313 ..Default::default()
314 },
315 "Windows Special Version [unknown bitness]",
316 ),
317 // Bitness.
318 (
319 Info {
320 bitness: Bitness::X32,
321 ..Default::default()
322 },
323 "Unknown [32-bit]",
324 ),
325 (
326 Info {
327 bitness: Bitness::X64,
328 ..Default::default()
329 },
330 "Unknown [64-bit]",
331 ),
332 // All info.
333 (
334 Info {
335 os_type: Type::Macos,
336 version: Version::Semantic(10, 2, 0),
337 edition: Some("edition".to_owned()),
338 codename: Some("codename".to_owned()),
339 bitness: Bitness::X64,
340 architecture: Some("architecture".to_owned()),
341 },
342 "Mac OS 10.2.0 (edition) (codename) [64-bit]",
343 ),
344 ];
345
346 for (info, expected) in &data {
347 assert_eq!(expected, &info.to_string());
348 }
349 }
350}