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