Skip to main content

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    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    /// Parses the OS in a "lossy" manner
418    /// This is equivalent to [`Self::from_str`], except that [`OS::Unknown`] is returned, instead of an error, on an unknown OS Field
419    pub fn parse(s: &str) -> Self {
420        Self::from_str(s).unwrap_or(Self::Unknown)
421    }
422
423    ///
424    /// Returns the canonical name of the operating system
425    /// The canonical name, when passed into `[`Self::parse`] will yield an equivalent value,
426    /// Formatting an OS yields this string
427    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///
479/// The Environment field of target tuples
480#[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    /// Parses the Environment name in a "lossy" manner
561    /// This is equivalent to [`Self::from_str`], except that [`Environment::Unknown`] is returned, instead of an error, on an unknown OS Field
562    pub fn parse(s: &str) -> Self {
563        Self::from_str(s).unwrap_or(Self::Unknown)
564    }
565
566    ///
567    /// Returns the canonical name of the environment
568    /// The canonical name, when passed into [`Self::parse`] will yield an equivalent value,
569    /// Formatting an Environment yields this string
570    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///
605/// The object format used by a target
606#[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    /// Parses the ObjectFormat name in a "lossy" manner, from the end of the Environment field
655    /// This is equivalent to [`Self::from_str`], except that [`ObjectFormat::Unknown`] is returned, instead of an error, on an unknown OS Field
656    pub fn parse(s: &str) -> Self {
657        Self::from_str(s).unwrap_or(Self::Unknown)
658    }
659
660    ///
661    /// Returns the canonical name of the object format
662    /// The canonical name, when passed into [`Self::parse`] will yield an equivalent value,
663    /// Formatting an ObjectFormat yields this string
664    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///
683/// The representation of a target tuple.
684///
685/// A Target Tuple is of the form arch-vendor-system, where system can be either os-env
686///  or simply either os or env (the latter is used in the case of a freestanding target).
687///
688/// There are two types of target tuple: canonical and exact.
689/// This type can be used to represent both.
690///
691/// The [`core::fmt::Display`] implementation will display the canonical tuple;
692///  the function [`Self::get_name`] extracts the exact form that was parsed.
693/// In any case, if any field, other than vendor, is unknown, or the form is not the one above,
694///  the [`core::str::FromStr`] implementation will yield an UnknownError.
695///
696#[derive(Clone, Debug)]
697pub struct Target {
698    full: String,
699    arch: Architecture,
700    vendor: Option<Vendor>,
701    // Invariant:
702    // At least one of these fields is Some
703    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    ///
856    /// Gets the exact name of the target tuple.
857    pub fn get_name(&self) -> &str {
858        &self.full
859    }
860
861    ///
862    /// Returns the architecture name
863    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    /// Gets the entire sys component
876    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    /// Parses a target tuple of the form arch-vendor-system (where system is either os-env, os, or env).
887    /// If a field is not known, it is left as unknown, and the original value will be available
888    ///  through the exact name.
889    ///
890    /// Panics if s is not of the above form
891    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    ///
986    /// Gets the value of the `os` field
987    pub fn operating_system(&self) -> Option<OS> {
988        self.os
989    }
990
991    ///
992    /// Gets the value of the `env` field, or unknown if the environment was omitted
993    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    ///
1038    /// Constructs a target tuple in canonical form from the specified components.
1039    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    ///
1059    /// Constructs a target tuple in canonical form from the specified components.
1060    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    ///
1088    /// Gets the object format, either from the end of the `env` field, or the default for the target
1089    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    /// Gets the object format component from the end of the env component, or None if none is present
1115    pub fn object_format(&self) -> Option<ObjectFormat> {
1116        self.objfmt
1117    }
1118
1119    ///
1120    /// Gets the value of the Architecture field
1121    pub fn arch(&self) -> Architecture {
1122        self.arch
1123    }
1124
1125    ///
1126    /// Gets the value of the vendor field.
1127    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///
1147/// Parses a target tuple from an environment variable.
1148#[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}