1use core::fmt;
47use core::str::FromStr;
48
49#[cfg(feature = "serde")]
50use serde::{Deserialize, Serialize};
51
52#[cfg(feature = "arbitrary")]
53use arbitrary::Arbitrary;
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58pub enum OsTypeError {
59 UnknownOperatingSystem,
61}
62
63impl fmt::Display for OsTypeError {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 match self {
66 Self::UnknownOperatingSystem => write!(f, "unknown operating system"),
67 }
68 }
69}
70
71#[cfg(feature = "std")]
72impl std::error::Error for OsTypeError {}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
104#[non_exhaustive]
105pub enum OsType {
106 LINUX,
108 MACOS,
110 WINDOWS,
112 FREEBSD,
114 OPENBSD,
116 NETBSD,
118 DRAGONFLY,
120 SOLARIS,
122 ILLUMOS,
124 ANDROID,
126 IOS,
128 REDOX,
130 FUCHSIA,
132 HERMIT,
134 VXWORKS,
136 AIX,
138 HAIKU,
140}
141
142impl OsType {
143 #[must_use]
158 pub const fn current() -> Self {
159 #[cfg(target_os = "linux")]
160 return Self::LINUX;
161 #[cfg(target_os = "macos")]
162 return Self::MACOS;
163 #[cfg(target_os = "windows")]
164 return Self::WINDOWS;
165 #[cfg(target_os = "freebsd")]
166 return Self::FREEBSD;
167 #[cfg(target_os = "openbsd")]
168 return Self::OPENBSD;
169 #[cfg(target_os = "netbsd")]
170 return Self::NETBSD;
171 #[cfg(target_os = "dragonfly")]
172 return Self::DRAGONFLY;
173 #[cfg(target_os = "solaris")]
174 return Self::SOLARIS;
175 #[cfg(target_os = "illumos")]
176 return Self::ILLUMOS;
177 #[cfg(target_os = "android")]
178 return Self::ANDROID;
179 #[cfg(target_os = "ios")]
180 return Self::IOS;
181 #[cfg(target_os = "redox")]
182 return Self::REDOX;
183 #[cfg(target_os = "fuchsia")]
184 return Self::FUCHSIA;
185 #[cfg(target_os = "hermit")]
186 return Self::HERMIT;
187 #[cfg(target_os = "vxworks")]
188 return Self::VXWORKS;
189 #[cfg(target_os = "aix")]
190 return Self::AIX;
191 #[cfg(target_os = "haiku")]
192 return Self::HAIKU;
193 #[cfg(not(any(
194 target_os = "linux",
195 target_os = "macos",
196 target_os = "windows",
197 target_os = "freebsd",
198 target_os = "openbsd",
199 target_os = "netbsd",
200 target_os = "dragonfly",
201 target_os = "solaris",
202 target_os = "illumos",
203 target_os = "android",
204 target_os = "ios",
205 target_os = "redox",
206 target_os = "fuchsia",
207 target_os = "hermit",
208 target_os = "vxworks",
209 target_os = "aix",
210 target_os = "haiku",
211 )))]
212 {
213 panic!("unsupported target operating system")
214 }
215 }
216
217 #[must_use]
229 pub const fn as_str(&self) -> &'static str {
230 match self {
231 Self::LINUX => "linux",
232 Self::MACOS => "macos",
233 Self::WINDOWS => "windows",
234 Self::FREEBSD => "freebsd",
235 Self::OPENBSD => "openbsd",
236 Self::NETBSD => "netbsd",
237 Self::DRAGONFLY => "dragonfly",
238 Self::SOLARIS => "solaris",
239 Self::ILLUMOS => "illumos",
240 Self::ANDROID => "android",
241 Self::IOS => "ios",
242 Self::REDOX => "redox",
243 Self::FUCHSIA => "fuchsia",
244 Self::HERMIT => "hermit",
245 Self::VXWORKS => "vxworks",
246 Self::AIX => "aix",
247 Self::HAIKU => "haiku",
248 }
249 }
250
251 #[must_use]
264 pub const fn is_unix(&self) -> bool {
265 matches!(
266 self,
267 Self::LINUX
268 | Self::MACOS
269 | Self::FREEBSD
270 | Self::OPENBSD
271 | Self::NETBSD
272 | Self::DRAGONFLY
273 | Self::SOLARIS
274 | Self::ILLUMOS
275 | Self::ANDROID
276 | Self::IOS
277 | Self::AIX
278 | Self::HAIKU
279 )
280 }
281
282 #[must_use]
298 pub const fn is_bsd(&self) -> bool {
299 matches!(
300 self,
301 Self::FREEBSD | Self::OPENBSD | Self::NETBSD | Self::DRAGONFLY | Self::MACOS
302 )
303 }
304
305 #[must_use]
317 pub const fn is_windows(&self) -> bool {
318 matches!(self, Self::WINDOWS)
319 }
320
321 #[must_use]
334 pub const fn is_mobile(&self) -> bool {
335 matches!(self, Self::ANDROID | Self::IOS)
336 }
337
338 #[must_use]
352 pub const fn is_desktop(&self) -> bool {
353 matches!(
354 self,
355 Self::LINUX | Self::MACOS | Self::WINDOWS | Self::FREEBSD | Self::HAIKU
356 )
357 }
358
359 #[must_use]
370 pub const fn is_embedded(&self) -> bool {
371 matches!(self, Self::VXWORKS)
372 }
373
374 #[must_use]
386 pub const fn is_microkernel(&self) -> bool {
387 matches!(self, Self::REDOX | Self::FUCHSIA)
388 }
389
390 #[must_use]
402 pub const fn is_posix(&self) -> bool {
403 self.is_unix()
404 }
405
406 #[must_use]
422 pub const fn is_tier1(&self) -> bool {
423 matches!(self, Self::LINUX | Self::MACOS | Self::WINDOWS)
424 }
425
426 #[must_use]
438 pub const fn family(&self) -> &'static str {
439 if self.is_unix() {
440 "unix"
441 } else if self.is_windows() {
442 "windows"
443 } else {
444 "unknown"
445 }
446 }
447}
448
449impl TryFrom<&str> for OsType {
450 type Error = OsTypeError;
451
452 fn try_from(s: &str) -> Result<Self, Self::Error> {
453 s.parse()
454 }
455}
456
457impl FromStr for OsType {
458 type Err = OsTypeError;
459
460 fn from_str(s: &str) -> Result<Self, Self::Err> {
461 match s.to_lowercase().as_str() {
462 "linux" => Ok(Self::LINUX),
463 "macos" | "mac" | "osx" | "darwin" | "os x" => Ok(Self::MACOS),
464 "windows" | "win" => Ok(Self::WINDOWS),
465 "freebsd" => Ok(Self::FREEBSD),
466 "openbsd" => Ok(Self::OPENBSD),
467 "netbsd" => Ok(Self::NETBSD),
468 "dragonfly" | "dragonfly bsd" => Ok(Self::DRAGONFLY),
469 "solaris" => Ok(Self::SOLARIS),
470 "illumos" => Ok(Self::ILLUMOS),
471 "android" => Ok(Self::ANDROID),
472 "ios" | "iphone" => Ok(Self::IOS),
473 "redox" => Ok(Self::REDOX),
474 "fuchsia" => Ok(Self::FUCHSIA),
475 "hermit" => Ok(Self::HERMIT),
476 "vxworks" => Ok(Self::VXWORKS),
477 "aix" => Ok(Self::AIX),
478 "haiku" => Ok(Self::HAIKU),
479 _ => Err(OsTypeError::UnknownOperatingSystem),
480 }
481 }
482}
483
484impl fmt::Display for OsType {
485 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486 write!(f, "{}", self.as_str())
487 }
488}
489
490#[cfg(test)]
491mod tests {
492 use super::*;
493
494 #[test]
495 fn test_as_str() {
496 assert_eq!(OsType::LINUX.as_str(), "linux");
497 assert_eq!(OsType::MACOS.as_str(), "macos");
498 assert_eq!(OsType::WINDOWS.as_str(), "windows");
499 assert_eq!(OsType::FREEBSD.as_str(), "freebsd");
500 assert_eq!(OsType::OPENBSD.as_str(), "openbsd");
501 assert_eq!(OsType::NETBSD.as_str(), "netbsd");
502 assert_eq!(OsType::DRAGONFLY.as_str(), "dragonfly");
503 assert_eq!(OsType::SOLARIS.as_str(), "solaris");
504 assert_eq!(OsType::ILLUMOS.as_str(), "illumos");
505 assert_eq!(OsType::ANDROID.as_str(), "android");
506 assert_eq!(OsType::IOS.as_str(), "ios");
507 assert_eq!(OsType::REDOX.as_str(), "redox");
508 assert_eq!(OsType::FUCHSIA.as_str(), "fuchsia");
509 assert_eq!(OsType::HERMIT.as_str(), "hermit");
510 assert_eq!(OsType::VXWORKS.as_str(), "vxworks");
511 assert_eq!(OsType::AIX.as_str(), "aix");
512 assert_eq!(OsType::HAIKU.as_str(), "haiku");
513 }
514
515 #[test]
516 fn test_is_unix() {
517 assert!(OsType::LINUX.is_unix());
518 assert!(OsType::MACOS.is_unix());
519 assert!(OsType::FREEBSD.is_unix());
520 assert!(OsType::OPENBSD.is_unix());
521 assert!(OsType::NETBSD.is_unix());
522 assert!(OsType::DRAGONFLY.is_unix());
523 assert!(OsType::SOLARIS.is_unix());
524 assert!(OsType::ILLUMOS.is_unix());
525 assert!(OsType::ANDROID.is_unix());
526 assert!(OsType::IOS.is_unix());
527 assert!(OsType::AIX.is_unix());
528 assert!(OsType::HAIKU.is_unix());
529 assert!(!OsType::WINDOWS.is_unix());
530 assert!(!OsType::REDOX.is_unix());
531 assert!(!OsType::FUCHSIA.is_unix());
532 }
533
534 #[test]
535 fn test_is_bsd() {
536 assert!(OsType::FREEBSD.is_bsd());
537 assert!(OsType::OPENBSD.is_bsd());
538 assert!(OsType::NETBSD.is_bsd());
539 assert!(OsType::DRAGONFLY.is_bsd());
540 assert!(OsType::MACOS.is_bsd());
541 assert!(!OsType::LINUX.is_bsd());
542 assert!(!OsType::WINDOWS.is_bsd());
543 }
544
545 #[test]
546 fn test_is_windows() {
547 assert!(OsType::WINDOWS.is_windows());
548 assert!(!OsType::LINUX.is_windows());
549 assert!(!OsType::MACOS.is_windows());
550 }
551
552 #[test]
553 fn test_is_mobile() {
554 assert!(OsType::ANDROID.is_mobile());
555 assert!(OsType::IOS.is_mobile());
556 assert!(!OsType::LINUX.is_mobile());
557 assert!(!OsType::WINDOWS.is_mobile());
558 }
559
560 #[test]
561 fn test_is_desktop() {
562 assert!(OsType::LINUX.is_desktop());
563 assert!(OsType::MACOS.is_desktop());
564 assert!(OsType::WINDOWS.is_desktop());
565 assert!(OsType::FREEBSD.is_desktop());
566 assert!(OsType::HAIKU.is_desktop());
567 assert!(!OsType::ANDROID.is_desktop());
568 assert!(!OsType::IOS.is_desktop());
569 }
570
571 #[test]
572 fn test_is_embedded() {
573 assert!(OsType::VXWORKS.is_embedded());
574 assert!(!OsType::LINUX.is_embedded());
575 }
576
577 #[test]
578 fn test_is_microkernel() {
579 assert!(OsType::REDOX.is_microkernel());
580 assert!(OsType::FUCHSIA.is_microkernel());
581 assert!(!OsType::LINUX.is_microkernel());
582 }
583
584 #[test]
585 fn test_is_posix() {
586 assert!(OsType::LINUX.is_posix());
587 assert!(OsType::MACOS.is_posix());
588 assert!(!OsType::WINDOWS.is_posix());
589 }
590
591 #[test]
592 fn test_is_tier1() {
593 assert!(OsType::LINUX.is_tier1());
594 assert!(OsType::MACOS.is_tier1());
595 assert!(OsType::WINDOWS.is_tier1());
596 assert!(!OsType::FREEBSD.is_tier1());
597 }
598
599 #[test]
600 fn test_family() {
601 assert_eq!(OsType::LINUX.family(), "unix");
602 assert_eq!(OsType::MACOS.family(), "unix");
603 assert_eq!(OsType::WINDOWS.family(), "windows");
604 }
605
606 #[test]
607 fn test_from_str() {
608 assert_eq!("linux".parse::<OsType>().unwrap(), OsType::LINUX);
609 assert_eq!("macos".parse::<OsType>().unwrap(), OsType::MACOS);
610 assert_eq!("mac".parse::<OsType>().unwrap(), OsType::MACOS);
611 assert_eq!("darwin".parse::<OsType>().unwrap(), OsType::MACOS);
612 assert_eq!("windows".parse::<OsType>().unwrap(), OsType::WINDOWS);
613 assert_eq!("freebsd".parse::<OsType>().unwrap(), OsType::FREEBSD);
614 assert_eq!("openbsd".parse::<OsType>().unwrap(), OsType::OPENBSD);
615 assert_eq!("netbsd".parse::<OsType>().unwrap(), OsType::NETBSD);
616 assert_eq!("dragonfly".parse::<OsType>().unwrap(), OsType::DRAGONFLY);
617 assert_eq!("solaris".parse::<OsType>().unwrap(), OsType::SOLARIS);
618 assert_eq!("illumos".parse::<OsType>().unwrap(), OsType::ILLUMOS);
619 assert_eq!("android".parse::<OsType>().unwrap(), OsType::ANDROID);
620 assert_eq!("ios".parse::<OsType>().unwrap(), OsType::IOS);
621 assert_eq!("redox".parse::<OsType>().unwrap(), OsType::REDOX);
622 assert_eq!("fuchsia".parse::<OsType>().unwrap(), OsType::FUCHSIA);
623 assert_eq!("hermit".parse::<OsType>().unwrap(), OsType::HERMIT);
624 assert_eq!("vxworks".parse::<OsType>().unwrap(), OsType::VXWORKS);
625 assert_eq!("aix".parse::<OsType>().unwrap(), OsType::AIX);
626 assert_eq!("haiku".parse::<OsType>().unwrap(), OsType::HAIKU);
627
628 assert_eq!("LINUX".parse::<OsType>().unwrap(), OsType::LINUX);
630 assert_eq!("Windows".parse::<OsType>().unwrap(), OsType::WINDOWS);
631 }
632
633 #[test]
634 fn test_from_str_error() {
635 assert!("unknown".parse::<OsType>().is_err());
636 assert!("".parse::<OsType>().is_err());
637 }
638
639 #[test]
640 fn test_display() {
641 assert_eq!(format!("{}", OsType::LINUX), "linux");
642 assert_eq!(format!("{}", OsType::MACOS), "macos");
643 assert_eq!(format!("{}", OsType::WINDOWS), "windows");
644 }
645
646 #[test]
647 fn test_current() {
648 let _os = OsType::current();
650 }
651
652 #[test]
653 fn test_copy() {
654 let os = OsType::LINUX;
655 let os2 = os;
656 assert_eq!(os, os2);
657 }
658
659 #[test]
660 fn test_clone() {
661 let os = OsType::LINUX;
662 let os2 = os.clone();
663 assert_eq!(os, os2);
664 }
665
666 #[test]
667 fn test_equality() {
668 assert_eq!(OsType::LINUX, OsType::LINUX);
669 assert_ne!(OsType::LINUX, OsType::WINDOWS);
670 }
671
672 #[test]
673 fn test_ordering() {
674 assert!(OsType::LINUX < OsType::ANDROID); assert!(OsType::LINUX < OsType::FREEBSD); }
677}