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}