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 Lilium = 42,
351
352 Null = (-1i32) as u32,
353 #[doc(hidden)]
354 __Nonexhaustive = (-2i32) as u32,
355}
356
357impl FromStr for OS {
358 type Err = UnknownError;
359
360 fn from_str(s: &str) -> Result<Self, Self::Err> {
361 Ok(match s {
362 x if x.starts_with("ananas") => Self::Ananas,
363 x if x.starts_with("cloudabi") => Self::CloudABI,
364 x if x.starts_with("darwin") => Self::Darwin,
365 x if x.starts_with("dragonfly") => Self::DragonFly,
366 x if x.starts_with("freebsd") => Self::FreeBSD,
367 x if x.starts_with("fuchsia") => Self::Fuchsia,
368 x if x.starts_with("ios") => Self::IOS,
369 x if x.starts_with("kfreebsd") => Self::KFreeBSD,
370 x if x.starts_with("linux") => Self::Linux,
371 x if x.starts_with("lv2") => Self::Lv2,
372 x if x.starts_with("macos") => Self::MacOSX,
373 x if x.starts_with("netbsd") => Self::NetBSD,
374 x if x.starts_with("openbsd") => Self::OpenBSD,
375 x if x.starts_with("solaris") => Self::Solaris,
376 x if x.starts_with("win32") | x.starts_with("windows") => Self::Win32,
377 x if x.starts_with("zos") => Self::ZOS,
378 x if x.starts_with("haiku") => Self::Haiku,
379 x if x.starts_with("minix") => Self::Minix,
380 x if x.starts_with("rtems") => Self::RTEMS,
381 x if x.starts_with("nacl") => Self::NaCl,
382 x if x.starts_with("aix") => Self::AIX,
383 x if x.starts_with("cuda") => Self::CUDA,
384 x if x.starts_with("nvcl") => Self::NVCL,
385 x if x.starts_with("amdhsa") => Self::AMDHSA,
386 x if x.starts_with("ps4") => Self::PS4,
387 x if x.starts_with("elfiamcu") => Self::ELFIAMCU,
388 x if x.starts_with("tvos") => Self::TvOS,
389 x if x.starts_with("watchos") => Self::WatchOS,
390 x if x.starts_with("mesa3d") => Self::Mesa3D,
391 x if x.starts_with("contiki") => Self::Contiki,
392 x if x.starts_with("amdpal") => Self::AMDPAL,
393 x if x.starts_with("hermit") => Self::HermitCore,
394 x if x.starts_with("hurd") => Self::Hurd,
395 x if x.starts_with("wasi") => Self::WASI,
396 x if x.starts_with("emscripten") => Self::Emscripten,
397 x if x.starts_with("phantom") => Self::PhantomOS,
398 x if x.starts_with("snes") => Self::SNES,
399 x if x.starts_with("nes") => Self::NES,
400 x if x.starts_with("cleveros") => Self::CleverOS,
401 x if x.starts_with("ableos") => Self::AbleOS,
402 x if x.starts_with("lilium") => Self::Lilium,
403 "none" => Self::None,
404
405 _ => return Err(UnknownError),
406 })
407 }
408}
409
410impl Display for OS {
411 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
412 self.canonical_name().fmt(f)
413 }
414}
415
416impl OS {
417 pub fn parse(s: &str) -> Self {
420 Self::from_str(s).unwrap_or(Self::Unknown)
421 }
422
423 pub fn canonical_name(&self) -> &'static str {
428 match self {
429 OS::Unknown => "unknown",
430 OS::Ananas => "ananas",
431 OS::CloudABI => "cloudabi",
432 OS::Darwin => "darwin",
433 OS::DragonFly => "dragonfly",
434 OS::FreeBSD => "freebsd",
435 OS::Fuchsia => "fuchsia",
436 OS::IOS => "ios",
437 OS::KFreeBSD => "kfreebsd",
438 OS::Linux => "linux",
439 OS::Lv2 => "lv2",
440 OS::MacOSX => "macos",
441 OS::NetBSD => "netbsd",
442 OS::OpenBSD => "openbsd",
443 OS::Solaris => "solaris",
444 OS::Win32 => "win32",
445 OS::ZOS => "zos",
446 OS::Haiku => "haiku",
447 OS::Minix => "minix",
448 OS::RTEMS => "rtems",
449 OS::NaCl => "nacl",
450 OS::AIX => "aix",
451 OS::CUDA => "cuda",
452 OS::NVCL => "nvcl",
453 OS::AMDHSA => "amdhsa",
454 OS::PS4 => "ps4",
455 OS::ELFIAMCU => "elfiamcu",
456 OS::TvOS => "tvos",
457 OS::WatchOS => "watchos",
458 OS::Mesa3D => "mesa3d",
459 OS::Contiki => "contiki",
460 OS::AMDPAL => "amdpal",
461 OS::HermitCore => "hermit",
462 OS::Hurd => "hurd",
463 OS::WASI => "wasi",
464 OS::Emscripten => "emscripten",
465 OS::PhantomOS => "phantom",
466 OS::SNES => "snes",
467 OS::NES => "nes",
468 OS::None => "none",
469 OS::CleverOS => "cleveros",
470 OS::AbleOS => "ableos",
471 OS::Lilium => "lilium",
472 OS::Null => "null",
473 OS::__Nonexhaustive => unreachable!(),
474 }
475 }
476}
477
478#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
481#[repr(u32)]
482pub enum Environment {
483 Unknown = 0,
484 GNU = 1,
485 GNUABIN32 = 2,
486 GNUABI64 = 3,
487 GNUEABI = 4,
488 GNUEABIHF = 5,
489 GNUX32 = 6,
490 CODE16 = 7,
491 EABI = 8,
492 EABIHF = 9,
493 Android = 10,
494 Musl = 11,
495 MuslEABI = 12,
496 MuslEABIHF = 13,
497
498 MSVC = 15,
499 Itanium = 16,
500 Cygnus = 17,
501 CoreCLR = 18,
502 Simulator = 19,
503 MacABI = 20,
504
505 #[deprecated = "Renamed OS, use Standard instead"]
506 PhantomStandard = 21,
507 #[deprecated = "Renamed OS, use Kernel instead"]
508 PhantomKernel = 22,
509
510 Standard = 23,
511 Kernel = 24,
512
513 Null = (-1i32) as u32,
514 #[doc(hidden)]
515 __Nonexhaustive = (-2i32) as u32,
516}
517
518impl FromStr for Environment {
519 type Err = UnknownError;
520
521 fn from_str(s: &str) -> Result<Self, Self::Err> {
522 Ok(match s {
523 x if x.starts_with("eabihf") => Self::EABIHF,
524 x if x.starts_with("eabi") => Self::EABI,
525 x if x.starts_with("gnuabin32") => Self::GNUABIN32,
526 x if x.starts_with("gnuabi64") => Self::GNUABI64,
527 x if x.starts_with("gnueabihf") => Self::GNUEABIHF,
528 x if x.starts_with("gnueabi") => Self::GNUEABI,
529 x if x.starts_with("gnux32") => Self::GNUX32,
530 x if x.starts_with("gnu") => Self::GNU,
531 x if x.starts_with("code16") => Self::CODE16,
532 x if x.starts_with("android") => Self::Android,
533 x if x.starts_with("musleabihf") => Self::MuslEABIHF,
534 x if x.starts_with("musleabi") => Self::MuslEABI,
535 x if x.starts_with("musl") => Self::Musl,
536 x if x.starts_with("msvc") => Self::MSVC,
537 x if x.starts_with("itanium") => Self::Itanium,
538 x if x.starts_with("cygnus") => Self::Cygnus,
539 x if x.starts_with("coreclr") => Self::CoreCLR,
540 x if x.starts_with("simulator") => Self::Simulator,
541 x if x.starts_with("macabi") => Self::MacABI,
542 #[allow(deprecated)]
543 x if x.starts_with("pcore") => Self::PhantomStandard,
544 #[allow(deprecated)]
545 x if x.starts_with("pkrnl") => Self::PhantomKernel,
546 x if x.starts_with("std") => Self::Standard,
547 x if x.starts_with("kernel") => Self::Kernel,
548 _ => return Err(UnknownError),
549 })
550 }
551}
552
553impl Display for Environment {
554 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
555 self.canonical_name().fmt(f)
556 }
557}
558
559impl Environment {
560 pub fn parse(s: &str) -> Self {
563 Self::from_str(s).unwrap_or(Self::Unknown)
564 }
565
566 pub fn canonical_name(&self) -> &'static str {
571 match self {
572 Environment::Unknown => "unknown",
573 Environment::GNU => "gnu",
574 Environment::GNUABIN32 => "gnuabin32",
575 Environment::GNUABI64 => "gnuabi64",
576 Environment::GNUEABI => "gnueabi",
577 Environment::GNUEABIHF => "gnueabihf",
578 Environment::GNUX32 => "gnux32",
579 Environment::CODE16 => "code16",
580 Environment::EABI => "eabi",
581 Environment::EABIHF => "eabihf",
582 Environment::Android => "android",
583 Environment::Musl => "musl",
584 Environment::MuslEABI => "musleabi",
585 Environment::MuslEABIHF => "musleabihf",
586 Environment::MSVC => "msvc",
587 Environment::Itanium => "itanium",
588 Environment::Cygnus => "cygnus",
589 Environment::CoreCLR => "coreclr",
590 Environment::Simulator => "simulator",
591 Environment::MacABI => "macabi",
592 #[allow(deprecated)]
593 Environment::PhantomStandard => "user",
594 #[allow(deprecated)]
595 Environment::PhantomKernel => "kernel",
596 Environment::Standard => "std",
597 Environment::Kernel => "kernel",
598 Environment::Null => "",
599 Environment::__Nonexhaustive => unreachable!(),
600 }
601 }
602}
603
604#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
607#[repr(u32)]
608pub enum ObjectFormat {
609 Unknown = 0,
610 XCoff = 1,
611 Coff = 2,
612 Elf = 3,
613 Goff = 4,
614 MachO = 5,
615 Wasm = 6,
616
617 Xo65 = 7,
618 O65 = 8,
619 WlaObj = 9,
620
621 Null = (-1i32) as u32,
622
623 #[doc(hidden)]
624 __Nonexhaustive = (-2i32) as u32,
625}
626
627impl FromStr for ObjectFormat {
628 type Err = UnknownError;
629
630 fn from_str(s: &str) -> Result<Self, Self::Err> {
631 Ok(match s {
632 x if x.ends_with("xcoff") => Self::XCoff,
633 x if x.ends_with("coff") => Self::Coff,
634 x if x.ends_with("elf") => Self::Elf,
635 x if x.ends_with("goff") => Self::Goff,
636 x if x.ends_with("macho") => Self::MachO,
637 x if x.ends_with("wasm") => Self::Wasm,
638 x if x.ends_with("xo65") => Self::Xo65,
639 x if x.ends_with("o65") => Self::O65,
640 x if x.ends_with("wlaobj") => Self::WlaObj,
641 x if x.ends_with("wla") => Self::WlaObj,
642 _ => return Err(UnknownError),
643 })
644 }
645}
646
647impl Display for ObjectFormat {
648 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
649 self.canonical_name().fmt(f)
650 }
651}
652
653impl ObjectFormat {
654 pub fn parse(s: &str) -> Self {
657 Self::from_str(s).unwrap_or(Self::Unknown)
658 }
659
660 pub fn canonical_name(&self) -> &'static str {
665 match self {
666 ObjectFormat::Unknown => "unknown",
667 ObjectFormat::XCoff => "xcoff",
668 ObjectFormat::Coff => "coff",
669 ObjectFormat::Elf => "elf",
670 ObjectFormat::Goff => "goff",
671 ObjectFormat::MachO => "macho",
672 ObjectFormat::Wasm => "wasm",
673 ObjectFormat::Xo65 => "xo65",
674 ObjectFormat::O65 => "o65",
675 ObjectFormat::WlaObj => "wlaobj",
676 ObjectFormat::Null => "",
677 ObjectFormat::__Nonexhaustive => unreachable!(),
678 }
679 }
680}
681
682#[derive(Clone, Debug)]
697pub struct Target {
698 full: String,
699 arch: Architecture,
700 vendor: Option<Vendor>,
701 os: Option<OS>,
704 env: Option<Environment>,
705 objfmt: Option<ObjectFormat>,
706}
707
708impl FromStr for Target {
709 type Err = UnknownError;
710
711 fn from_str(s: &str) -> Result<Self, Self::Err> {
712 let mut split = s.split('-');
713 let arch = split.next().ok_or(UnknownError).and_then(|s| s.parse())?;
714 let f2 = split.next().ok_or(UnknownError)?;
715 let f3 = split.next();
716 let f4 = split.next();
717 let vendor;
718 let os;
719 let env;
720 let objfmt;
721 if let (Some(s), None) = (f3, f4) {
722 if let "unknown" = f2 {
723 vendor = Some(Vendor::Unknown);
724 if let Ok(o) = s.parse() {
725 os = Some(o);
726 env = None;
727 objfmt = None;
728 } else if let Ok(e) = s.parse() {
729 os = None;
730 env = Some(e);
731 objfmt = s.parse().ok();
732 } else if let Ok(of) = s.parse() {
733 os = None;
734 env = None;
735 objfmt = Some(of);
736 } else {
737 return Err(UnknownError);
738 }
739 } else if let Vendor::Unknown = f2.parse().unwrap() {
740 vendor = None;
741 os = Some(f2.parse()?);
742 env = s.parse().ok();
743 objfmt = s.parse().ok();
744 env.map(|_| ())
745 .or_else(|| objfmt.map(|_| ()))
746 .ok_or(UnknownError)?;
747 } else {
748 vendor = Some(f2.parse().unwrap());
749 if let Ok(o) = s.parse() {
750 os = Some(o);
751 env = None;
752 objfmt = None;
753 } else if let Ok(e) = s.parse() {
754 os = None;
755 env = Some(e);
756 objfmt = s.parse().ok();
757 } else if let Ok(of) = s.parse() {
758 os = None;
759 env = None;
760 objfmt = Some(of);
761 } else {
762 return Err(UnknownError);
763 }
764 }
765 } else if let Some(s) = f4 {
766 vendor = Some(f2.parse().unwrap());
767 os = Some(f3.unwrap().parse()?);
768 env = s.parse().ok();
769 objfmt = s.parse().ok();
770 env.map(|_| ())
771 .or_else(|| objfmt.map(|_| ()))
772 .ok_or(UnknownError)?;
773 } else if let Ok(o) = f2.parse() {
774 vendor = None;
775 os = Some(o);
776 env = None;
777 objfmt = None;
778 } else if let Ok(e) = f2.parse() {
779 vendor = None;
780 os = None;
781 env = Some(e);
782 objfmt = f2.parse().ok();
783 } else if let Ok(of) = f2.parse() {
784 vendor = None;
785 os = None;
786 env = None;
787 objfmt = Some(of);
788 } else {
789 return Err(UnknownError);
790 }
791
792 Ok(Self {
793 full: s.to_owned(),
794 arch,
795 vendor,
796 os,
797 env,
798 objfmt,
799 })
800 }
801}
802
803impl Display for Target {
804 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
805 self.arch.fmt(f)?;
806 f.write_str("-")?;
807 if let Some(vendor) = &self.vendor {
808 vendor.fmt(f)?;
809 } else {
810 self.vendor().fmt(f)?;
811 }
812 if let Some(os) = &self.os {
813 f.write_str("-")?;
814 os.fmt(f)?;
815 }
816 let mut last_field_sep = true;
817 if let Some(env) = &self.env {
818 last_field_sep = false;
819 f.write_str("-")?;
820 env.fmt(f)?;
821 }
822 if let Some(objfmt) = &self.objfmt {
823 if last_field_sep {
824 f.write_str("-")?;
825 }
826 objfmt.fmt(f)?;
827 }
828 Ok(())
829 }
830}
831
832impl core::hash::Hash for Target {
833 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
834 self.arch.hash(state);
835 self.vendor.hash(state);
836 self.os.hash(state);
837 self.env.hash(state);
838 self.objfmt.hash(state);
839 }
840}
841
842impl PartialEq for Target {
843 fn eq(&self, other: &Self) -> bool {
844 self.arch == other.arch
845 && self.vendor == other.vendor
846 && self.os == other.os
847 && self.env == other.env
848 && self.objfmt == other.objfmt
849 }
850}
851
852impl Eq for Target {}
853
854impl Target {
855 pub fn get_name(&self) -> &str {
858 &self.full
859 }
860
861 pub fn arch_name(&self) -> &str {
864 self.full.split('-').next().unwrap()
865 }
866
867 pub fn vendor_name(&self) -> &str {
868 if self.vendor.is_some() {
869 self.full.split('-').nth(2).unwrap()
870 } else {
871 self.vendor().canonical_name()
872 }
873 }
874
875 pub fn sys(&self) -> &str {
877 let pos = self.full.find('-').unwrap();
878 let mut r = &self.full[(pos + 1)..];
879 if self.vendor.is_some() {
880 let pos = r.find('-').unwrap();
881 r = &r[(pos + 1)..];
882 }
883 r
884 }
885
886 pub fn parse(s: &str) -> Self {
892 let mut split = s.split('-');
893 let arch = Architecture::parse(split.next().unwrap());
894 let f2 = split.next().ok_or(UnknownError).unwrap();
895 let f3 = split.next();
896 let f4 = split.next();
897 let os;
898 let env;
899 let objfmt;
900 let vendor;
901 if let (Some(s), None) = (f3, f4) {
902 if let "unknown" = f2 {
903 vendor = Some(Vendor::Unknown);
904 if let Ok(o) = s.parse() {
905 os = Some(o);
906 env = None;
907 objfmt = None;
908 } else if let Ok(e) = s.parse() {
909 os = None;
910 env = Some(e);
911 objfmt = s.parse().ok();
912 } else if let Ok(of) = s.parse() {
913 os = None;
914 env = None;
915 objfmt = Some(of);
916 } else {
917 os = Some(OS::Unknown);
918 env = Some(Environment::Unknown);
919 objfmt = None;
920 }
921 } else if let Vendor::Unknown = f2.parse().unwrap() {
922 vendor = None;
923 os = Some(f2.parse().unwrap());
924 env = s.parse().ok();
925 objfmt = s.parse().ok();
926 env.map(|_| ()).or_else(|| objfmt.map(|_| ())).unwrap();
927 } else {
928 vendor = Some(f2.parse().unwrap());
929 if let Ok(o) = s.parse() {
930 os = Some(o);
931 env = None;
932 objfmt = None;
933 } else if let Ok(e) = s.parse() {
934 os = None;
935 env = Some(e);
936 objfmt = s.parse().ok();
937 } else if let Ok(of) = s.parse() {
938 os = None;
939 env = None;
940 objfmt = Some(of);
941 } else {
942 os = Some(OS::Unknown);
943 env = Some(Environment::Unknown);
944 objfmt = None;
945 }
946 }
947 } else if let Some(s) = f4 {
948 vendor = Some(f2.parse().unwrap());
949 os = Some(OS::parse(f3.unwrap()));
950 env = s.parse().ok();
951 objfmt = s.parse().ok();
952 env.map(|_| ()).or_else(|| objfmt.map(|_| ())).unwrap();
953 } else if let Ok(o) = f2.parse() {
954 vendor = None;
955 os = Some(o);
956 env = None;
957 objfmt = None;
958 } else if let Ok(e) = f2.parse() {
959 vendor = None;
960 os = None;
961 env = Some(e);
962 objfmt = f2.parse().ok();
963 } else if let Ok(of) = f2.parse() {
964 vendor = None;
965 os = None;
966 env = None;
967 objfmt = Some(of);
968 } else {
969 vendor = Some(Vendor::Unknown);
970 os = Some(OS::Unknown);
971 env = Some(Environment::Unknown);
972 objfmt = None;
973 }
974
975 Self {
976 full: s.to_owned(),
977 arch,
978 vendor,
979 os,
980 env,
981 objfmt,
982 }
983 }
984
985 pub fn operating_system(&self) -> Option<OS> {
988 self.os
989 }
990
991 pub fn environment(&self) -> Option<Environment> {
994 self.env
995 }
996
997 pub fn parse_components(arch: &str, vendor: Option<&str>, sys: &str) -> Self {
998 use core::fmt::Write;
999 let mut full = String::new();
1000 write!(full, "{}", arch).unwrap();
1001 if let Some(vendor) = vendor {
1002 write!(full, "-{}", vendor).unwrap();
1003 }
1004 write!(full, "-{}", sys).unwrap();
1005
1006 let arch = Architecture::parse(arch);
1007 let vendor = vendor.map(Vendor::parse);
1008
1009 let mut os = None;
1010 let mut env = None;
1011 let mut objfmt = None;
1012
1013 if let Some(pos) = sys.find('-') {
1014 let (l, r) = sys.split_at(pos);
1015 let r = &r[1..];
1016 os = Some(OS::parse(l));
1017
1018 env = r.parse().ok();
1019 objfmt = r.parse().ok();
1020 } else if let Ok(o) = sys.parse::<OS>() {
1021 os = Some(o);
1022 } else {
1023 env = sys.parse().ok();
1024 objfmt = sys.parse().ok();
1025 }
1026 assert!(os.is_some() || env.is_some() || objfmt.is_some());
1027 Self {
1028 full,
1029 arch,
1030 vendor,
1031 os,
1032 env,
1033 objfmt,
1034 }
1035 }
1036
1037 pub fn from_components(
1040 arch: Architecture,
1041 vendor: Vendor,
1042 os: Option<OS>,
1043 env: Option<Environment>,
1044 objfmt: Option<ObjectFormat>,
1045 ) -> Self {
1046 let mut ret = Self {
1047 full: String::new(),
1048 arch,
1049 vendor: Some(vendor),
1050 os,
1051 env,
1052 objfmt,
1053 };
1054 ret.full = alloc::format!("{}", &ret);
1055 ret
1056 }
1057
1058 pub fn from_components_without_vendor(
1061 arch: Architecture,
1062 os: Option<OS>,
1063 env: Option<Environment>,
1064 objfmt: Option<ObjectFormat>,
1065 ) -> Self {
1066 use core::fmt::Write;
1067 let mut ret = Self {
1068 full: String::new(),
1069 arch,
1070 vendor: None,
1071 os,
1072 env,
1073 objfmt,
1074 };
1075 write!(ret.full, "{}", arch).unwrap();
1076 if let Some(os) = os {
1077 write!(ret.full, "-{}", os).unwrap();
1078 }
1079 if let Some(env) = env {
1080 write!(ret.full, "-{}", env).unwrap();
1081 } else if let Some(objfmt) = objfmt {
1082 write!(ret.full, "-{}", objfmt).unwrap();
1083 }
1084 ret
1085 }
1086
1087 pub fn target_object_format(&self) -> ObjectFormat {
1090 if let Some(of) = self.objfmt {
1091 of
1092 } else {
1093 match (&self.arch, &self.os) {
1094 (Architecture::Unknown, Some(OS::MacOSX)) => ObjectFormat::MachO,
1095 (Architecture::Aarch64, Some(OS::MacOSX)) => ObjectFormat::MachO,
1096 (Architecture::Aarch64_32, Some(OS::MacOSX)) => ObjectFormat::MachO,
1097 (Architecture::Arm, Some(OS::MacOSX)) => ObjectFormat::MachO,
1098 (arch, Some(OS::MacOSX)) if arch.is_x86() => ObjectFormat::MachO,
1099 (Architecture::X86_64, Some(OS::MacOSX)) => ObjectFormat::MachO,
1100 (Architecture::Unknown, Some(OS::Win32)) => ObjectFormat::Coff,
1101 (Architecture::Aarch64, Some(OS::Win32)) => ObjectFormat::Coff,
1102 (Architecture::Aarch64_32, Some(OS::Win32)) => ObjectFormat::Coff,
1103 (Architecture::Arm, Some(OS::Win32)) => ObjectFormat::Coff,
1104 (arch, Some(OS::Win32)) if arch.is_x86() => ObjectFormat::Coff,
1105 (Architecture::X86_64, Some(OS::Win32)) => ObjectFormat::Coff,
1106 (Architecture::PowerPC32, Some(OS::AIX)) => ObjectFormat::XCoff,
1107 (Architecture::PowerPC64, Some(OS::AIX)) => ObjectFormat::XCoff,
1108 (Architecture::SPC700, _) => ObjectFormat::WlaObj,
1109 _ => ObjectFormat::Elf,
1110 }
1111 }
1112 }
1113
1114 pub fn object_format(&self) -> Option<ObjectFormat> {
1116 self.objfmt
1117 }
1118
1119 pub fn arch(&self) -> Architecture {
1122 self.arch
1123 }
1124
1125 pub fn vendor(&self) -> Vendor {
1128 if let Some(vendor) = &self.vendor {
1129 *vendor
1130 } else if self.arch.is_x86() || Architecture::X86_64 == self.arch {
1131 match self.os {
1132 Some(OS::MacOSX) | Some(OS::IOS) | Some(OS::TvOS) | Some(OS::WatchOS) => {
1133 Vendor::Apple
1134 }
1135 Some(OS::CUDA) => Vendor::NVIDIA,
1136 _ => Vendor::PC,
1137 }
1138 } else if let Architecture::Wc65c816 = self.arch {
1139 Vendor::WDC
1140 } else {
1141 Vendor::Unknown
1142 }
1143 }
1144}
1145
1146#[macro_export]
1149macro_rules! from_env {
1150 ($var:literal) => {{
1151 use core::str::FromStr as _;
1152 let _target: $crate::Target = ::core::env!($var).parse().unwrap();
1153 _target
1154 }};
1155 ($var:literal?) => {{
1156 use core::str::FromStr as _;
1157 let _target: ::core::option::Option<$crate::Target> =
1158 ::core::option_env!($var).map(|s| s.parse().unwrap());
1159 _target
1160 }};
1161}