target_tuples/
pieces.rs

1#![allow(
2    clippy::upper_case_acronyms,
3    clippy::manual_non_exhaustive,
4    clippy::match_like_matches_macro
5)] // Kill clippy for MSRV
6use alloc::{borrow::ToOwned, string::String};
7use core::fmt::Formatter;
8use core::{fmt::Display, str::FromStr};
9
10///
11/// The result of FromStr::from_str, when parsing a field (other than vendor),
12///  with a value that is not known to the library
13#[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///
23/// The Architecture field of a target tuple
24#[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    /// Used for ABI Purposes with lccc
66    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    /// Parses the Architecture in a "lossy" manner
133    /// This is equivalent to [`Self::from_str`], but returns [`Architecture::Unknown`], instead of an error,
134    ///  on an unknown architecture.
135    /// This is useful (in conjunction with an actual target name)
136    pub fn parse(st: &str) -> Self {
137        Self::from_str(st).unwrap_or(Architecture::Unknown)
138    }
139
140    ///
141    /// Returns the canonical name of the target
142    /// The canonical name, when passed into `[`Self::parse`] will yield an equivalent value,
143    /// Formatting an Architecture yields this string
144    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///
205/// The Vendor field of a target tuple
206///
207#[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    /// Used for ABI Purposes with lccc
228    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            // "nes" => Self::NES,
241            // "snes" | "snesdev" => Self::SNES,
242            "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    /// Parses the Vendor in a "lossy" manner
268    /// This is equivalent to [`Self::from_str`].
269    /// Note that an unknown vendor is not considered an error.
270    pub fn parse(s: &str) -> Self {
271        Self::from_str(s).unwrap()
272    }
273
274    ///
275    /// Returns the canonical name of the vendor
276    /// The canonical name, when passed into `[`Self::parse`] will yield an equivalent value,
277    /// Formatting a Vendor yields this string
278    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///
303/// The Operating System Field of a target tuple
304#[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, // Not an OS, but the currently config.sub places it in the os field
346    NES = 38,  // likewise
347    None = 39, // No OS
348    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    /// Parses the OS in a "lossy" manner
416    /// This is equivalent to [`Self::from_str`], except that [`OS::Unknown`] is returned, instead of an error, on an unknown OS Field
417    pub fn parse(s: &str) -> Self {
418        Self::from_str(s).unwrap_or(Self::Unknown)
419    }
420
421    ///
422    /// Returns the canonical name of the operating system
423    /// The canonical name, when passed into `[`Self::parse`] will yield an equivalent value,
424    /// Formatting an OS yields this string
425    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///
476/// The Environment field of target tuples
477#[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    /// Parses the Environment name in a "lossy" manner
549    /// This is equivalent to [`Self::from_str`], except that [`Environment::Unknown`] is returned, instead of an error, on an unknown OS Field
550    pub fn parse(s: &str) -> Self {
551        Self::from_str(s).unwrap_or(Self::Unknown)
552    }
553
554    ///
555    /// Returns the canonical name of the environment
556    /// The canonical name, when passed into [`Self::parse`] will yield an equivalent value,
557    /// Formatting an Environment yields this string
558    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///
589/// The object format used by a target
590#[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    /// Parses the ObjectFormat name in a "lossy" manner, from the end of the Environment field
639    /// This is equivalent to [`Self::from_str`], except that [`ObjectFormat::Unknown`] is returned, instead of an error, on an unknown OS Field
640    pub fn parse(s: &str) -> Self {
641        Self::from_str(s).unwrap_or(Self::Unknown)
642    }
643
644    ///
645    /// Returns the canonical name of the object format
646    /// The canonical name, when passed into [`Self::parse`] will yield an equivalent value,
647    /// Formatting an ObjectFormat yields this string
648    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///
667/// The representation of a target tuple.
668///
669/// A Target Tuple is of the form arch-vendor-system, where system can be either os-env
670///  or simply either os or env (the latter is used in the case of a freestanding target).
671///
672/// There are two types of target tuple: canonical and exact.
673/// This type can be used to represent both.
674///
675/// The [`core::fmt::Display`] implementation will display the canonical tuple;
676///  the function [`Self::get_name`] extracts the exact form that was parsed.
677/// In any case, if any field, other than vendor, is unknown, or the form is not the one above,
678///  the [`core::str::FromStr`] implementation will yield an UnknownError.
679///
680#[derive(Clone, Debug)]
681pub struct Target {
682    full: String,
683    arch: Architecture,
684    vendor: Option<Vendor>,
685    // Invariant:
686    // At least one of these fields is Some
687    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    ///
840    /// Gets the exact name of the target tuple.
841    pub fn get_name(&self) -> &str {
842        &self.full
843    }
844
845    ///
846    /// Returns the architecture name
847    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    /// Gets the entire sys component
860    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    /// Parses a target tuple of the form arch-vendor-system (where system is either os-env, os, or env).
871    /// If a field is not known, it is left as unknown, and the original value will be available
872    ///  through the exact name.
873    ///
874    /// Panics if s is not of the above form
875    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    ///
970    /// Gets the value of the `os` field
971    pub fn operating_system(&self) -> Option<OS> {
972        self.os
973    }
974
975    ///
976    /// Gets the value of the `env` field, or unknown if the environment was omitted
977    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    ///
1022    /// Constructs a target tuple in canonical form from the specified components.
1023    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    ///
1043    /// Constructs a target tuple in canonical form from the specified components.
1044    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    ///
1072    /// Gets the object format, either from the end of the `env` field, or the default for the target
1073    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    /// Gets the object format component from the end of the env component, or None if none is present
1099    pub fn object_format(&self) -> Option<ObjectFormat> {
1100        self.objfmt
1101    }
1102
1103    ///
1104    /// Gets the value of the Architecture field
1105    pub fn arch(&self) -> Architecture {
1106        self.arch
1107    }
1108
1109    ///
1110    /// Gets the value of the vendor field.
1111    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///
1131/// Parses a target tuple from an environment variable.
1132#[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}