1#![cfg_attr(not(test), no_std)]
2#![allow(
3 clippy::upper_case_acronyms,
4 clippy::manual_non_exhaustive,
5 clippy::match_like_matches_macro
6)] use core::fmt::Formatter;
9use core::{fmt::Display, str::FromStr};
10
11#[derive(Debug, Clone, Copy)]
15pub struct UnknownError;
16
17impl Display for UnknownError {
18 fn fmt(&self, fmt: &mut Formatter) -> core::fmt::Result {
19 fmt.write_str("Unknown or invalid target or component")
20 }
21}
22
23#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
26#[non_exhaustive]
27pub enum Architecture {
28 Unknown,
29 X86_16(u8),
30 X86_32(u8),
31 X86_64 { microarch: u8 },
32 Arm,
33 ArmBe,
34 Aarch64,
35 Aarch64Be,
36 Aarch64_32,
37 Mips,
38 MipsLE,
39 Mips64,
40 Mips64LE,
41 PowerPC32,
42 PowerPC64,
43 PowerPC64le,
44 RiscV32,
45 RiscV64,
46 Sparc,
47 SparcV9,
48 SparcEL,
49 Wasm32,
50 Wasm64,
51 Wc65c816,
52 M6502,
53 M65C02,
54 SPC700,
55 Clever,
56 HoleyBytes,
57 Skyarch,
58}
59
60impl FromStr for Architecture {
61 type Err = UnknownError;
62
63 fn from_str(s: &str) -> Result<Self, Self::Err> {
64 Ok(match s {
65 "i86" | "i8086" | "i086" => Self::X86_16(0),
66 "i186" => Self::X86_16(1),
67 "i286" => Self::X86_16(2),
68 "i386" => Self::X86_32(3),
69 "i486" => Self::X86_32(4),
70 "i586" => Self::X86_32(5),
71 "i686" => Self::X86_32(6),
72 "i786" => Self::X86_32(7),
73 "amd64" | "x86_64" | "x86_64h" | "x64" => Self::X86_64 { microarch: 1 },
74 "x86_64v2" => Self::X86_64 { microarch: 2 },
75 "x86_64v3" => Self::X86_64 { microarch: 3 },
76 "x86_64v4" => Self::X86_64 { microarch: 4 },
77 "armeb" => Self::ArmBe,
78 "arm" => Self::Arm,
79 "aarch64" | "arm64" | "arm64e" => Self::Aarch64,
80 "aarch64_be" | "arm64_be" => Self::Aarch64Be,
81 "aarch64_32" | "arm64_32" => Self::Aarch64_32,
82 s if s.starts_with("clever") => Self::Clever,
83 "powerpc" | "powerpcspe" | "ppc" | "ppc32" => Self::PowerPC32,
84 "powerpc64" | "ppu" | "ppc64" => Self::PowerPC64,
85 "powerpc64le" | "ppc64le" => Self::PowerPC64le,
86 "mips" | "mipseb" | "mipsallegrex" | "mipsisa32r6" | "mipsr6" => Self::Mips,
87 "mipsel" | "mipsallegrexel" | "mipsisa32r6el" | "mipsr6el" => Self::MipsLE,
88 "mips64" | "mips64eb" | "mipsn32" | "mipsisa64r6" | "mips64r6" | "mipsn32r6" => {
89 Self::Mips64
90 }
91 "mips64el" | "mipsn32el" | "mipsisa64r6el" | "mips64r6el" | "mipsn32r6el" => {
92 Self::Mips64LE
93 }
94 "sparc" => Self::Sparc,
95 "sparcel" => Self::SparcEL,
96 "sparcv9" | "sparc64" => Self::SparcV9,
97 "riscv32" => Self::RiscV32,
98 "riscv64" => Self::RiscV64,
99 "wc65c816" | "65816" | "w65c816" | "65c816" | "w65" => Self::Wc65c816,
100 "6502" | "6502x" | "6502X" => Self::M6502,
101 "65c02" | "65C02" => Self::M65C02,
102 "wasm32" => Self::Wasm32,
103 "wasm64" => Self::Wasm64,
104
105 "spc700" | "spc" => Self::SPC700,
106 "holeybytes" | "hbvm" | "hb" => Self::HoleyBytes,
107 "skyarch" => Self::Skyarch,
108
109 _ => return Err(UnknownError),
110 })
111 }
112}
113
114impl Display for Architecture {
115 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116 self.canonical_name().fmt(f)
117 }
118}
119
120impl Architecture {
121 pub fn parse(st: &str) -> Self {
126 Self::from_str(st).unwrap_or(Architecture::Unknown)
127 }
128
129 pub fn canonical_name(&self) -> &'static str {
134 match self {
135 Architecture::Unknown => "unknown",
136 Architecture::X86_16(0) => "i86",
137 Architecture::X86_16(1) => "i186",
138 Architecture::X86_16(2..) => "i286",
139 Architecture::X86_32(..=3) => "i386",
140 Architecture::X86_32(4) => "i486",
141 Architecture::X86_32(5) => "i586",
142 Architecture::X86_32(6) => "i686",
143 Architecture::X86_32(7..) => "i786",
144 Architecture::X86_64 {
145 microarch: 0 | 1 | 5..,
146 } => "x86_64",
147 Architecture::X86_64 { microarch: 2 } => "x86_64v2",
148 Architecture::X86_64 { microarch: 3 } => "x86_64v3",
149 Architecture::X86_64 { microarch: 4 } => "x86_64v4",
150 Architecture::Arm => "arm",
151 Architecture::ArmBe => "armeb",
152 Architecture::Aarch64 => "aarch64",
153 Architecture::Aarch64Be => "aarch64_be",
154 Architecture::Aarch64_32 => "aarch64_32",
155 Architecture::Mips => "mips",
156 Architecture::Mips64 => "mips64",
157 Architecture::PowerPC32 => "powerpc",
158 Architecture::PowerPC64 => "powerpc64",
159 Architecture::PowerPC64le => "powerpc64le",
160 Architecture::RiscV32 => "riscv32",
161 Architecture::RiscV64 => "riscv64",
162 Architecture::Sparc => "sparc",
163 Architecture::SparcV9 => "sparcv9",
164 Architecture::SparcEL => "sparcel",
165 Architecture::Wasm32 => "wasm32",
166 Architecture::Wasm64 => "wasm64",
167 Architecture::Wc65c816 => "w65",
168 Architecture::MipsLE => "mipsel",
169 Architecture::Mips64LE => "mips64el",
170 Architecture::M6502 => "6502",
171 Architecture::M65C02 => "6502",
172 Architecture::SPC700 => "spc700",
173 Architecture::Clever => "clever",
174 Architecture::HoleyBytes => "holeybytes",
175 Architecture::Skyarch => "skyarch",
176 }
177 }
178}
179
180#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
184#[non_exhaustive]
185pub enum Vendor {
186 Unknown = 0,
187 Apple = 1,
188 PC = 2,
189 SCEI = 3,
190 Freescale = 4,
191 IBM = 5,
192 ImaginationTechnologies = 6,
193 MipsTechnologies = 7,
194 NVIDIA = 8,
195 CSR = 9,
196 Myriad = 10,
197 AMD = 11,
198 Mesa = 12,
199 SUSE = 13,
200 OpenEmbedded = 14,
201 WDC = 15,
202}
203
204impl FromStr for Vendor {
205 type Err = core::convert::Infallible;
206
207 fn from_str(s: &str) -> Result<Self, Self::Err> {
208 Ok(match s {
209 "apple" => Self::Apple,
210 "pc" => Self::PC,
211 "scei" => Self::SCEI,
214 "fsl" => Self::Freescale,
215 "img" => Self::ImaginationTechnologies,
216 "ibm" => Self::IBM,
217 "mti" => Self::MipsTechnologies,
218 "nvidia" => Self::NVIDIA,
219 "csr" => Self::CSR,
220 "myriad" => Self::Myriad,
221 "amd" => Self::AMD,
222 "mesa" => Self::Mesa,
223 "suse" => Self::SUSE,
224 "oe" => Self::OpenEmbedded,
225 "wdc" => Self::WDC,
226 _ => Self::Unknown,
227 })
228 }
229}
230
231impl Display for Vendor {
232 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
233 self.canonical_name().fmt(f)
234 }
235}
236
237impl Vendor {
238 pub fn parse(s: &str) -> Self {
242 Self::from_str(s).unwrap()
243 }
244
245 pub fn canonical_name(&self) -> &'static str {
250 match self {
251 Vendor::Apple => "apple",
252 Vendor::PC => "pc",
253 Vendor::Unknown => "unknown",
254 Vendor::SCEI => "scei",
255 Vendor::Freescale => "fsl",
256 Vendor::IBM => "ibm",
257 Vendor::ImaginationTechnologies => "img",
258 Vendor::MipsTechnologies => "mti",
259 Vendor::NVIDIA => "nvidia",
260 Vendor::CSR => "csr",
261 Vendor::Myriad => "myriad",
262 Vendor::AMD => "amd",
263 Vendor::Mesa => "mesa",
264 Vendor::SUSE => "suse",
265 Vendor::OpenEmbedded => "oe",
266 Vendor::WDC => "wdc",
267 }
268 }
269}
270
271#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
274#[non_exhaustive]
275pub enum OS {
276 Unknown = 0,
277
278 Ananas = 1,
279 CloudABI = 2,
280 Darwin = 3,
281 DragonFly = 4,
282 FreeBSD = 5,
283 Fuchsia = 6,
284 IOS = 7,
285 KFreeBSD = 8,
286 Linux = 9,
287 Lv2 = 10,
288 MacOSX = 11,
289 NetBSD = 12,
290 OpenBSD = 13,
291 Solaris = 14,
292 Win32 = 15,
293 ZOS = 16,
294 Haiku = 17,
295 Minix = 18,
296 RTEMS = 19,
297 NaCl = 20,
298 AIX = 21,
299 CUDA = 22,
300 NVCL = 23,
301 AMDHSA = 24,
302 PS4 = 25,
303 ELFIAMCU = 26,
304 TvOS = 27,
305 WatchOS = 28,
306 Mesa3D = 29,
307 Contiki = 30,
308 AMDPAL = 31,
309 HermitCore = 32,
310 Hurd = 33,
311 WASI = 34,
312 Emscripten = 35,
313 SNES = 37, NES = 38, None = 39, CleverOS = 40,
317 AbleOS = 41,
318 Lilium = 42,
319}
320
321impl FromStr for OS {
322 type Err = UnknownError;
323
324 fn from_str(s: &str) -> Result<Self, Self::Err> {
325 Ok(match s {
326 x if x.starts_with("ananas") => Self::Ananas,
327 x if x.starts_with("cloudabi") => Self::CloudABI,
328 x if x.starts_with("darwin") => Self::Darwin,
329 x if x.starts_with("dragonfly") => Self::DragonFly,
330 x if x.starts_with("freebsd") => Self::FreeBSD,
331 x if x.starts_with("fuchsia") => Self::Fuchsia,
332 x if x.starts_with("ios") => Self::IOS,
333 x if x.starts_with("kfreebsd") => Self::KFreeBSD,
334 x if x.starts_with("linux") => Self::Linux,
335 x if x.starts_with("lv2") => Self::Lv2,
336 x if x.starts_with("macos") => Self::MacOSX,
337 x if x.starts_with("netbsd") => Self::NetBSD,
338 x if x.starts_with("openbsd") => Self::OpenBSD,
339 x if x.starts_with("solaris") => Self::Solaris,
340 x if x.starts_with("win32") | x.starts_with("windows") => Self::Win32,
341 x if x.starts_with("zos") => Self::ZOS,
342 x if x.starts_with("haiku") => Self::Haiku,
343 x if x.starts_with("minix") => Self::Minix,
344 x if x.starts_with("rtems") => Self::RTEMS,
345 x if x.starts_with("nacl") => Self::NaCl,
346 x if x.starts_with("aix") => Self::AIX,
347 x if x.starts_with("cuda") => Self::CUDA,
348 x if x.starts_with("nvcl") => Self::NVCL,
349 x if x.starts_with("amdhsa") => Self::AMDHSA,
350 x if x.starts_with("ps4") => Self::PS4,
351 x if x.starts_with("elfiamcu") => Self::ELFIAMCU,
352 x if x.starts_with("tvos") => Self::TvOS,
353 x if x.starts_with("watchos") => Self::WatchOS,
354 x if x.starts_with("mesa3d") => Self::Mesa3D,
355 x if x.starts_with("contiki") => Self::Contiki,
356 x if x.starts_with("amdpal") => Self::AMDPAL,
357 x if x.starts_with("hermit") => Self::HermitCore,
358 x if x.starts_with("hurd") => Self::Hurd,
359 x if x.starts_with("wasi") => Self::WASI,
360 x if x.starts_with("emscripten") => Self::Emscripten,
361 x if x.starts_with("snes") => Self::SNES,
362 x if x.starts_with("nes") => Self::NES,
363 x if x.starts_with("cleveros") => Self::CleverOS,
364 x if x.starts_with("ableos") => Self::AbleOS,
365 x if x.starts_with("lilium") => Self::Lilium,
366 "none" => Self::None,
367
368 _ => return Err(UnknownError),
369 })
370 }
371}
372
373impl Display for OS {
374 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
375 self.canonical_name().fmt(f)
376 }
377}
378
379impl OS {
380 pub fn parse(s: &str) -> Self {
383 Self::from_str(s).unwrap_or(Self::Unknown)
384 }
385
386 pub fn canonical_name(&self) -> &'static str {
391 match self {
392 OS::Unknown => "unknown",
393 OS::Ananas => "ananas",
394 OS::CloudABI => "cloudabi",
395 OS::Darwin => "darwin",
396 OS::DragonFly => "dragonfly",
397 OS::FreeBSD => "freebsd",
398 OS::Fuchsia => "fuchsia",
399 OS::IOS => "ios",
400 OS::KFreeBSD => "kfreebsd",
401 OS::Linux => "linux",
402 OS::Lv2 => "lv2",
403 OS::MacOSX => "macos",
404 OS::NetBSD => "netbsd",
405 OS::OpenBSD => "openbsd",
406 OS::Solaris => "solaris",
407 OS::Win32 => "windows",
408 OS::ZOS => "zos",
409 OS::Haiku => "haiku",
410 OS::Minix => "minix",
411 OS::RTEMS => "rtems",
412 OS::NaCl => "nacl",
413 OS::AIX => "aix",
414 OS::CUDA => "cuda",
415 OS::NVCL => "nvcl",
416 OS::AMDHSA => "amdhsa",
417 OS::PS4 => "ps4",
418 OS::ELFIAMCU => "elfiamcu",
419 OS::TvOS => "tvos",
420 OS::WatchOS => "watchos",
421 OS::Mesa3D => "mesa3d",
422 OS::Contiki => "contiki",
423 OS::AMDPAL => "amdpal",
424 OS::HermitCore => "hermit",
425 OS::Hurd => "hurd",
426 OS::WASI => "wasi",
427 OS::Emscripten => "emscripten",
428 OS::SNES => "snes",
429 OS::NES => "nes",
430 OS::None => "none",
431 OS::CleverOS => "cleveros",
432 OS::AbleOS => "ableos",
433 OS::Lilium => "lilium",
434 }
435 }
436}
437
438#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
441pub enum Environment {
442 Unknown = 0,
443 GNU = 1,
444 GNUABIN32 = 2,
445 GNUABI64 = 3,
446 GNUEABI = 4,
447 GNUEABIHF = 5,
448 GNUX32 = 6,
449 CODE16 = 7,
450 EABI = 8,
451 EABIHF = 9,
452 Android = 10,
453 Musl = 11,
454 MuslEABI = 12,
455 MuslEABIHF = 13,
456
457 MSVC = 15,
458 Itanium = 16,
459 Cygnus = 17,
460 CoreCLR = 18,
461 Simulator = 19,
462 MacABI = 20,
463
464 Standard = 23,
465 Kernel = 24,
466}
467
468impl FromStr for Environment {
469 type Err = UnknownError;
470
471 fn from_str(s: &str) -> Result<Self, Self::Err> {
472 Ok(match s {
473 x if x.starts_with("eabihf") => Self::EABIHF,
474 x if x.starts_with("eabi") => Self::EABI,
475 x if x.starts_with("gnuabin32") => Self::GNUABIN32,
476 x if x.starts_with("gnuabi64") => Self::GNUABI64,
477 x if x.starts_with("gnueabihf") => Self::GNUEABIHF,
478 x if x.starts_with("gnueabi") => Self::GNUEABI,
479 x if x.starts_with("gnux32") => Self::GNUX32,
480 x if x.starts_with("gnu") => Self::GNU,
481 x if x.starts_with("code16") => Self::CODE16,
482 x if x.starts_with("android") => Self::Android,
483 x if x.starts_with("musleabihf") => Self::MuslEABIHF,
484 x if x.starts_with("musleabi") => Self::MuslEABI,
485 x if x.starts_with("musl") => Self::Musl,
486 x if x.starts_with("msvc") => Self::MSVC,
487 x if x.starts_with("itanium") => Self::Itanium,
488 x if x.starts_with("cygnus") => Self::Cygnus,
489 x if x.starts_with("coreclr") => Self::CoreCLR,
490 x if x.starts_with("simulator") => Self::Simulator,
491 x if x.starts_with("macabi") => Self::MacABI,
492 x if x.starts_with("std") => Self::Standard,
493 x if x.starts_with("kernel") => Self::Kernel,
494 _ => return Err(UnknownError),
495 })
496 }
497}
498
499impl Display for Environment {
500 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
501 self.canonical_name().fmt(f)
502 }
503}
504
505impl Environment {
506 pub fn parse(s: &str) -> Self {
509 Self::from_str(s).unwrap_or(Self::Unknown)
510 }
511
512 pub fn canonical_name(&self) -> &'static str {
517 match self {
518 Environment::Unknown => "unknown",
519 Environment::GNU => "gnu",
520 Environment::GNUABIN32 => "gnuabin32",
521 Environment::GNUABI64 => "gnuabi64",
522 Environment::GNUEABI => "gnueabi",
523 Environment::GNUEABIHF => "gnueabihf",
524 Environment::GNUX32 => "gnux32",
525 Environment::CODE16 => "code16",
526 Environment::EABI => "eabi",
527 Environment::EABIHF => "eabihf",
528 Environment::Android => "android",
529 Environment::Musl => "musl",
530 Environment::MuslEABI => "musleabi",
531 Environment::MuslEABIHF => "musleabihf",
532 Environment::MSVC => "msvc",
533 Environment::Itanium => "itanium",
534 Environment::Cygnus => "cygnus",
535 Environment::CoreCLR => "coreclr",
536 Environment::Simulator => "simulator",
537 Environment::MacABI => "macabi",
538 Environment::Standard => "std",
539 Environment::Kernel => "kernel",
540 }
541 }
542}
543
544#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
547#[non_exhaustive]
548pub enum ObjectFormat {
549 Unknown = 0,
550 XCoff = 1,
551 Coff = 2,
552 Elf = 3,
553 Goff = 4,
554 MachO = 5,
555 Wasm = 6,
556
557 Xo65 = 7,
558 O65 = 8,
559 WlaObj = 9,
560}
561
562impl FromStr for ObjectFormat {
563 type Err = UnknownError;
564
565 fn from_str(s: &str) -> Result<Self, Self::Err> {
566 Ok(match s {
567 x if x.ends_with("xcoff") => Self::XCoff,
568 x if x.ends_with("coff") => Self::Coff,
569 x if x.ends_with("elf") => Self::Elf,
570 x if x.ends_with("goff") => Self::Goff,
571 x if x.ends_with("macho") => Self::MachO,
572 x if x.ends_with("wasm") => Self::Wasm,
573 x if x.ends_with("xo65") => Self::Xo65,
574 x if x.ends_with("o65") => Self::O65,
575 x if x.ends_with("wlaobj") => Self::WlaObj,
576 x if x.ends_with("wla") => Self::WlaObj,
577 _ => return Err(UnknownError),
578 })
579 }
580}
581
582impl Display for ObjectFormat {
583 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
584 self.canonical_name().fmt(f)
585 }
586}
587
588impl ObjectFormat {
589 pub fn parse(s: &str) -> Self {
592 Self::from_str(s).unwrap_or(Self::Unknown)
593 }
594
595 pub fn canonical_name(&self) -> &'static str {
600 match self {
601 ObjectFormat::Unknown => "unknown",
602 ObjectFormat::XCoff => "xcoff",
603 ObjectFormat::Coff => "coff",
604 ObjectFormat::Elf => "elf",
605 ObjectFormat::Goff => "goff",
606 ObjectFormat::MachO => "macho",
607 ObjectFormat::Wasm => "wasm",
608 ObjectFormat::Xo65 => "xo65",
609 ObjectFormat::O65 => "o65",
610 ObjectFormat::WlaObj => "wlaobj",
611 }
612 }
613}
614
615#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
616pub struct System {
617 os: Option<OS>,
618 env: Option<Environment>,
619 objfmt: Option<ObjectFormat>,
620}
621
622impl System {
623 pub const fn from_pieces(
628 os: Option<OS>,
629 env: Option<Environment>,
630 objfmt: Option<ObjectFormat>,
631 ) -> Self {
632 assert!(os.is_some() || env.is_some() || objfmt.is_some());
633
634 Self { os, env, objfmt }
635 }
636
637 pub const fn from_os(os: OS) -> Self {
638 Self {
639 os: Some(os),
640 env: None,
641 objfmt: None,
642 }
643 }
644
645 pub const fn from_os_env(os: OS, env: Environment) -> Self {
646 Self {
647 os: Some(os),
648 env: Some(env),
649 objfmt: None,
650 }
651 }
652
653 pub const fn from_env(env: Environment) -> Self {
654 Self {
655 os: None,
656 env: Some(env),
657 objfmt: None,
658 }
659 }
660
661 pub const fn from_objfmt(objfmt: ObjectFormat) -> Self {
662 Self {
663 os: None,
664 env: None,
665 objfmt: Some(objfmt),
666 }
667 }
668
669 pub const fn os(&self) -> Option<OS> {
670 self.os
671 }
672
673 pub const fn env(&self) -> Option<Environment> {
674 self.env
675 }
676
677 pub const fn object_format(&self) -> Option<ObjectFormat> {
678 self.objfmt
679 }
680}
681
682impl core::fmt::Display for System {
683 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
684 let mut sep = "";
685 if let Some(os) = self.os {
686 os.fmt(f)?;
687 sep = "-";
688 }
689
690 if let Some(env) = self.env {
691 f.write_str(sep)?;
692 sep = "";
693 env.fmt(f)?;
694 }
695
696 if let Some(objfmt) = self.objfmt {
697 f.write_str(sep)?;
698 objfmt.fmt(f)?;
699 }
700
701 Ok(())
702 }
703}
704
705impl FromStr for System {
706 type Err = UnknownError;
707
708 fn from_str(sys: &str) -> Result<Self, Self::Err> {
709 if let Some((os, senv)) = sys.split_once('-') {
710 let os = os.parse::<OS>()?;
711
712 let env = senv.parse::<Environment>();
713 let objfmt = senv.parse::<ObjectFormat>();
714
715 env.map(|_| ()).or_else(|_| objfmt.map(|_| ()))?;
716
717 Ok(Self {
718 os: Some(os),
719 env: env.ok(),
720 objfmt: objfmt.ok(),
721 })
722 } else if let Ok(os) = sys.parse::<OS>() {
723 Ok(Self {
724 os: Some(os),
725 env: None,
726 objfmt: None,
727 })
728 } else {
729 let env = sys.parse::<Environment>();
730 let objfmt = sys.parse::<ObjectFormat>();
731
732 env.map(|_| ()).or_else(|_| objfmt.map(|_| ()))?;
733
734 Ok(Self {
735 os: None,
736 env: env.ok(),
737 objfmt: objfmt.ok(),
738 })
739 }
740 }
741}