1#![allow(
2 clippy::upper_case_acronyms,
3 clippy::manual_non_exhaustive,
4 clippy::match_like_matches_macro
5)] use alloc::{borrow::ToOwned, string::String};
7use core::fmt::Formatter;
8use core::{fmt::Display, str::FromStr};
9
10#[derive(Debug, Clone, Copy)]
14pub struct UnknownError;
15
16impl Display for UnknownError {
17 fn fmt(&self, fmt: &mut Formatter) -> core::fmt::Result {
18 fmt.write_str("Unknown or invalid target or component")
19 }
20}
21
22#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
25#[repr(u32)]
26pub enum Architecture {
27 Unknown = 0,
28 I86 = 1,
29 I8086 = 2,
30 I086 = 3,
31 I186 = 4,
32 I286 = 5,
33 I386 = 6,
34 I486 = 7,
35 I586 = 8,
36 I686 = 9,
37 I786 = 35,
38 X86_64 = 10,
39 Arm = 11,
40 ArmBe = 12,
41 Aarch64 = 13,
42 Aarch64Be = 14,
43 Aarch64_32 = 15,
44 Mips = 16,
45 MipsLE = 17,
46 Mips64 = 18,
47 Mips64LE = 19,
48 PowerPC32 = 20,
49 PowerPC64 = 21,
50 PowerPC64le = 22,
51 RiscV32 = 23,
52 RiscV64 = 24,
53 Sparc = 25,
54 SparcV9 = 26,
55 SparcEL = 27,
56 Wasm32 = 28,
57 Wasm64 = 29,
58 Wc65c816 = 30,
59 M6502 = 31,
60 M65C02 = 32,
61 SPC700 = 33,
62 Clever = 34,
63 HoleyBytes = 36,
64
65 Null = (-1i32) as u32,
67 #[doc(hidden)]
68 __Nonexhaustive = (-2i32) as u32,
69}
70
71impl FromStr for Architecture {
72 type Err = UnknownError;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 Ok(match s {
76 "i86" => Self::I86,
77 "i8086" => Self::I8086,
78 "i086" => Self::I086,
79 "i186" => Self::I186,
80 "i286" => Self::I286,
81 "i386" => Self::I386,
82 "i486" => Self::I486,
83 "i586" => Self::I586,
84 "i686" => Self::I686,
85 "i786" => Self::I786,
86 "amd64" | "x86_64" | "x86_64h" | "x86_64v2" | "x86_64v3" | "x86_64v4" | "x64" => {
87 Self::X86_64
88 }
89 "armeb" => Self::ArmBe,
90 "arm" => Self::Arm,
91 "aarch64" | "arm64" | "arm64e" => Self::Aarch64,
92 "aarch64_be" | "arm64_be" => Self::Aarch64Be,
93 "aarch64_32" | "arm64_32" => Self::Aarch64_32,
94 s if s.starts_with("clever") => Self::Clever,
95 "powerpc" | "powerpcspe" | "ppc" | "ppc32" => Self::PowerPC32,
96 "powerpc64" | "ppu" | "ppc64" => Self::PowerPC64,
97 "powerpc64le" | "ppc64le" => Self::PowerPC64le,
98 "mips" | "mipseb" | "mipsallegrex" | "mipsisa32r6" | "mipsr6" => Self::Mips,
99 "mipsel" | "mipsallegrexel" | "mipsisa32r6el" | "mipsr6el" => Self::MipsLE,
100 "mips64" | "mips64eb" | "mipsn32" | "mipsisa64r6" | "mips64r6" | "mipsn32r6" => {
101 Self::Mips64
102 }
103 "mips64el" | "mipsn32el" | "mipsisa64r6el" | "mips64r6el" | "mipsn32r6el" => {
104 Self::Mips64LE
105 }
106 "sparc" => Self::Sparc,
107 "sparcel" => Self::SparcEL,
108 "sparcv9" | "sparc64" => Self::SparcV9,
109 "riscv32" => Self::RiscV32,
110 "riscv64" => Self::RiscV64,
111 "wc65c816" | "65816" | "w65c816" | "65c816" | "w65" => Self::Wc65c816,
112 "6502" | "6502x" | "6502X" => Self::M6502,
113 "65c02" | "65C02" => Self::M65C02,
114 "wasm32" => Self::Wasm32,
115 "wasm64" => Self::Wasm64,
116
117 "spc700" | "spc" => Self::SPC700,
118 "holeybytes" | "hbvm" | "hb" => Self::HoleyBytes,
119
120 _ => return Err(UnknownError),
121 })
122 }
123}
124
125impl Display for Architecture {
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 self.canonical_name().fmt(f)
128 }
129}
130
131impl Architecture {
132 pub fn parse(st: &str) -> Self {
137 Self::from_str(st).unwrap_or(Architecture::Unknown)
138 }
139
140 pub fn canonical_name(&self) -> &'static str {
145 match self {
146 Architecture::Unknown => "unknown",
147 Architecture::I86 => "i86",
148 Architecture::I086 => "i086",
149 Architecture::I8086 => "i8086",
150 Architecture::I186 => "i186",
151 Architecture::I286 => "i286",
152 Architecture::I386 => "i386",
153 Architecture::I486 => "i486",
154 Architecture::I586 => "i586",
155 Architecture::I686 => "i686",
156 Architecture::I786 => "i786",
157 Architecture::X86_64 => "x86_64",
158 Architecture::Arm => "arm",
159 Architecture::ArmBe => "armeb",
160 Architecture::Aarch64 => "aarch64",
161 Architecture::Aarch64Be => "aarch64_be",
162 Architecture::Aarch64_32 => "aarch64_32",
163 Architecture::Mips => "mips",
164 Architecture::Mips64 => "mips64",
165 Architecture::PowerPC32 => "powerpc",
166 Architecture::PowerPC64 => "powerpc64",
167 Architecture::PowerPC64le => "powerpc64le",
168 Architecture::RiscV32 => "riscv32",
169 Architecture::RiscV64 => "riscv64",
170 Architecture::Sparc => "sparc",
171 Architecture::SparcV9 => "sparcv9",
172 Architecture::SparcEL => "sparcel",
173 Architecture::Wasm32 => "wasm32",
174 Architecture::Wasm64 => "wasm64",
175 Architecture::Wc65c816 => "w65",
176 Architecture::MipsLE => "mipsel",
177 Architecture::Mips64LE => "mips64el",
178 Architecture::M6502 => "6502",
179 Architecture::M65C02 => "6502",
180 Architecture::SPC700 => "spc700",
181 Architecture::Clever => "clever",
182 Architecture::HoleyBytes => "holeybytes",
183 Architecture::Null => "null",
184 Architecture::__Nonexhaustive => unreachable!(),
185 }
186 }
187
188 pub fn is_x86(&self) -> bool {
189 match self {
190 Architecture::I86
191 | Architecture::I8086
192 | Architecture::I186
193 | Architecture::I286
194 | Architecture::I386
195 | Architecture::I486
196 | Architecture::I586
197 | Architecture::I686
198 | Architecture::I786 => true,
199 _ => false,
200 }
201 }
202}
203
204#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
208#[repr(u32)]
209pub enum Vendor {
210 Unknown = 0,
211 Apple = 1,
212 PC = 2,
213 SCEI = 3,
214 Freescale = 4,
215 IBM = 5,
216 ImaginationTechnologies = 6,
217 MipsTechnologies = 7,
218 NVIDIA = 8,
219 CSR = 9,
220 Myriad = 10,
221 AMD = 11,
222 Mesa = 12,
223 SUSE = 13,
224 OpenEmbedded = 14,
225 WDC = 15,
226
227 Null = (-1i32) as u32,
229 #[doc(hidden)]
230 __Nonexhaustive = (-2i32) as u32,
231}
232
233impl FromStr for Vendor {
234 type Err = core::convert::Infallible;
235
236 fn from_str(s: &str) -> Result<Self, Self::Err> {
237 Ok(match s {
238 "apple" => Self::Apple,
239 "pc" => Self::PC,
240 "scei" => Self::SCEI,
243 "fsl" => Self::Freescale,
244 "img" => Self::ImaginationTechnologies,
245 "ibm" => Self::IBM,
246 "mti" => Self::MipsTechnologies,
247 "nvidia" => Self::NVIDIA,
248 "csr" => Self::CSR,
249 "myriad" => Self::Myriad,
250 "amd" => Self::AMD,
251 "mesa" => Self::Mesa,
252 "suse" => Self::SUSE,
253 "oe" => Self::OpenEmbedded,
254 "wdc" => Self::WDC,
255 _ => Self::Unknown,
256 })
257 }
258}
259
260impl Display for Vendor {
261 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
262 self.canonical_name().fmt(f)
263 }
264}
265
266impl Vendor {
267 pub fn parse(s: &str) -> Self {
271 Self::from_str(s).unwrap()
272 }
273
274 pub fn canonical_name(&self) -> &'static str {
279 match self {
280 Vendor::Apple => "apple",
281 Vendor::PC => "pc",
282 Vendor::Unknown => "unknown",
283 Vendor::SCEI => "scei",
284 Vendor::Freescale => "fsl",
285 Vendor::IBM => "ibm",
286 Vendor::ImaginationTechnologies => "img",
287 Vendor::MipsTechnologies => "mti",
288 Vendor::NVIDIA => "nvidia",
289 Vendor::CSR => "csr",
290 Vendor::Myriad => "myriad",
291 Vendor::AMD => "amd",
292 Vendor::Mesa => "mesa",
293 Vendor::SUSE => "suse",
294 Vendor::OpenEmbedded => "oe",
295 Vendor::WDC => "wdc",
296 Vendor::Null => "null",
297 Vendor::__Nonexhaustive => unreachable!(),
298 }
299 }
300}
301
302#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
305#[repr(u32)]
306pub enum OS {
307 Unknown = 0,
308
309 Ananas = 1,
310 CloudABI = 2,
311 Darwin = 3,
312 DragonFly = 4,
313 FreeBSD = 5,
314 Fuchsia = 6,
315 IOS = 7,
316 KFreeBSD = 8,
317 Linux = 9,
318 Lv2 = 10,
319 MacOSX = 11,
320 NetBSD = 12,
321 OpenBSD = 13,
322 Solaris = 14,
323 Win32 = 15,
324 ZOS = 16,
325 Haiku = 17,
326 Minix = 18,
327 RTEMS = 19,
328 NaCl = 20,
329 AIX = 21,
330 CUDA = 22,
331 NVCL = 23,
332 AMDHSA = 24,
333 PS4 = 25,
334 ELFIAMCU = 26,
335 TvOS = 27,
336 WatchOS = 28,
337 Mesa3D = 29,
338 Contiki = 30,
339 AMDPAL = 31,
340 HermitCore = 32,
341 Hurd = 33,
342 WASI = 34,
343 Emscripten = 35,
344 PhantomOS = 36,
345 SNES = 37, NES = 38, None = 39, CleverOS = 40,
349 AbleOS = 41,
350
351 Null = (-1i32) as u32,
352 #[doc(hidden)]
353 __Nonexhaustive = (-2i32) as u32,
354}
355
356impl FromStr for OS {
357 type Err = UnknownError;
358
359 fn from_str(s: &str) -> Result<Self, Self::Err> {
360 Ok(match s {
361 x if x.starts_with("ananas") => Self::Ananas,
362 x if x.starts_with("cloudabi") => Self::CloudABI,
363 x if x.starts_with("darwin") => Self::Darwin,
364 x if x.starts_with("dragonfly") => Self::DragonFly,
365 x if x.starts_with("freebsd") => Self::FreeBSD,
366 x if x.starts_with("fuchsia") => Self::Fuchsia,
367 x if x.starts_with("ios") => Self::IOS,
368 x if x.starts_with("kfreebsd") => Self::KFreeBSD,
369 x if x.starts_with("linux") => Self::Linux,
370 x if x.starts_with("lv2") => Self::Lv2,
371 x if x.starts_with("macos") => Self::MacOSX,
372 x if x.starts_with("netbsd") => Self::NetBSD,
373 x if x.starts_with("openbsd") => Self::OpenBSD,
374 x if x.starts_with("solaris") => Self::Solaris,
375 x if x.starts_with("win32") | x.starts_with("windows") => Self::Win32,
376 x if x.starts_with("zos") => Self::ZOS,
377 x if x.starts_with("haiku") => Self::Haiku,
378 x if x.starts_with("minix") => Self::Minix,
379 x if x.starts_with("rtems") => Self::RTEMS,
380 x if x.starts_with("nacl") => Self::NaCl,
381 x if x.starts_with("aix") => Self::AIX,
382 x if x.starts_with("cuda") => Self::CUDA,
383 x if x.starts_with("nvcl") => Self::NVCL,
384 x if x.starts_with("amdhsa") => Self::AMDHSA,
385 x if x.starts_with("ps4") => Self::PS4,
386 x if x.starts_with("elfiamcu") => Self::ELFIAMCU,
387 x if x.starts_with("tvos") => Self::TvOS,
388 x if x.starts_with("watchos") => Self::WatchOS,
389 x if x.starts_with("mesa3d") => Self::Mesa3D,
390 x if x.starts_with("contiki") => Self::Contiki,
391 x if x.starts_with("amdpal") => Self::AMDPAL,
392 x if x.starts_with("hermit") => Self::HermitCore,
393 x if x.starts_with("hurd") => Self::Hurd,
394 x if x.starts_with("wasi") => Self::WASI,
395 x if x.starts_with("emscripten") => Self::Emscripten,
396 x if x.starts_with("phantom") => Self::PhantomOS,
397 x if x.starts_with("snes") => Self::SNES,
398 x if x.starts_with("nes") => Self::NES,
399 x if x.starts_with("cleveros") => Self::CleverOS,
400 x if x.starts_with("ableos") => Self::AbleOS,
401 "none" => Self::None,
402
403 _ => return Err(UnknownError),
404 })
405 }
406}
407
408impl Display for OS {
409 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
410 self.canonical_name().fmt(f)
411 }
412}
413
414impl OS {
415 pub fn parse(s: &str) -> Self {
418 Self::from_str(s).unwrap_or(Self::Unknown)
419 }
420
421 pub fn canonical_name(&self) -> &'static str {
426 match self {
427 OS::Unknown => "unknown",
428 OS::Ananas => "ananas",
429 OS::CloudABI => "cloudabi",
430 OS::Darwin => "darwin",
431 OS::DragonFly => "dragonfly",
432 OS::FreeBSD => "freebsd",
433 OS::Fuchsia => "fuchsia",
434 OS::IOS => "ios",
435 OS::KFreeBSD => "kfreebsd",
436 OS::Linux => "linux",
437 OS::Lv2 => "lv2",
438 OS::MacOSX => "macos",
439 OS::NetBSD => "netbsd",
440 OS::OpenBSD => "openbsd",
441 OS::Solaris => "solaris",
442 OS::Win32 => "win32",
443 OS::ZOS => "zos",
444 OS::Haiku => "haiku",
445 OS::Minix => "minix",
446 OS::RTEMS => "rtems",
447 OS::NaCl => "nacl",
448 OS::AIX => "aix",
449 OS::CUDA => "cuda",
450 OS::NVCL => "nvcl",
451 OS::AMDHSA => "amdhsa",
452 OS::PS4 => "ps4",
453 OS::ELFIAMCU => "elfiamcu",
454 OS::TvOS => "tvos",
455 OS::WatchOS => "watchos",
456 OS::Mesa3D => "mesa3d",
457 OS::Contiki => "contiki",
458 OS::AMDPAL => "amdpal",
459 OS::HermitCore => "hermit",
460 OS::Hurd => "hurd",
461 OS::WASI => "wasi",
462 OS::Emscripten => "emscripten",
463 OS::PhantomOS => "phantom",
464 OS::SNES => "snes",
465 OS::NES => "nes",
466 OS::None => "none",
467 OS::CleverOS => "cleveros",
468 OS::AbleOS => "ableos",
469 OS::Null => "null",
470 OS::__Nonexhaustive => unreachable!(),
471 }
472 }
473}
474
475#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
478#[repr(u32)]
479pub enum Environment {
480 Unknown = 0,
481 GNU = 1,
482 GNUABIN32 = 2,
483 GNUABI64 = 3,
484 GNUEABI = 4,
485 GNUEABIHF = 5,
486 GNUX32 = 6,
487 CODE16 = 7,
488 EABI = 8,
489 EABIHF = 9,
490 Android = 10,
491 Musl = 11,
492 MuslEABI = 12,
493 MuslEABIHF = 13,
494
495 MSVC = 15,
496 Itanium = 16,
497 Cygnus = 17,
498 CoreCLR = 18,
499 Simulator = 19,
500 MacABI = 20,
501
502 PhantomStandard = 21,
503 PhantomKernel = 22,
504
505 Null = (-1i32) as u32,
506 #[doc(hidden)]
507 __Nonexhaustive = (-2i32) as u32,
508}
509
510impl FromStr for Environment {
511 type Err = UnknownError;
512
513 fn from_str(s: &str) -> Result<Self, Self::Err> {
514 Ok(match s {
515 x if x.starts_with("eabihf") => Self::EABIHF,
516 x if x.starts_with("eabi") => Self::EABI,
517 x if x.starts_with("gnuabin32") => Self::GNUABIN32,
518 x if x.starts_with("gnuabi64") => Self::GNUABI64,
519 x if x.starts_with("gnueabihf") => Self::GNUEABIHF,
520 x if x.starts_with("gnueabi") => Self::GNUEABI,
521 x if x.starts_with("gnux32") => Self::GNUX32,
522 x if x.starts_with("gnu") => Self::GNU,
523 x if x.starts_with("code16") => Self::CODE16,
524 x if x.starts_with("android") => Self::Android,
525 x if x.starts_with("musleabihf") => Self::MuslEABIHF,
526 x if x.starts_with("musleabi") => Self::MuslEABI,
527 x if x.starts_with("musl") => Self::Musl,
528 x if x.starts_with("msvc") => Self::MSVC,
529 x if x.starts_with("itanium") => Self::Itanium,
530 x if x.starts_with("cygnus") => Self::Cygnus,
531 x if x.starts_with("coreclr") => Self::CoreCLR,
532 x if x.starts_with("simulator") => Self::Simulator,
533 x if x.starts_with("macabi") => Self::MacABI,
534 x if x.starts_with("pcore") || x.starts_with("user") => Self::PhantomStandard,
535 x if x.starts_with("pkrnl") || x.starts_with("kernel") => Self::PhantomKernel,
536 _ => return Err(UnknownError),
537 })
538 }
539}
540
541impl Display for Environment {
542 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
543 self.canonical_name().fmt(f)
544 }
545}
546
547impl Environment {
548 pub fn parse(s: &str) -> Self {
551 Self::from_str(s).unwrap_or(Self::Unknown)
552 }
553
554 pub fn canonical_name(&self) -> &'static str {
559 match self {
560 Environment::Unknown => "unknown",
561 Environment::GNU => "gnu",
562 Environment::GNUABIN32 => "gnuabin32",
563 Environment::GNUABI64 => "gnuabi64",
564 Environment::GNUEABI => "gnueabi",
565 Environment::GNUEABIHF => "gnueabihf",
566 Environment::GNUX32 => "gnux32",
567 Environment::CODE16 => "code16",
568 Environment::EABI => "eabi",
569 Environment::EABIHF => "eabihf",
570 Environment::Android => "android",
571 Environment::Musl => "musl",
572 Environment::MuslEABI => "musleabi",
573 Environment::MuslEABIHF => "musleabihf",
574 Environment::MSVC => "msvc",
575 Environment::Itanium => "itanium",
576 Environment::Cygnus => "cygnus",
577 Environment::CoreCLR => "coreclr",
578 Environment::Simulator => "simulator",
579 Environment::MacABI => "macabi",
580 Environment::PhantomStandard => "user",
581 Environment::PhantomKernel => "kernel",
582 Environment::Null => "",
583 Environment::__Nonexhaustive => unreachable!(),
584 }
585 }
586}
587
588#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
591#[repr(u32)]
592pub enum ObjectFormat {
593 Unknown = 0,
594 XCoff = 1,
595 Coff = 2,
596 Elf = 3,
597 Goff = 4,
598 MachO = 5,
599 Wasm = 6,
600
601 Xo65 = 7,
602 O65 = 8,
603 WlaObj = 9,
604
605 Null = (-1i32) as u32,
606
607 #[doc(hidden)]
608 __Nonexhaustive = (-2i32) as u32,
609}
610
611impl FromStr for ObjectFormat {
612 type Err = UnknownError;
613
614 fn from_str(s: &str) -> Result<Self, Self::Err> {
615 Ok(match s {
616 x if x.ends_with("xcoff") => Self::XCoff,
617 x if x.ends_with("coff") => Self::Coff,
618 x if x.ends_with("elf") => Self::Elf,
619 x if x.ends_with("goff") => Self::Goff,
620 x if x.ends_with("macho") => Self::MachO,
621 x if x.ends_with("wasm") => Self::Wasm,
622 x if x.ends_with("xo65") => Self::Xo65,
623 x if x.ends_with("o65") => Self::O65,
624 x if x.ends_with("wlaobj") => Self::WlaObj,
625 x if x.ends_with("wla") => Self::WlaObj,
626 _ => return Err(UnknownError),
627 })
628 }
629}
630
631impl Display for ObjectFormat {
632 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
633 self.canonical_name().fmt(f)
634 }
635}
636
637impl ObjectFormat {
638 pub fn parse(s: &str) -> Self {
641 Self::from_str(s).unwrap_or(Self::Unknown)
642 }
643
644 pub fn canonical_name(&self) -> &'static str {
649 match self {
650 ObjectFormat::Unknown => "unknown",
651 ObjectFormat::XCoff => "xcoff",
652 ObjectFormat::Coff => "coff",
653 ObjectFormat::Elf => "elf",
654 ObjectFormat::Goff => "goff",
655 ObjectFormat::MachO => "macho",
656 ObjectFormat::Wasm => "wasm",
657 ObjectFormat::Xo65 => "xo65",
658 ObjectFormat::O65 => "o65",
659 ObjectFormat::WlaObj => "wlaobj",
660 ObjectFormat::Null => "",
661 ObjectFormat::__Nonexhaustive => unreachable!(),
662 }
663 }
664}
665
666#[derive(Clone, Debug)]
681pub struct Target {
682 full: String,
683 arch: Architecture,
684 vendor: Option<Vendor>,
685 os: Option<OS>,
688 env: Option<Environment>,
689 objfmt: Option<ObjectFormat>,
690}
691
692impl FromStr for Target {
693 type Err = UnknownError;
694
695 fn from_str(s: &str) -> Result<Self, Self::Err> {
696 let mut split = s.split('-');
697 let arch = split.next().ok_or(UnknownError).and_then(|s| s.parse())?;
698 let f2 = split.next().ok_or(UnknownError)?;
699 let f3 = split.next();
700 let f4 = split.next();
701 let vendor;
702 let os;
703 let env;
704 let objfmt;
705 if let (Some(s), None) = (f3, f4) {
706 if let "unknown" = f2 {
707 vendor = Some(Vendor::Unknown);
708 if let Ok(o) = s.parse() {
709 os = Some(o);
710 env = None;
711 objfmt = None;
712 } else if let Ok(e) = s.parse() {
713 os = None;
714 env = Some(e);
715 objfmt = s.parse().ok();
716 } else if let Ok(of) = s.parse() {
717 os = None;
718 env = None;
719 objfmt = Some(of);
720 } else {
721 return Err(UnknownError);
722 }
723 } else if let Vendor::Unknown = f2.parse().unwrap() {
724 vendor = None;
725 os = Some(f2.parse()?);
726 env = s.parse().ok();
727 objfmt = s.parse().ok();
728 env.map(|_| ())
729 .or_else(|| objfmt.map(|_| ()))
730 .ok_or(UnknownError)?;
731 } else {
732 vendor = Some(f2.parse().unwrap());
733 if let Ok(o) = s.parse() {
734 os = Some(o);
735 env = None;
736 objfmt = None;
737 } else if let Ok(e) = s.parse() {
738 os = None;
739 env = Some(e);
740 objfmt = s.parse().ok();
741 } else if let Ok(of) = s.parse() {
742 os = None;
743 env = None;
744 objfmt = Some(of);
745 } else {
746 return Err(UnknownError);
747 }
748 }
749 } else if let Some(s) = f4 {
750 vendor = Some(f2.parse().unwrap());
751 os = Some(f3.unwrap().parse()?);
752 env = s.parse().ok();
753 objfmt = s.parse().ok();
754 env.map(|_| ())
755 .or_else(|| objfmt.map(|_| ()))
756 .ok_or(UnknownError)?;
757 } else if let Ok(o) = f2.parse() {
758 vendor = None;
759 os = Some(o);
760 env = None;
761 objfmt = None;
762 } else if let Ok(e) = f2.parse() {
763 vendor = None;
764 os = None;
765 env = Some(e);
766 objfmt = f2.parse().ok();
767 } else if let Ok(of) = f2.parse() {
768 vendor = None;
769 os = None;
770 env = None;
771 objfmt = Some(of);
772 } else {
773 return Err(UnknownError);
774 }
775
776 Ok(Self {
777 full: s.to_owned(),
778 arch,
779 vendor,
780 os,
781 env,
782 objfmt,
783 })
784 }
785}
786
787impl Display for Target {
788 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
789 self.arch.fmt(f)?;
790 f.write_str("-")?;
791 if let Some(vendor) = &self.vendor {
792 vendor.fmt(f)?;
793 } else {
794 self.vendor().fmt(f)?;
795 }
796 if let Some(os) = &self.os {
797 f.write_str("-")?;
798 os.fmt(f)?;
799 }
800 let mut last_field_sep = true;
801 if let Some(env) = &self.env {
802 last_field_sep = false;
803 f.write_str("-")?;
804 env.fmt(f)?;
805 }
806 if let Some(objfmt) = &self.objfmt {
807 if last_field_sep {
808 f.write_str("-")?;
809 }
810 objfmt.fmt(f)?;
811 }
812 Ok(())
813 }
814}
815
816impl core::hash::Hash for Target {
817 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
818 self.arch.hash(state);
819 self.vendor.hash(state);
820 self.os.hash(state);
821 self.env.hash(state);
822 self.objfmt.hash(state);
823 }
824}
825
826impl PartialEq for Target {
827 fn eq(&self, other: &Self) -> bool {
828 self.arch == other.arch
829 && self.vendor == other.vendor
830 && self.os == other.os
831 && self.env == other.env
832 && self.objfmt == other.objfmt
833 }
834}
835
836impl Eq for Target {}
837
838impl Target {
839 pub fn get_name(&self) -> &str {
842 &self.full
843 }
844
845 pub fn arch_name(&self) -> &str {
848 self.full.split('-').next().unwrap()
849 }
850
851 pub fn vendor_name(&self) -> &str {
852 if self.vendor.is_some() {
853 self.full.split('-').nth(2).unwrap()
854 } else {
855 self.vendor().canonical_name()
856 }
857 }
858
859 pub fn sys(&self) -> &str {
861 let pos = self.full.find('-').unwrap();
862 let mut r = &self.full[(pos + 1)..];
863 if self.vendor.is_some() {
864 let pos = r.find('-').unwrap();
865 r = &r[(pos + 1)..];
866 }
867 r
868 }
869
870 pub fn parse(s: &str) -> Self {
876 let mut split = s.split('-');
877 let arch = Architecture::parse(split.next().unwrap());
878 let f2 = split.next().ok_or(UnknownError).unwrap();
879 let f3 = split.next();
880 let f4 = split.next();
881 let os;
882 let env;
883 let objfmt;
884 let vendor;
885 if let (Some(s), None) = (f3, f4) {
886 if let "unknown" = f2 {
887 vendor = Some(Vendor::Unknown);
888 if let Ok(o) = s.parse() {
889 os = Some(o);
890 env = None;
891 objfmt = None;
892 } else if let Ok(e) = s.parse() {
893 os = None;
894 env = Some(e);
895 objfmt = s.parse().ok();
896 } else if let Ok(of) = s.parse() {
897 os = None;
898 env = None;
899 objfmt = Some(of);
900 } else {
901 os = Some(OS::Unknown);
902 env = Some(Environment::Unknown);
903 objfmt = None;
904 }
905 } else if let Vendor::Unknown = f2.parse().unwrap() {
906 vendor = None;
907 os = Some(f2.parse().unwrap());
908 env = s.parse().ok();
909 objfmt = s.parse().ok();
910 env.map(|_| ()).or_else(|| objfmt.map(|_| ())).unwrap();
911 } else {
912 vendor = Some(f2.parse().unwrap());
913 if let Ok(o) = s.parse() {
914 os = Some(o);
915 env = None;
916 objfmt = None;
917 } else if let Ok(e) = s.parse() {
918 os = None;
919 env = Some(e);
920 objfmt = s.parse().ok();
921 } else if let Ok(of) = s.parse() {
922 os = None;
923 env = None;
924 objfmt = Some(of);
925 } else {
926 os = Some(OS::Unknown);
927 env = Some(Environment::Unknown);
928 objfmt = None;
929 }
930 }
931 } else if let Some(s) = f4 {
932 vendor = Some(f2.parse().unwrap());
933 os = Some(OS::parse(f3.unwrap()));
934 env = s.parse().ok();
935 objfmt = s.parse().ok();
936 env.map(|_| ()).or_else(|| objfmt.map(|_| ())).unwrap();
937 } else if let Ok(o) = f2.parse() {
938 vendor = None;
939 os = Some(o);
940 env = None;
941 objfmt = None;
942 } else if let Ok(e) = f2.parse() {
943 vendor = None;
944 os = None;
945 env = Some(e);
946 objfmt = f2.parse().ok();
947 } else if let Ok(of) = f2.parse() {
948 vendor = None;
949 os = None;
950 env = None;
951 objfmt = Some(of);
952 } else {
953 vendor = Some(Vendor::Unknown);
954 os = Some(OS::Unknown);
955 env = Some(Environment::Unknown);
956 objfmt = None;
957 }
958
959 Self {
960 full: s.to_owned(),
961 arch,
962 vendor,
963 os,
964 env,
965 objfmt,
966 }
967 }
968
969 pub fn operating_system(&self) -> Option<OS> {
972 self.os
973 }
974
975 pub fn environment(&self) -> Option<Environment> {
978 self.env
979 }
980
981 pub fn parse_components(arch: &str, vendor: Option<&str>, sys: &str) -> Self {
982 use core::fmt::Write;
983 let mut full = String::new();
984 write!(full, "{}", arch).unwrap();
985 if let Some(vendor) = vendor {
986 write!(full, "-{}", vendor).unwrap();
987 }
988 write!(full, "-{}", sys).unwrap();
989
990 let arch = Architecture::parse(arch);
991 let vendor = vendor.map(Vendor::parse);
992
993 let mut os = None;
994 let mut env = None;
995 let mut objfmt = None;
996
997 if let Some(pos) = sys.find('-') {
998 let (l, r) = sys.split_at(pos);
999 let r = &r[1..];
1000 os = Some(OS::parse(l));
1001
1002 env = r.parse().ok();
1003 objfmt = r.parse().ok();
1004 } else if let Ok(o) = sys.parse::<OS>() {
1005 os = Some(o);
1006 } else {
1007 env = sys.parse().ok();
1008 objfmt = sys.parse().ok();
1009 }
1010 assert!(os.is_some() || env.is_some() || objfmt.is_some());
1011 Self {
1012 full,
1013 arch,
1014 vendor,
1015 os,
1016 env,
1017 objfmt,
1018 }
1019 }
1020
1021 pub fn from_components(
1024 arch: Architecture,
1025 vendor: Vendor,
1026 os: Option<OS>,
1027 env: Option<Environment>,
1028 objfmt: Option<ObjectFormat>,
1029 ) -> Self {
1030 let mut ret = Self {
1031 full: String::new(),
1032 arch,
1033 vendor: Some(vendor),
1034 os,
1035 env,
1036 objfmt,
1037 };
1038 ret.full = alloc::format!("{}", &ret);
1039 ret
1040 }
1041
1042 pub fn from_components_without_vendor(
1045 arch: Architecture,
1046 os: Option<OS>,
1047 env: Option<Environment>,
1048 objfmt: Option<ObjectFormat>,
1049 ) -> Self {
1050 use core::fmt::Write;
1051 let mut ret = Self {
1052 full: String::new(),
1053 arch,
1054 vendor: None,
1055 os,
1056 env,
1057 objfmt,
1058 };
1059 write!(ret.full, "{}", arch).unwrap();
1060 if let Some(os) = os {
1061 write!(ret.full, "-{}", os).unwrap();
1062 }
1063 if let Some(env) = env {
1064 write!(ret.full, "-{}", env).unwrap();
1065 } else if let Some(objfmt) = objfmt {
1066 write!(ret.full, "-{}", objfmt).unwrap();
1067 }
1068 ret
1069 }
1070
1071 pub fn target_object_format(&self) -> ObjectFormat {
1074 if let Some(of) = self.objfmt {
1075 of
1076 } else {
1077 match (&self.arch, &self.os) {
1078 (Architecture::Unknown, Some(OS::MacOSX)) => ObjectFormat::MachO,
1079 (Architecture::Aarch64, Some(OS::MacOSX)) => ObjectFormat::MachO,
1080 (Architecture::Aarch64_32, Some(OS::MacOSX)) => ObjectFormat::MachO,
1081 (Architecture::Arm, Some(OS::MacOSX)) => ObjectFormat::MachO,
1082 (arch, Some(OS::MacOSX)) if arch.is_x86() => ObjectFormat::MachO,
1083 (Architecture::X86_64, Some(OS::MacOSX)) => ObjectFormat::MachO,
1084 (Architecture::Unknown, Some(OS::Win32)) => ObjectFormat::Coff,
1085 (Architecture::Aarch64, Some(OS::Win32)) => ObjectFormat::Coff,
1086 (Architecture::Aarch64_32, Some(OS::Win32)) => ObjectFormat::Coff,
1087 (Architecture::Arm, Some(OS::Win32)) => ObjectFormat::Coff,
1088 (arch, Some(OS::Win32)) if arch.is_x86() => ObjectFormat::Coff,
1089 (Architecture::X86_64, Some(OS::Win32)) => ObjectFormat::Coff,
1090 (Architecture::PowerPC32, Some(OS::AIX)) => ObjectFormat::XCoff,
1091 (Architecture::PowerPC64, Some(OS::AIX)) => ObjectFormat::XCoff,
1092 (Architecture::SPC700, _) => ObjectFormat::WlaObj,
1093 _ => ObjectFormat::Elf,
1094 }
1095 }
1096 }
1097
1098 pub fn object_format(&self) -> Option<ObjectFormat> {
1100 self.objfmt
1101 }
1102
1103 pub fn arch(&self) -> Architecture {
1106 self.arch
1107 }
1108
1109 pub fn vendor(&self) -> Vendor {
1112 if let Some(vendor) = &self.vendor {
1113 *vendor
1114 } else if self.arch.is_x86() || Architecture::X86_64 == self.arch {
1115 match self.os {
1116 Some(OS::MacOSX) | Some(OS::IOS) | Some(OS::TvOS) | Some(OS::WatchOS) => {
1117 Vendor::Apple
1118 }
1119 Some(OS::CUDA) => Vendor::NVIDIA,
1120 _ => Vendor::PC,
1121 }
1122 } else if let Architecture::Wc65c816 = self.arch {
1123 Vendor::WDC
1124 } else {
1125 Vendor::Unknown
1126 }
1127 }
1128}
1129
1130#[macro_export]
1133macro_rules! from_env {
1134 ($var:literal) => {{
1135 use core::str::FromStr as _;
1136 let _target: $crate::Target = ::core::env!($var).parse().unwrap();
1137 _target
1138 }};
1139 ($var:literal?) => {{
1140 use core::str::FromStr as _;
1141 let _target: ::core::option::Option<$crate::Target> =
1142 ::core::option_env!($var).map(|s| s.parse().unwrap());
1143 _target
1144 }};
1145}