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::AOSC,
218 Type::Arch,
219 Type::Artix,
220 Type::Bluefin,
221 Type::CachyOS,
222 Type::CentOS,
223 Type::Debian,
224 Type::Emscripten,
225 Type::EndeavourOS,
226 Type::Fedora,
227 Type::Gentoo,
228 Type::Linux,
229 Type::Macos,
230 Type::Manjaro,
231 Type::Mariner,
232 Type::NixOS,
233 Type::Nobara,
234 Type::Uos,
235 Type::OpenCloudOS,
236 Type::openEuler,
237 Type::openSUSE,
238 Type::OracleLinux,
239 Type::Pop,
240 Type::Redhat,
241 Type::RedHatEnterprise,
242 Type::Redox,
243 Type::Solus,
244 Type::SUSE,
245 Type::Ubuntu,
246 Type::Ultramarine,
247 Type::Void,
248 Type::Mint,
249 Type::Unknown,
250 Type::Windows,
251 ];
252
253 for t in &types {
254 let info = Info::with_type(*t);
255 assert_eq!(t, &info.os_type());
256 }
257 }
258
259 #[test]
260 fn default() {
261 assert_eq!(Info::default(), Info::unknown());
262 }
263
264 #[test]
265 fn display() {
266 let data = [
267 // All unknown.
268 (Info::unknown(), "Unknown [unknown bitness]"),
269 // Type.
270 (
271 Info {
272 os_type: Type::Redox,
273 ..Default::default()
274 },
275 "Redox [unknown bitness]",
276 ),
277 // Type and version.
278 (
279 Info {
280 os_type: Type::Linux,
281 version: Version::Semantic(2, 3, 4),
282 ..Default::default()
283 },
284 "Linux 2.3.4 [unknown bitness]",
285 ),
286 (
287 Info {
288 os_type: Type::AOSC,
289 version: Version::Semantic(12, 1, 3),
290 ..Default::default()
291 },
292 "AOSC OS 12.1.3 [unknown bitness]",
293 ),
294 (
295 Info {
296 os_type: Type::Arch,
297 version: Version::Rolling(None),
298 ..Default::default()
299 },
300 "Arch Linux Rolling Release [unknown bitness]",
301 ),
302 (
303 Info {
304 os_type: Type::Artix,
305 version: Version::Rolling(None),
306 ..Default::default()
307 },
308 "Artix Linux Rolling Release [unknown bitness]",
309 ),
310 (
311 Info {
312 os_type: Type::Manjaro,
313 version: Version::Rolling(Some("2020.05.24".to_owned())),
314 ..Default::default()
315 },
316 "Manjaro Rolling Release (2020.05.24) [unknown bitness]",
317 ),
318 (
319 Info {
320 os_type: Type::Windows,
321 version: Version::Custom("Special Version".to_owned()),
322 ..Default::default()
323 },
324 "Windows Special Version [unknown bitness]",
325 ),
326 // Bitness.
327 (
328 Info {
329 bitness: Bitness::X32,
330 ..Default::default()
331 },
332 "Unknown [32-bit]",
333 ),
334 (
335 Info {
336 bitness: Bitness::X64,
337 ..Default::default()
338 },
339 "Unknown [64-bit]",
340 ),
341 // All info.
342 (
343 Info {
344 os_type: Type::Macos,
345 version: Version::Semantic(10, 2, 0),
346 edition: Some("edition".to_owned()),
347 codename: Some("codename".to_owned()),
348 bitness: Bitness::X64,
349 architecture: Some("architecture".to_owned()),
350 },
351 "Mac OS 10.2.0 (edition) (codename) [64-bit]",
352 ),
353 ];
354
355 for (info, expected) in &data {
356 assert_eq!(expected, &info.to_string());
357 }
358 }
359}