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))]
58#[non_exhaustive]
59pub enum OsTypeError {
60 UnknownOperatingSystem,
67}
68
69impl fmt::Display for OsTypeError {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 match self {
72 Self::UnknownOperatingSystem => write!(f, "unknown operating system"),
73 }
74 }
75}
76
77#[cfg(feature = "std")]
78impl std::error::Error for OsTypeError {}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
110#[non_exhaustive]
111pub enum OsType {
112 LINUX,
114 MACOS,
116 WINDOWS,
118 FREEBSD,
120 OPENBSD,
122 NETBSD,
124 DRAGONFLY,
126 SOLARIS,
128 ILLUMOS,
130 ANDROID,
132 IOS,
134 REDOX,
136 FUCHSIA,
138 HERMIT,
140 VXWORKS,
142 AIX,
144 HAIKU,
146}
147
148impl OsType {
149 #[must_use]
164 pub const fn current() -> Self {
165 #[cfg(target_os = "linux")]
166 return Self::LINUX;
167 #[cfg(target_os = "macos")]
168 return Self::MACOS;
169 #[cfg(target_os = "windows")]
170 return Self::WINDOWS;
171 #[cfg(target_os = "freebsd")]
172 return Self::FREEBSD;
173 #[cfg(target_os = "openbsd")]
174 return Self::OPENBSD;
175 #[cfg(target_os = "netbsd")]
176 return Self::NETBSD;
177 #[cfg(target_os = "dragonfly")]
178 return Self::DRAGONFLY;
179 #[cfg(target_os = "solaris")]
180 return Self::SOLARIS;
181 #[cfg(target_os = "illumos")]
182 return Self::ILLUMOS;
183 #[cfg(target_os = "android")]
184 return Self::ANDROID;
185 #[cfg(target_os = "ios")]
186 return Self::IOS;
187 #[cfg(target_os = "redox")]
188 return Self::REDOX;
189 #[cfg(target_os = "fuchsia")]
190 return Self::FUCHSIA;
191 #[cfg(target_os = "hermit")]
192 return Self::HERMIT;
193 #[cfg(target_os = "vxworks")]
194 return Self::VXWORKS;
195 #[cfg(target_os = "aix")]
196 return Self::AIX;
197 #[cfg(target_os = "haiku")]
198 return Self::HAIKU;
199 #[cfg(not(any(
200 target_os = "linux",
201 target_os = "macos",
202 target_os = "windows",
203 target_os = "freebsd",
204 target_os = "openbsd",
205 target_os = "netbsd",
206 target_os = "dragonfly",
207 target_os = "solaris",
208 target_os = "illumos",
209 target_os = "android",
210 target_os = "ios",
211 target_os = "redox",
212 target_os = "fuchsia",
213 target_os = "hermit",
214 target_os = "vxworks",
215 target_os = "aix",
216 target_os = "haiku",
217 )))]
218 {
219 panic!("unsupported target operating system")
220 }
221 }
222
223 #[must_use]
235 pub const fn as_str(&self) -> &'static str {
236 match self {
237 Self::LINUX => "linux",
238 Self::MACOS => "macos",
239 Self::WINDOWS => "windows",
240 Self::FREEBSD => "freebsd",
241 Self::OPENBSD => "openbsd",
242 Self::NETBSD => "netbsd",
243 Self::DRAGONFLY => "dragonfly",
244 Self::SOLARIS => "solaris",
245 Self::ILLUMOS => "illumos",
246 Self::ANDROID => "android",
247 Self::IOS => "ios",
248 Self::REDOX => "redox",
249 Self::FUCHSIA => "fuchsia",
250 Self::HERMIT => "hermit",
251 Self::VXWORKS => "vxworks",
252 Self::AIX => "aix",
253 Self::HAIKU => "haiku",
254 }
255 }
256
257 #[must_use]
270 pub const fn is_unix(&self) -> bool {
271 matches!(
272 self,
273 Self::LINUX
274 | Self::MACOS
275 | Self::FREEBSD
276 | Self::OPENBSD
277 | Self::NETBSD
278 | Self::DRAGONFLY
279 | Self::SOLARIS
280 | Self::ILLUMOS
281 | Self::ANDROID
282 | Self::IOS
283 | Self::AIX
284 | Self::HAIKU
285 )
286 }
287
288 #[must_use]
304 pub const fn is_bsd(&self) -> bool {
305 matches!(
306 self,
307 Self::FREEBSD | Self::OPENBSD | Self::NETBSD | Self::DRAGONFLY | Self::MACOS
308 )
309 }
310
311 #[must_use]
323 pub const fn is_windows(&self) -> bool {
324 matches!(self, Self::WINDOWS)
325 }
326
327 #[must_use]
340 pub const fn is_mobile(&self) -> bool {
341 matches!(self, Self::ANDROID | Self::IOS)
342 }
343
344 #[must_use]
358 pub const fn is_desktop(&self) -> bool {
359 matches!(
360 self,
361 Self::LINUX | Self::MACOS | Self::WINDOWS | Self::FREEBSD | Self::HAIKU
362 )
363 }
364
365 #[must_use]
376 pub const fn is_embedded(&self) -> bool {
377 matches!(self, Self::VXWORKS)
378 }
379
380 #[must_use]
392 pub const fn is_microkernel(&self) -> bool {
393 matches!(self, Self::REDOX | Self::FUCHSIA)
394 }
395
396 #[must_use]
408 pub const fn is_posix(&self) -> bool {
409 self.is_unix()
410 }
411
412 #[must_use]
428 pub const fn is_tier1(&self) -> bool {
429 matches!(self, Self::LINUX | Self::MACOS | Self::WINDOWS)
430 }
431
432 #[must_use]
444 pub const fn family(&self) -> &'static str {
445 if self.is_unix() {
446 "unix"
447 } else if self.is_windows() {
448 "windows"
449 } else {
450 "unknown"
451 }
452 }
453}
454
455impl TryFrom<&str> for OsType {
456 type Error = OsTypeError;
457
458 fn try_from(s: &str) -> Result<Self, Self::Error> {
459 s.parse()
460 }
461}
462
463impl FromStr for OsType {
464 type Err = OsTypeError;
465
466 fn from_str(s: &str) -> Result<Self, Self::Err> {
467 match s.to_lowercase().as_str() {
468 "linux" => Ok(Self::LINUX),
469 "macos" | "mac" | "osx" | "darwin" | "os x" => Ok(Self::MACOS),
470 "windows" | "win" => Ok(Self::WINDOWS),
471 "freebsd" => Ok(Self::FREEBSD),
472 "openbsd" => Ok(Self::OPENBSD),
473 "netbsd" => Ok(Self::NETBSD),
474 "dragonfly" | "dragonfly bsd" => Ok(Self::DRAGONFLY),
475 "solaris" => Ok(Self::SOLARIS),
476 "illumos" => Ok(Self::ILLUMOS),
477 "android" => Ok(Self::ANDROID),
478 "ios" | "iphone" => Ok(Self::IOS),
479 "redox" => Ok(Self::REDOX),
480 "fuchsia" => Ok(Self::FUCHSIA),
481 "hermit" => Ok(Self::HERMIT),
482 "vxworks" => Ok(Self::VXWORKS),
483 "aix" => Ok(Self::AIX),
484 "haiku" => Ok(Self::HAIKU),
485 _ => Err(OsTypeError::UnknownOperatingSystem),
486 }
487 }
488}
489
490impl fmt::Display for OsType {
491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492 write!(f, "{}", self.as_str())
493 }
494}
495
496#[cfg(test)]
497mod tests {
498 use super::*;
499
500 #[test]
501 fn test_as_str() {
502 assert_eq!(OsType::LINUX.as_str(), "linux");
503 assert_eq!(OsType::MACOS.as_str(), "macos");
504 assert_eq!(OsType::WINDOWS.as_str(), "windows");
505 assert_eq!(OsType::FREEBSD.as_str(), "freebsd");
506 assert_eq!(OsType::OPENBSD.as_str(), "openbsd");
507 assert_eq!(OsType::NETBSD.as_str(), "netbsd");
508 assert_eq!(OsType::DRAGONFLY.as_str(), "dragonfly");
509 assert_eq!(OsType::SOLARIS.as_str(), "solaris");
510 assert_eq!(OsType::ILLUMOS.as_str(), "illumos");
511 assert_eq!(OsType::ANDROID.as_str(), "android");
512 assert_eq!(OsType::IOS.as_str(), "ios");
513 assert_eq!(OsType::REDOX.as_str(), "redox");
514 assert_eq!(OsType::FUCHSIA.as_str(), "fuchsia");
515 assert_eq!(OsType::HERMIT.as_str(), "hermit");
516 assert_eq!(OsType::VXWORKS.as_str(), "vxworks");
517 assert_eq!(OsType::AIX.as_str(), "aix");
518 assert_eq!(OsType::HAIKU.as_str(), "haiku");
519 }
520
521 #[test]
522 fn test_is_unix() {
523 assert!(OsType::LINUX.is_unix());
524 assert!(OsType::MACOS.is_unix());
525 assert!(OsType::FREEBSD.is_unix());
526 assert!(OsType::OPENBSD.is_unix());
527 assert!(OsType::NETBSD.is_unix());
528 assert!(OsType::DRAGONFLY.is_unix());
529 assert!(OsType::SOLARIS.is_unix());
530 assert!(OsType::ILLUMOS.is_unix());
531 assert!(OsType::ANDROID.is_unix());
532 assert!(OsType::IOS.is_unix());
533 assert!(OsType::AIX.is_unix());
534 assert!(OsType::HAIKU.is_unix());
535 assert!(!OsType::WINDOWS.is_unix());
536 assert!(!OsType::REDOX.is_unix());
537 assert!(!OsType::FUCHSIA.is_unix());
538 }
539
540 #[test]
541 fn test_is_bsd() {
542 assert!(OsType::FREEBSD.is_bsd());
543 assert!(OsType::OPENBSD.is_bsd());
544 assert!(OsType::NETBSD.is_bsd());
545 assert!(OsType::DRAGONFLY.is_bsd());
546 assert!(OsType::MACOS.is_bsd());
547 assert!(!OsType::LINUX.is_bsd());
548 assert!(!OsType::WINDOWS.is_bsd());
549 }
550
551 #[test]
552 fn test_is_windows() {
553 assert!(OsType::WINDOWS.is_windows());
554 assert!(!OsType::LINUX.is_windows());
555 assert!(!OsType::MACOS.is_windows());
556 }
557
558 #[test]
559 fn test_is_mobile() {
560 assert!(OsType::ANDROID.is_mobile());
561 assert!(OsType::IOS.is_mobile());
562 assert!(!OsType::LINUX.is_mobile());
563 assert!(!OsType::WINDOWS.is_mobile());
564 }
565
566 #[test]
567 fn test_is_desktop() {
568 assert!(OsType::LINUX.is_desktop());
569 assert!(OsType::MACOS.is_desktop());
570 assert!(OsType::WINDOWS.is_desktop());
571 assert!(OsType::FREEBSD.is_desktop());
572 assert!(OsType::HAIKU.is_desktop());
573 assert!(!OsType::ANDROID.is_desktop());
574 assert!(!OsType::IOS.is_desktop());
575 }
576
577 #[test]
578 fn test_is_embedded() {
579 assert!(OsType::VXWORKS.is_embedded());
580 assert!(!OsType::LINUX.is_embedded());
581 }
582
583 #[test]
584 fn test_is_microkernel() {
585 assert!(OsType::REDOX.is_microkernel());
586 assert!(OsType::FUCHSIA.is_microkernel());
587 assert!(!OsType::LINUX.is_microkernel());
588 }
589
590 #[test]
591 fn test_is_posix() {
592 assert!(OsType::LINUX.is_posix());
593 assert!(OsType::MACOS.is_posix());
594 assert!(!OsType::WINDOWS.is_posix());
595 }
596
597 #[test]
598 fn test_is_tier1() {
599 assert!(OsType::LINUX.is_tier1());
600 assert!(OsType::MACOS.is_tier1());
601 assert!(OsType::WINDOWS.is_tier1());
602 assert!(!OsType::FREEBSD.is_tier1());
603 }
604
605 #[test]
606 fn test_family() {
607 assert_eq!(OsType::LINUX.family(), "unix");
608 assert_eq!(OsType::MACOS.family(), "unix");
609 assert_eq!(OsType::WINDOWS.family(), "windows");
610 }
611
612 #[test]
613 fn test_from_str() {
614 assert_eq!("linux".parse::<OsType>().unwrap(), OsType::LINUX);
615 assert_eq!("macos".parse::<OsType>().unwrap(), OsType::MACOS);
616 assert_eq!("mac".parse::<OsType>().unwrap(), OsType::MACOS);
617 assert_eq!("darwin".parse::<OsType>().unwrap(), OsType::MACOS);
618 assert_eq!("windows".parse::<OsType>().unwrap(), OsType::WINDOWS);
619 assert_eq!("freebsd".parse::<OsType>().unwrap(), OsType::FREEBSD);
620 assert_eq!("openbsd".parse::<OsType>().unwrap(), OsType::OPENBSD);
621 assert_eq!("netbsd".parse::<OsType>().unwrap(), OsType::NETBSD);
622 assert_eq!("dragonfly".parse::<OsType>().unwrap(), OsType::DRAGONFLY);
623 assert_eq!("solaris".parse::<OsType>().unwrap(), OsType::SOLARIS);
624 assert_eq!("illumos".parse::<OsType>().unwrap(), OsType::ILLUMOS);
625 assert_eq!("android".parse::<OsType>().unwrap(), OsType::ANDROID);
626 assert_eq!("ios".parse::<OsType>().unwrap(), OsType::IOS);
627 assert_eq!("redox".parse::<OsType>().unwrap(), OsType::REDOX);
628 assert_eq!("fuchsia".parse::<OsType>().unwrap(), OsType::FUCHSIA);
629 assert_eq!("hermit".parse::<OsType>().unwrap(), OsType::HERMIT);
630 assert_eq!("vxworks".parse::<OsType>().unwrap(), OsType::VXWORKS);
631 assert_eq!("aix".parse::<OsType>().unwrap(), OsType::AIX);
632 assert_eq!("haiku".parse::<OsType>().unwrap(), OsType::HAIKU);
633
634 assert_eq!("LINUX".parse::<OsType>().unwrap(), OsType::LINUX);
636 assert_eq!("Windows".parse::<OsType>().unwrap(), OsType::WINDOWS);
637 }
638
639 #[test]
640 fn test_from_str_error() {
641 assert!("unknown".parse::<OsType>().is_err());
642 assert!("".parse::<OsType>().is_err());
643 }
644
645 #[test]
646 fn test_display() {
647 assert_eq!(format!("{}", OsType::LINUX), "linux");
648 assert_eq!(format!("{}", OsType::MACOS), "macos");
649 assert_eq!(format!("{}", OsType::WINDOWS), "windows");
650 }
651
652 #[test]
653 fn test_current() {
654 let _os = OsType::current();
656 }
657
658 #[test]
659 fn test_copy() {
660 let os = OsType::LINUX;
661 let os2 = os;
662 assert_eq!(os, os2);
663 }
664
665 #[test]
666 fn test_clone() {
667 let os = OsType::LINUX;
668 let os2 = os.clone();
669 assert_eq!(os, os2);
670 }
671
672 #[test]
673 fn test_equality() {
674 assert_eq!(OsType::LINUX, OsType::LINUX);
675 assert_ne!(OsType::LINUX, OsType::WINDOWS);
676 }
677
678 #[test]
679 fn test_ordering() {
680 assert!(OsType::LINUX < OsType::ANDROID); assert!(OsType::LINUX < OsType::FREEBSD); }
683}