target_lexicon/
targets.rs

1// This file defines all the identifier enums and target-aware logic.
2
3use crate::triple::{Endianness, PointerWidth, Triple};
4use alloc::borrow::Cow;
5use alloc::boxed::Box;
6use alloc::format;
7use alloc::string::String;
8use core::fmt;
9use core::hash::{Hash, Hasher};
10use core::str::FromStr;
11
12/// The "architecture" field, which in some cases also specifies a specific
13/// subarchitecture.
14#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
15#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16#[allow(missing_docs)]
17pub enum Architecture {
18    Unknown,
19    Arm(ArmArchitecture),
20    AmdGcn,
21    Aarch64(Aarch64Architecture),
22    Asmjs,
23    Avr,
24    Bpfeb,
25    Bpfel,
26    Hexagon,
27    X86_32(X86_32Architecture),
28    M68k,
29    LoongArch64,
30    Mips32(Mips32Architecture),
31    Mips64(Mips64Architecture),
32    Msp430,
33    Nvptx64,
34    Pulley32,
35    Pulley64,
36    Pulley32be,
37    Pulley64be,
38    Powerpc,
39    Powerpc64,
40    Powerpc64le,
41    Riscv32(Riscv32Architecture),
42    Riscv64(Riscv64Architecture),
43    S390x,
44    Sparc,
45    Sparc64,
46    Sparcv9,
47    Wasm32,
48    Wasm64,
49    X86_64,
50    /// x86_64 target that only supports Haswell-compatible Intel chips.
51    X86_64h,
52    XTensa,
53    Clever(CleverArchitecture),
54    /// A software machine that produces zero-knowledge proofs of the execution.
55    ///
56    /// See https://wiki.polygon.technology/docs/category/zk-assembly/
57    #[cfg(feature = "arch_zkasm")]
58    ZkAsm,
59    #[cfg(feature = "arch_z80")]
60    Z80(Z80Architecture),
61}
62
63#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
64#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
65#[allow(missing_docs)]
66pub enum ArmArchitecture {
67    Arm, // Generic arm
68    Armeb,
69    Armv4,
70    Armv4t,
71    Armv5t,
72    Armv5te,
73    Armv5tej,
74    Armv6,
75    Armv6j,
76    Armv6k,
77    Armv6z,
78    Armv6kz,
79    Armv6t2,
80    Armv6m,
81    Armv7,
82    Armv7a,
83    Armv7k,
84    Armv7ve,
85    Armv7m,
86    Armv7r,
87    Armv7s,
88    Armv8,
89    Armv8a,
90    Armv8_1a,
91    Armv8_2a,
92    Armv8_3a,
93    Armv8_4a,
94    Armv8_5a,
95    Armv8mBase,
96    Armv8mMain,
97    Armv8r,
98
99    Armebv7r,
100
101    Thumbeb,
102    Thumbv4t,
103    Thumbv5te,
104    Thumbv6m,
105    Thumbv7a,
106    Thumbv7em,
107    Thumbv7m,
108    Thumbv7neon,
109    Thumbv8mBase,
110    Thumbv8mMain,
111}
112
113#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
114#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
115#[allow(missing_docs)]
116pub enum Aarch64Architecture {
117    Aarch64,
118    Aarch64be,
119}
120
121// #[cfg_attr(feature = "rust_1_40", non_exhaustive)]
122// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
123// #[allow(missing_docs)]
124// pub enum ArmFpu {
125//     Vfp,
126//     Vfpv2,
127//     Vfpv3,
128//     Vfpv3Fp16,
129//     Vfpv3Xd,
130//     Vfpv3XdFp16,
131//     Neon,
132//     NeonVfpv3,
133//     NeonVfpv4,
134//     Vfpv4,
135//     Vfpv4D16,
136//     Fpv4SpD16,
137//     Fpv5SpD16,
138//     Fpv5D16,
139//     FpArmv8,
140//     NeonFpArmv8,
141//     CryptoNeonFpArmv8,
142// }
143
144impl ArmArchitecture {
145    /// Test if this architecture uses the Thumb instruction set.
146    #[rustfmt::skip]
147    pub fn is_thumb(self) -> bool {
148        use ArmArchitecture::*;
149
150        match self {
151            Arm
152            | Armeb
153            | Armv4
154            | Armv4t
155            | Armv5t
156            | Armv5te
157            | Armv5tej
158            | Armv6
159            | Armv6j
160            | Armv6k
161            | Armv6z
162            | Armv6kz
163            | Armv6t2
164            | Armv6m
165            | Armv7
166            | Armv7a
167            | Armv7k
168            | Armv7ve
169            | Armv7m
170            | Armv7r
171            | Armv7s
172            | Armv8
173            | Armv8a
174            | Armv8_1a
175            | Armv8_2a
176            | Armv8_3a
177            | Armv8_4a
178            | Armv8_5a
179            | Armv8mBase
180            | Armv8mMain
181            | Armv8r
182            | Armebv7r => false,
183            Thumbeb
184            | Thumbv4t
185            | Thumbv5te
186            | Thumbv6m
187            | Thumbv7a
188            | Thumbv7em
189            | Thumbv7m
190            | Thumbv7neon
191            | Thumbv8mBase
192            | Thumbv8mMain => true,
193        }
194    }
195
196    // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> {
197
198    // }
199
200    /// Return the pointer bit width of this target's architecture.
201    #[rustfmt::skip]
202    pub fn pointer_width(self) -> PointerWidth {
203        use ArmArchitecture::*;
204
205        match self {
206            Arm
207            | Armeb
208            | Armv4
209            | Armv4t
210            | Armv5t
211            | Armv5te
212            | Armv5tej
213            | Armv6
214            | Armv6j
215            | Armv6k
216            | Armv6z
217            | Armv6kz
218            | Armv6t2
219            | Armv6m
220            | Armv7
221            | Armv7a
222            | Armv7k
223            | Armv7ve
224            | Armv7m
225            | Armv7r
226            | Armv7s
227            | Armv8
228            | Armv8a
229            | Armv8_1a
230            | Armv8_2a
231            | Armv8_3a
232            | Armv8_4a
233            | Armv8_5a
234            | Armv8mBase
235            | Armv8mMain
236            | Armv8r
237            | Armebv7r
238            | Thumbeb
239            | Thumbv4t
240            | Thumbv5te
241            | Thumbv6m
242            | Thumbv7a
243            | Thumbv7em
244            | Thumbv7m
245            | Thumbv7neon
246            | Thumbv8mBase
247            | Thumbv8mMain => PointerWidth::U32,
248        }
249    }
250
251    /// Return the endianness of this architecture.
252    #[rustfmt::skip]
253    pub fn endianness(self) -> Endianness {
254        use ArmArchitecture::*;
255
256        match self {
257            Arm
258            | Armv4
259            | Armv4t
260            | Armv5t
261            | Armv5te
262            | Armv5tej
263            | Armv6
264            | Armv6j
265            | Armv6k
266            | Armv6z
267            | Armv6kz
268            | Armv6t2
269            | Armv6m
270            | Armv7
271            | Armv7a
272            | Armv7k
273            | Armv7ve
274            | Armv7m
275            | Armv7r
276            | Armv7s
277            | Armv8
278            | Armv8a
279            | Armv8_1a
280            | Armv8_2a
281            | Armv8_3a
282            | Armv8_4a
283            | Armv8_5a
284            | Armv8mBase
285            | Armv8mMain
286            | Armv8r
287            | Thumbv4t
288            | Thumbv5te
289            | Thumbv6m
290            | Thumbv7a
291            | Thumbv7em
292            | Thumbv7m
293            | Thumbv7neon
294            | Thumbv8mBase
295            | Thumbv8mMain => Endianness::Little,
296            Armeb | Armebv7r | Thumbeb => Endianness::Big,
297        }
298    }
299
300    /// Convert into a string
301    pub fn into_str(self) -> Cow<'static, str> {
302        use ArmArchitecture::*;
303
304        match self {
305            Arm => Cow::Borrowed("arm"),
306            Armeb => Cow::Borrowed("armeb"),
307            Armv4 => Cow::Borrowed("armv4"),
308            Armv4t => Cow::Borrowed("armv4t"),
309            Armv5t => Cow::Borrowed("armv5t"),
310            Armv5te => Cow::Borrowed("armv5te"),
311            Armv5tej => Cow::Borrowed("armv5tej"),
312            Armv6 => Cow::Borrowed("armv6"),
313            Armv6j => Cow::Borrowed("armv6j"),
314            Armv6k => Cow::Borrowed("armv6k"),
315            Armv6z => Cow::Borrowed("armv6z"),
316            Armv6kz => Cow::Borrowed("armv6kz"),
317            Armv6t2 => Cow::Borrowed("armv6t2"),
318            Armv6m => Cow::Borrowed("armv6m"),
319            Armv7 => Cow::Borrowed("armv7"),
320            Armv7a => Cow::Borrowed("armv7a"),
321            Armv7k => Cow::Borrowed("armv7k"),
322            Armv7ve => Cow::Borrowed("armv7ve"),
323            Armv7m => Cow::Borrowed("armv7m"),
324            Armv7r => Cow::Borrowed("armv7r"),
325            Armv7s => Cow::Borrowed("armv7s"),
326            Armv8 => Cow::Borrowed("armv8"),
327            Armv8a => Cow::Borrowed("armv8a"),
328            Armv8_1a => Cow::Borrowed("armv8.1a"),
329            Armv8_2a => Cow::Borrowed("armv8.2a"),
330            Armv8_3a => Cow::Borrowed("armv8.3a"),
331            Armv8_4a => Cow::Borrowed("armv8.4a"),
332            Armv8_5a => Cow::Borrowed("armv8.5a"),
333            Armv8mBase => Cow::Borrowed("armv8m.base"),
334            Armv8mMain => Cow::Borrowed("armv8m.main"),
335            Armv8r => Cow::Borrowed("armv8r"),
336            Thumbeb => Cow::Borrowed("thumbeb"),
337            Thumbv4t => Cow::Borrowed("thumbv4t"),
338            Thumbv5te => Cow::Borrowed("thumbv5te"),
339            Thumbv6m => Cow::Borrowed("thumbv6m"),
340            Thumbv7a => Cow::Borrowed("thumbv7a"),
341            Thumbv7em => Cow::Borrowed("thumbv7em"),
342            Thumbv7m => Cow::Borrowed("thumbv7m"),
343            Thumbv7neon => Cow::Borrowed("thumbv7neon"),
344            Thumbv8mBase => Cow::Borrowed("thumbv8m.base"),
345            Thumbv8mMain => Cow::Borrowed("thumbv8m.main"),
346            Armebv7r => Cow::Borrowed("armebv7r"),
347        }
348    }
349}
350
351impl Aarch64Architecture {
352    /// Test if this architecture uses the Thumb instruction set.
353    pub fn is_thumb(self) -> bool {
354        match self {
355            Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => false,
356        }
357    }
358
359    // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> {
360
361    // }
362
363    /// Return the pointer bit width of this target's architecture.
364    ///
365    /// This function is only aware of the CPU architecture so it is not aware
366    /// of ilp32 ABIs.
367    pub fn pointer_width(self) -> PointerWidth {
368        match self {
369            Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => PointerWidth::U64,
370        }
371    }
372
373    /// Return the endianness of this architecture.
374    pub fn endianness(self) -> Endianness {
375        match self {
376            Aarch64Architecture::Aarch64 => Endianness::Little,
377            Aarch64Architecture::Aarch64be => Endianness::Big,
378        }
379    }
380
381    /// Convert into a string
382    pub fn into_str(self) -> Cow<'static, str> {
383        use Aarch64Architecture::*;
384
385        match self {
386            Aarch64 => Cow::Borrowed("aarch64"),
387            Aarch64be => Cow::Borrowed("aarch64_be"),
388        }
389    }
390}
391
392#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
393#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
394#[allow(missing_docs)]
395pub enum CleverArchitecture {
396    Clever,
397    Clever1_0,
398}
399
400impl CleverArchitecture {
401    /// Convert into a string
402    pub fn into_str(self) -> Cow<'static, str> {
403        use CleverArchitecture::*;
404
405        match self {
406            Clever => Cow::Borrowed("clever"),
407            Clever1_0 => Cow::Borrowed("clever1.0"),
408        }
409    }
410}
411
412/// An enum for all 32-bit RISC-V architectures.
413#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
414#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
415#[allow(missing_docs)]
416pub enum Riscv32Architecture {
417    Riscv32,
418    Riscv32gc,
419    Riscv32i,
420    Riscv32im,
421    Riscv32ima,
422    Riscv32imac,
423    Riscv32imafc,
424    Riscv32imc,
425}
426
427impl Riscv32Architecture {
428    /// Convert into a string
429    pub fn into_str(self) -> Cow<'static, str> {
430        use Riscv32Architecture::*;
431
432        match self {
433            Riscv32 => Cow::Borrowed("riscv32"),
434            Riscv32gc => Cow::Borrowed("riscv32gc"),
435            Riscv32i => Cow::Borrowed("riscv32i"),
436            Riscv32im => Cow::Borrowed("riscv32im"),
437            Riscv32ima => Cow::Borrowed("riscv32ima"),
438            Riscv32imac => Cow::Borrowed("riscv32imac"),
439            Riscv32imafc => Cow::Borrowed("riscv32imafc"),
440            Riscv32imc => Cow::Borrowed("riscv32imc"),
441        }
442    }
443}
444
445/// An enum for all 64-bit RISC-V architectures.
446#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
447#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
448#[allow(missing_docs)]
449pub enum Riscv64Architecture {
450    Riscv64,
451    Riscv64gc,
452    Riscv64imac,
453    Riscv64a23,
454}
455
456impl Riscv64Architecture {
457    /// Convert into a string
458    pub fn into_str(self) -> Cow<'static, str> {
459        use Riscv64Architecture::*;
460
461        match self {
462            Riscv64 => Cow::Borrowed("riscv64"),
463            Riscv64gc => Cow::Borrowed("riscv64gc"),
464            Riscv64imac => Cow::Borrowed("riscv64imac"),
465            Riscv64a23 => Cow::Borrowed("riscv64a23"),
466        }
467    }
468}
469
470/// An enum for all 32-bit x86 architectures.
471#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
472#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
473#[allow(missing_docs)]
474pub enum X86_32Architecture {
475    I386,
476    I586,
477    I686,
478}
479
480impl X86_32Architecture {
481    /// Convert into a string
482    pub fn into_str(self) -> Cow<'static, str> {
483        use X86_32Architecture::*;
484
485        match self {
486            I386 => Cow::Borrowed("i386"),
487            I586 => Cow::Borrowed("i586"),
488            I686 => Cow::Borrowed("i686"),
489        }
490    }
491}
492
493/// An enum for all 32-bit MIPS architectures (not just "MIPS32").
494#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
495#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
496#[allow(missing_docs)]
497pub enum Mips32Architecture {
498    Mips,
499    Mipsel,
500    Mipsisa32r6,
501    Mipsisa32r6el,
502}
503
504impl Mips32Architecture {
505    /// Convert into a string
506    pub fn into_str(self) -> Cow<'static, str> {
507        use Mips32Architecture::*;
508
509        match self {
510            Mips => Cow::Borrowed("mips"),
511            Mipsel => Cow::Borrowed("mipsel"),
512            Mipsisa32r6 => Cow::Borrowed("mipsisa32r6"),
513            Mipsisa32r6el => Cow::Borrowed("mipsisa32r6el"),
514        }
515    }
516}
517
518/// An enum for all 64-bit MIPS architectures (not just "MIPS64").
519#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
520#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
521#[allow(missing_docs)]
522pub enum Mips64Architecture {
523    Mips64,
524    Mips64el,
525    Mipsisa64r6,
526    Mipsisa64r6el,
527}
528
529impl Mips64Architecture {
530    /// Convert into a string
531    pub fn into_str(self) -> Cow<'static, str> {
532        use Mips64Architecture::*;
533
534        match self {
535            Mips64 => Cow::Borrowed("mips64"),
536            Mips64el => Cow::Borrowed("mips64el"),
537            Mipsisa64r6 => Cow::Borrowed("mipsisa64r6"),
538            Mipsisa64r6el => Cow::Borrowed("mipsisa64r6el"),
539        }
540    }
541}
542
543#[cfg(feature = "arch_z80")]
544#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
545#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
546#[allow(missing_docs)]
547pub enum Z80Architecture {
548    Z80,
549    Z180,
550    Ez80,
551    Sm83,
552    Rabbit2000,
553    Rabbit2000A,
554    Rabbit3000,
555    Rabbit3000A,
556    Tlcs90,
557    R800,
558}
559
560#[cfg(feature = "arch_z80")]
561impl Z80Architecture {
562    pub fn into_str(self) -> Cow<'static, str> {
563        use Z80Architecture::*;
564
565        match self {
566            Z80 => Cow::Borrowed("z80"),
567            Z180 => Cow::Borrowed("z180"),
568            Ez80 => Cow::Borrowed("ez80"),
569            Sm83 => Cow::Borrowed("sm83"),
570            Rabbit2000 => Cow::Borrowed("rabbit2000"),
571            Rabbit2000A => Cow::Borrowed("rabbit2000a"),
572            Rabbit3000 => Cow::Borrowed("rabbit3000"),
573            Rabbit3000A => Cow::Borrowed("rabbit3000a"),
574            Tlcs90 => Cow::Borrowed("tlcs90"),
575            R800 => Cow::Borrowed("r800"),
576        }
577    }
578}
579
580/// A string for a `Vendor::Custom` that can either be used in `const`
581/// contexts or hold dynamic strings.
582#[derive(Clone, Debug, Eq)]
583pub enum CustomVendor {
584    /// An owned `String`. This supports the general case.
585    Owned(Box<String>),
586    /// A static `str`, so that `CustomVendor` can be constructed in `const`
587    /// contexts.
588    Static(&'static str),
589}
590
591impl CustomVendor {
592    /// Extracts a string slice.
593    pub fn as_str(&self) -> &str {
594        match self {
595            CustomVendor::Owned(s) => s,
596            CustomVendor::Static(s) => s,
597        }
598    }
599}
600
601impl PartialEq for CustomVendor {
602    fn eq(&self, other: &Self) -> bool {
603        self.as_str() == other.as_str()
604    }
605}
606
607impl Hash for CustomVendor {
608    fn hash<H: Hasher>(&self, state: &mut H) {
609        self.as_str().hash(state)
610    }
611}
612
613/// The "vendor" field, which in practice is little more than an arbitrary
614/// modifier.
615#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
616#[derive(Clone, Debug, PartialEq, Eq, Hash)]
617#[allow(missing_docs)]
618pub enum Vendor {
619    Unknown,
620    Amd,
621    Apple,
622    Espressif,
623    Experimental,
624    Fortanix,
625    Ibm,
626    Kmc,
627    Nintendo,
628    Nvidia,
629    Pc,
630    Rumprun,
631    Sun,
632    Uwp,
633    Wrs,
634
635    /// A custom vendor. "Custom" in this context means that the vendor is
636    /// not specifically recognized by upstream Autotools, LLVM, Rust, or other
637    /// relevant authorities on triple naming. It's useful for people building
638    /// and using locally patched toolchains.
639    ///
640    /// Outside of such patched environments, users of `target-lexicon` should
641    /// treat `Custom` the same as `Unknown` and ignore the string.
642    Custom(CustomVendor),
643}
644
645impl Vendor {
646    /// Extracts a string slice.
647    pub fn as_str(&self) -> &str {
648        use Vendor::*;
649
650        match self {
651            Unknown => "unknown",
652            Amd => "amd",
653            Apple => "apple",
654            Espressif => "espressif",
655            Experimental => "experimental",
656            Fortanix => "fortanix",
657            Ibm => "ibm",
658            Kmc => "kmc",
659            Nintendo => "nintendo",
660            Nvidia => "nvidia",
661            Pc => "pc",
662            Rumprun => "rumprun",
663            Sun => "sun",
664            Uwp => "uwp",
665            Wrs => "wrs",
666            Custom(name) => name.as_str(),
667        }
668    }
669}
670
671/// The minimum OS version that we're compiling for.
672///
673/// This is formatted as `"major.minor.patch"`.
674///
675/// The size of the parts here are limited by Mach-O's `LC_BUILD_VERSION`.
676#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
677#[allow(missing_docs)]
678pub struct DeploymentTarget {
679    pub major: u16,
680    pub minor: u8,
681    pub patch: u8,
682}
683
684/// The "operating system" field, which sometimes implies an environment, and
685/// sometimes isn't an actual operating system.
686///
687/// LLVM's Apple triples may optionally include the [deployment target].
688///
689/// [deployment target]: DeploymentTarget
690#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
691#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
692#[allow(missing_docs)]
693pub enum OperatingSystem {
694    Unknown,
695    Aix,
696    AmdHsa,
697    Bitrig,
698    Cloudabi,
699    Cuda,
700    Cygwin,
701    /// The general [Darwin][darwin-wiki] core OS.
702    ///
703    /// Generally, `-mmacosx-version-min=...` or similar flags are required by
704    /// Clang to determine the actual OS (either macOS, iOS, tvOS, watchOS or
705    /// visionOS).
706    ///
707    /// WARNING: When parsing `rustc` target triples, this matches the macOS
708    /// target triples as well.
709    ///
710    /// [darwin-wiki]: https://en.wikipedia.org/wiki/Darwin_(operating_system)
711    Darwin(Option<DeploymentTarget>),
712    Dragonfly,
713    Emscripten,
714    Espidf,
715    Freebsd,
716    Fuchsia,
717    Haiku,
718    Hermit,
719    Horizon,
720    Hurd,
721    Illumos,
722    IOS(Option<DeploymentTarget>),
723    L4re,
724    Linux,
725    /// macOS.
726    ///
727    /// WARNING: This does _not_ match the macOS triples when parsing `rustc`
728    /// target triples, for that see the [`darwin`](Self::Darwin) OS name.
729    MacOSX(Option<DeploymentTarget>),
730    Nebulet,
731    Netbsd,
732    None_,
733    Openbsd,
734    Psp,
735    Redox,
736    Solaris,
737    SolidAsp3,
738    TvOS(Option<DeploymentTarget>),
739    Uefi,
740    VisionOS(Option<DeploymentTarget>),
741    VxWorks,
742    Wasi,
743    WasiP1,
744    WasiP2,
745    WatchOS(Option<DeploymentTarget>),
746    Windows,
747    /// An alternate name for [visionOS][Self::VisionOS].
748    XROS(Option<DeploymentTarget>),
749}
750
751impl OperatingSystem {
752    /// Convert into a string
753    pub fn into_str(self) -> Cow<'static, str> {
754        use OperatingSystem::*;
755
756        let darwin_version = |name, deployment_target| {
757            if let Some(DeploymentTarget {
758                major,
759                minor,
760                patch,
761            }) = deployment_target
762            {
763                Cow::Owned(format!("{}{}.{}.{}", name, major, minor, patch))
764            } else {
765                Cow::Borrowed(name)
766            }
767        };
768
769        match self {
770            Unknown => Cow::Borrowed("unknown"),
771            Aix => Cow::Borrowed("aix"),
772            AmdHsa => Cow::Borrowed("amdhsa"),
773            Bitrig => Cow::Borrowed("bitrig"),
774            Cloudabi => Cow::Borrowed("cloudabi"),
775            Cuda => Cow::Borrowed("cuda"),
776            Cygwin => Cow::Borrowed("cygwin"),
777            Darwin(deployment_target) => darwin_version("darwin", deployment_target),
778            Dragonfly => Cow::Borrowed("dragonfly"),
779            Emscripten => Cow::Borrowed("emscripten"),
780            Espidf => Cow::Borrowed("espidf"),
781            Freebsd => Cow::Borrowed("freebsd"),
782            Fuchsia => Cow::Borrowed("fuchsia"),
783            Haiku => Cow::Borrowed("haiku"),
784            Hermit => Cow::Borrowed("hermit"),
785            Horizon => Cow::Borrowed("horizon"),
786            Hurd => Cow::Borrowed("hurd"),
787            Illumos => Cow::Borrowed("illumos"),
788            IOS(deployment_target) => darwin_version("ios", deployment_target),
789            L4re => Cow::Borrowed("l4re"),
790            Linux => Cow::Borrowed("linux"),
791            MacOSX(deployment_target) => darwin_version("macosx", deployment_target),
792            Nebulet => Cow::Borrowed("nebulet"),
793            Netbsd => Cow::Borrowed("netbsd"),
794            None_ => Cow::Borrowed("none"),
795            Openbsd => Cow::Borrowed("openbsd"),
796            Psp => Cow::Borrowed("psp"),
797            Redox => Cow::Borrowed("redox"),
798            Solaris => Cow::Borrowed("solaris"),
799            SolidAsp3 => Cow::Borrowed("solid_asp3"),
800            TvOS(deployment_target) => darwin_version("tvos", deployment_target),
801            Uefi => Cow::Borrowed("uefi"),
802            VxWorks => Cow::Borrowed("vxworks"),
803            VisionOS(deployment_target) => darwin_version("visionos", deployment_target),
804            Wasi => Cow::Borrowed("wasi"),
805            WasiP1 => Cow::Borrowed("wasip1"),
806            WasiP2 => Cow::Borrowed("wasip2"),
807            WatchOS(deployment_target) => darwin_version("watchos", deployment_target),
808            Windows => Cow::Borrowed("windows"),
809            XROS(deployment_target) => darwin_version("xros", deployment_target),
810        }
811    }
812
813    /// Whether the OS is similar to Darwin.
814    ///
815    /// This matches on any of:
816    /// - [Darwin](Self::Darwin)
817    /// - [iOS](Self::IOS)
818    /// - [macOS](Self::MacOSX)
819    /// - [tvOS](Self::TvOS)
820    /// - [visionOS](Self::VisionOS)
821    /// - [watchOS](Self::WatchOS)
822    /// - [xrOS](Self::XROS)
823    pub fn is_like_darwin(&self) -> bool {
824        use OperatingSystem::*;
825
826        match self {
827            Darwin(_) | IOS(_) | MacOSX(_) | TvOS(_) | VisionOS(_) | WatchOS(_) | XROS(_) => true,
828            _ => false,
829        }
830    }
831}
832
833/// The "environment" field, which specifies an ABI environment on top of the
834/// operating system. In many configurations, this field is omitted, and the
835/// environment is implied by the operating system.
836#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
837#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
838#[allow(missing_docs)]
839pub enum Environment {
840    Unknown,
841    AmdGiz,
842    Android,
843    Androideabi,
844    Eabi,
845    Eabihf,
846    Gnu,
847    Gnuabi64,
848    Gnueabi,
849    Gnueabihf,
850    Gnuspe,
851    Gnux32,
852    GnuIlp32,
853    GnuLlvm,
854    HermitKernel,
855    HurdKernel,
856    LinuxKernel,
857    Macabi,
858    Musl,
859    Musleabi,
860    Musleabihf,
861    Muslabi64,
862    Msvc,
863    Newlib,
864    None,
865    Kernel,
866    Uclibc,
867    Uclibceabi,
868    Uclibceabihf,
869    Sgx,
870    Sim,
871    Softfloat,
872    Spe,
873    Threads,
874    Ohos,
875}
876
877impl Environment {
878    /// Convert into a string
879    pub fn into_str(self) -> Cow<'static, str> {
880        use Environment::*;
881
882        match self {
883            Unknown => Cow::Borrowed("unknown"),
884            AmdGiz => Cow::Borrowed("amdgiz"),
885            Android => Cow::Borrowed("android"),
886            Androideabi => Cow::Borrowed("androideabi"),
887            Eabi => Cow::Borrowed("eabi"),
888            Eabihf => Cow::Borrowed("eabihf"),
889            Gnu => Cow::Borrowed("gnu"),
890            Gnuabi64 => Cow::Borrowed("gnuabi64"),
891            Gnueabi => Cow::Borrowed("gnueabi"),
892            Gnueabihf => Cow::Borrowed("gnueabihf"),
893            Gnuspe => Cow::Borrowed("gnuspe"),
894            Gnux32 => Cow::Borrowed("gnux32"),
895            GnuIlp32 => Cow::Borrowed("gnu_ilp32"),
896            GnuLlvm => Cow::Borrowed("gnullvm"),
897            HermitKernel => Cow::Borrowed("hermitkernel"),
898            HurdKernel => Cow::Borrowed("hurdkernel"),
899            LinuxKernel => Cow::Borrowed("linuxkernel"),
900            Macabi => Cow::Borrowed("macabi"),
901            Musl => Cow::Borrowed("musl"),
902            Musleabi => Cow::Borrowed("musleabi"),
903            Musleabihf => Cow::Borrowed("musleabihf"),
904            Muslabi64 => Cow::Borrowed("muslabi64"),
905            Msvc => Cow::Borrowed("msvc"),
906            Newlib => Cow::Borrowed("newlib"),
907            None => Cow::Borrowed("none"),
908            Kernel => Cow::Borrowed("kernel"),
909            Uclibc => Cow::Borrowed("uclibc"),
910            Uclibceabi => Cow::Borrowed("uclibceabi"),
911            Uclibceabihf => Cow::Borrowed("uclibceabihf"),
912            Sgx => Cow::Borrowed("sgx"),
913            Sim => Cow::Borrowed("sim"),
914            Softfloat => Cow::Borrowed("softfloat"),
915            Spe => Cow::Borrowed("spe"),
916            Threads => Cow::Borrowed("threads"),
917            Ohos => Cow::Borrowed("ohos"),
918        }
919    }
920}
921
922/// The "binary format" field, which is usually omitted, and the binary format
923/// is implied by the other fields.
924#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
925#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
926#[allow(missing_docs)]
927pub enum BinaryFormat {
928    Unknown,
929    Elf,
930    Coff,
931    Macho,
932    Wasm,
933    Xcoff,
934}
935
936impl BinaryFormat {
937    /// Convert into a string
938    pub fn into_str(self) -> Cow<'static, str> {
939        use BinaryFormat::*;
940
941        match self {
942            Unknown => Cow::Borrowed("unknown"),
943            Elf => Cow::Borrowed("elf"),
944            Coff => Cow::Borrowed("coff"),
945            Macho => Cow::Borrowed("macho"),
946            Wasm => Cow::Borrowed("wasm"),
947            Xcoff => Cow::Borrowed("xcoff"),
948        }
949    }
950}
951
952impl Architecture {
953    /// Return the endianness of this architecture.
954    #[rustfmt::skip]
955    pub fn endianness(self) -> Result<Endianness, ()> {
956        use Architecture::*;
957
958        match self {
959            Unknown => Err(()),
960            Arm(arm) => Ok(arm.endianness()),
961            Aarch64(aarch) => Ok(aarch.endianness()),
962            AmdGcn
963            | Asmjs
964            | Avr
965            | Bpfel
966            | Hexagon
967            | X86_32(_)
968            | LoongArch64
969            | Mips64(Mips64Architecture::Mips64el)
970            | Mips32(Mips32Architecture::Mipsel)
971            | Mips32(Mips32Architecture::Mipsisa32r6el)
972            | Mips64(Mips64Architecture::Mipsisa64r6el)
973            | Msp430
974            | Nvptx64
975            | Pulley32
976            | Pulley64
977            | Powerpc64le
978            | Riscv32(_)
979            | Riscv64(_)
980            | Wasm32
981            | Wasm64
982            | X86_64
983            | X86_64h
984            | XTensa
985            | Clever(_) => Ok(Endianness::Little),
986            Bpfeb
987            | M68k
988            | Mips32(Mips32Architecture::Mips)
989            | Mips64(Mips64Architecture::Mips64)
990            | Mips32(Mips32Architecture::Mipsisa32r6)
991            | Mips64(Mips64Architecture::Mipsisa64r6)
992            | Powerpc
993            | Powerpc64
994            | Pulley32be
995            | Pulley64be
996            | S390x
997            | Sparc
998            | Sparc64
999            | Sparcv9 => Ok(Endianness::Big),
1000            #[cfg(feature="arch_zkasm")]
1001            ZkAsm => Ok(Endianness::Big),
1002            #[cfg(feature = "arch_z80")]
1003            Z80(_) => Ok(Endianness::Little),
1004        }
1005    }
1006
1007    /// Return the pointer bit width of this target's architecture.
1008    ///
1009    /// This function is only aware of the CPU architecture so it is not aware
1010    /// of ilp32 and x32 ABIs.
1011    #[rustfmt::skip]
1012    pub fn pointer_width(self) -> Result<PointerWidth, ()> {
1013        use Architecture::*;
1014
1015        match self {
1016            Unknown => Err(()),
1017            Avr | Msp430 => Ok(PointerWidth::U16),
1018            Arm(arm) => Ok(arm.pointer_width()),
1019            Aarch64(aarch) => Ok(aarch.pointer_width()),
1020            Asmjs
1021            | Hexagon
1022            | X86_32(_)
1023            | Riscv32(_)
1024            | Sparc
1025            | Wasm32
1026            | M68k
1027            | Mips32(_)
1028            | Pulley32
1029            | Pulley32be
1030            | Powerpc
1031            | XTensa => Ok(PointerWidth::U32),
1032            AmdGcn
1033            | Bpfeb
1034            | Bpfel
1035            | Powerpc64le
1036            | Riscv64(_)
1037            | X86_64
1038            | X86_64h
1039            | Mips64(_)
1040            | Nvptx64
1041            | Pulley64
1042            | Pulley64be
1043            | Powerpc64
1044            | S390x
1045            | Sparc64
1046            | Sparcv9
1047            | LoongArch64
1048            | Wasm64
1049            | Clever(_) => Ok(PointerWidth::U64),
1050            #[cfg(feature="arch_zkasm")]
1051            ZkAsm => Ok(PointerWidth::U64),
1052            #[cfg(feature = "arch_z80")]
1053            Z80(_) => Ok(PointerWidth::U16),
1054        }
1055    }
1056
1057    /// Checks if this Architecture is some variant of Clever-ISA
1058    pub fn is_clever(&self) -> bool {
1059        match self {
1060            Architecture::Clever(_) => true,
1061            _ => false,
1062        }
1063    }
1064
1065    /// Convert into a string
1066    pub fn into_str(self) -> Cow<'static, str> {
1067        use Architecture::*;
1068
1069        match self {
1070            Arm(arm) => arm.into_str(),
1071            Aarch64(aarch) => aarch.into_str(),
1072            Unknown => Cow::Borrowed("unknown"),
1073            AmdGcn => Cow::Borrowed("amdgcn"),
1074            Asmjs => Cow::Borrowed("asmjs"),
1075            Avr => Cow::Borrowed("avr"),
1076            Bpfeb => Cow::Borrowed("bpfeb"),
1077            Bpfel => Cow::Borrowed("bpfel"),
1078            Hexagon => Cow::Borrowed("hexagon"),
1079            X86_32(x86_32) => x86_32.into_str(),
1080            LoongArch64 => Cow::Borrowed("loongarch64"),
1081            M68k => Cow::Borrowed("m68k"),
1082            Mips32(mips32) => mips32.into_str(),
1083            Mips64(mips64) => mips64.into_str(),
1084            Msp430 => Cow::Borrowed("msp430"),
1085            Nvptx64 => Cow::Borrowed("nvptx64"),
1086            Pulley32 => Cow::Borrowed("pulley32"),
1087            Pulley64 => Cow::Borrowed("pulley64"),
1088            Pulley32be => Cow::Borrowed("pulley32be"),
1089            Pulley64be => Cow::Borrowed("pulley64be"),
1090            Powerpc => Cow::Borrowed("powerpc"),
1091            Powerpc64 => Cow::Borrowed("powerpc64"),
1092            Powerpc64le => Cow::Borrowed("powerpc64le"),
1093            Riscv32(riscv32) => riscv32.into_str(),
1094            Riscv64(riscv64) => riscv64.into_str(),
1095            S390x => Cow::Borrowed("s390x"),
1096            Sparc => Cow::Borrowed("sparc"),
1097            Sparc64 => Cow::Borrowed("sparc64"),
1098            Sparcv9 => Cow::Borrowed("sparcv9"),
1099            Wasm32 => Cow::Borrowed("wasm32"),
1100            Wasm64 => Cow::Borrowed("wasm64"),
1101            X86_64 => Cow::Borrowed("x86_64"),
1102            X86_64h => Cow::Borrowed("x86_64h"),
1103            XTensa => Cow::Borrowed("xtensa"),
1104            Clever(ver) => ver.into_str(),
1105            #[cfg(feature = "arch_zkasm")]
1106            ZkAsm => Cow::Borrowed("zkasm"),
1107            #[cfg(feature = "arch_z80")]
1108            Z80(z80) => z80.into_str(),
1109        }
1110    }
1111}
1112
1113/// Return the binary format implied by this target triple, ignoring its
1114/// `binary_format` field.
1115pub(crate) fn default_binary_format(triple: &Triple) -> BinaryFormat {
1116    match triple.operating_system {
1117        OperatingSystem::None_ => match triple.environment {
1118            Environment::Eabi | Environment::Eabihf => BinaryFormat::Elf,
1119            _ => BinaryFormat::Unknown,
1120        },
1121        OperatingSystem::Aix => BinaryFormat::Xcoff,
1122        os if os.is_like_darwin() => BinaryFormat::Macho,
1123        OperatingSystem::Windows => BinaryFormat::Coff,
1124        OperatingSystem::Nebulet
1125        | OperatingSystem::Emscripten
1126        | OperatingSystem::VxWorks
1127        | OperatingSystem::Wasi
1128        | OperatingSystem::Unknown => match triple.architecture {
1129            Architecture::Wasm32 | Architecture::Wasm64 => BinaryFormat::Wasm,
1130            Architecture::Unknown => BinaryFormat::Unknown,
1131            // Default to ELF, following `getDefaultFormat` in LLVM.
1132            _ => BinaryFormat::Elf,
1133        },
1134        _ => BinaryFormat::Elf,
1135    }
1136}
1137
1138impl fmt::Display for ArmArchitecture {
1139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1140        f.write_str(&self.into_str())
1141    }
1142}
1143
1144impl fmt::Display for Aarch64Architecture {
1145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1146        f.write_str(&self.into_str())
1147    }
1148}
1149
1150impl fmt::Display for CleverArchitecture {
1151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1152        f.write_str(&self.into_str())
1153    }
1154}
1155
1156impl fmt::Display for Riscv32Architecture {
1157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1158        f.write_str(&self.into_str())
1159    }
1160}
1161
1162impl fmt::Display for Riscv64Architecture {
1163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1164        f.write_str(&self.into_str())
1165    }
1166}
1167
1168impl fmt::Display for X86_32Architecture {
1169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1170        f.write_str(&self.into_str())
1171    }
1172}
1173
1174impl fmt::Display for Mips32Architecture {
1175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1176        f.write_str(&self.into_str())
1177    }
1178}
1179
1180impl fmt::Display for Mips64Architecture {
1181    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1182        f.write_str(&self.into_str())
1183    }
1184}
1185
1186#[cfg(feature = "arch_z80")]
1187impl fmt::Display for Z80Architecture {
1188    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1189        f.write_str(&self.into_str())
1190    }
1191}
1192
1193impl fmt::Display for Architecture {
1194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1195        f.write_str(&self.into_str())
1196    }
1197}
1198
1199impl FromStr for ArmArchitecture {
1200    type Err = ();
1201
1202    fn from_str(s: &str) -> Result<Self, ()> {
1203        use ArmArchitecture::*;
1204
1205        Ok(match s {
1206            "arm" => Arm,
1207            "armeb" => Armeb,
1208            "armv4" => Armv4,
1209            "armv4t" => Armv4t,
1210            "armv5t" => Armv5t,
1211            "armv5te" => Armv5te,
1212            "armv5tej" => Armv5tej,
1213            "armv6" => Armv6,
1214            "armv6j" => Armv6j,
1215            "armv6k" => Armv6k,
1216            "armv6z" => Armv6z,
1217            "armv6kz" => Armv6kz,
1218            "armv6t2" => Armv6t2,
1219            "armv6m" => Armv6m,
1220            "armv7" => Armv7,
1221            "armv7a" => Armv7a,
1222            "armv7k" => Armv7k,
1223            "armv7ve" => Armv7ve,
1224            "armv7m" => Armv7m,
1225            "armv7r" => Armv7r,
1226            "armv7s" => Armv7s,
1227            "armv8" => Armv8,
1228            "armv8a" => Armv8a,
1229            "armv8.1a" => Armv8_1a,
1230            "armv8.2a" => Armv8_2a,
1231            "armv8.3a" => Armv8_3a,
1232            "armv8.4a" => Armv8_4a,
1233            "armv8.5a" => Armv8_5a,
1234            "armv8m.base" => Armv8mBase,
1235            "armv8m.main" => Armv8mMain,
1236            "armv8r" => Armv8r,
1237            "thumbeb" => Thumbeb,
1238            "thumbv4t" => Thumbv4t,
1239            "thumbv5te" => Thumbv5te,
1240            "thumbv6m" => Thumbv6m,
1241            "thumbv7a" => Thumbv7a,
1242            "thumbv7em" => Thumbv7em,
1243            "thumbv7m" => Thumbv7m,
1244            "thumbv7neon" => Thumbv7neon,
1245            "thumbv8m.base" => Thumbv8mBase,
1246            "thumbv8m.main" => Thumbv8mMain,
1247            "armebv7r" => Armebv7r,
1248            _ => return Err(()),
1249        })
1250    }
1251}
1252
1253impl FromStr for Aarch64Architecture {
1254    type Err = ();
1255
1256    fn from_str(s: &str) -> Result<Self, ()> {
1257        use Aarch64Architecture::*;
1258
1259        Ok(match s {
1260            "aarch64" => Aarch64,
1261            "arm64" => Aarch64,
1262            "aarch64_be" => Aarch64be,
1263            _ => return Err(()),
1264        })
1265    }
1266}
1267
1268impl FromStr for CleverArchitecture {
1269    type Err = ();
1270    fn from_str(s: &str) -> Result<Self, ()> {
1271        match s {
1272            "clever" => Ok(CleverArchitecture::Clever),
1273            "clever1.0" => Ok(CleverArchitecture::Clever1_0),
1274            _ => Err(()),
1275        }
1276    }
1277}
1278
1279impl FromStr for Riscv32Architecture {
1280    type Err = ();
1281
1282    fn from_str(s: &str) -> Result<Self, ()> {
1283        use Riscv32Architecture::*;
1284
1285        Ok(match s {
1286            "riscv32" => Riscv32,
1287            "riscv32gc" => Riscv32gc,
1288            "riscv32i" => Riscv32i,
1289            "riscv32im" => Riscv32im,
1290            "riscv32ima" => Riscv32ima,
1291            "riscv32imac" => Riscv32imac,
1292            "riscv32imafc" => Riscv32imafc,
1293            "riscv32imc" => Riscv32imc,
1294            _ => return Err(()),
1295        })
1296    }
1297}
1298
1299impl FromStr for Riscv64Architecture {
1300    type Err = ();
1301
1302    fn from_str(s: &str) -> Result<Self, ()> {
1303        use Riscv64Architecture::*;
1304
1305        Ok(match s {
1306            "riscv64" => Riscv64,
1307            "riscv64gc" => Riscv64gc,
1308            "riscv64imac" => Riscv64imac,
1309            "riscv64a23" => Riscv64a23,
1310            _ => return Err(()),
1311        })
1312    }
1313}
1314
1315impl FromStr for X86_32Architecture {
1316    type Err = ();
1317
1318    fn from_str(s: &str) -> Result<Self, ()> {
1319        use X86_32Architecture::*;
1320
1321        Ok(match s {
1322            "i386" => I386,
1323            "i586" => I586,
1324            "i686" => I686,
1325            _ => return Err(()),
1326        })
1327    }
1328}
1329
1330impl FromStr for Mips32Architecture {
1331    type Err = ();
1332
1333    fn from_str(s: &str) -> Result<Self, ()> {
1334        use Mips32Architecture::*;
1335
1336        Ok(match s {
1337            "mips" => Mips,
1338            "mipsel" => Mipsel,
1339            "mipsisa32r6" => Mipsisa32r6,
1340            "mipsisa32r6el" => Mipsisa32r6el,
1341            _ => return Err(()),
1342        })
1343    }
1344}
1345
1346impl FromStr for Mips64Architecture {
1347    type Err = ();
1348
1349    fn from_str(s: &str) -> Result<Self, ()> {
1350        use Mips64Architecture::*;
1351
1352        Ok(match s {
1353            "mips64" => Mips64,
1354            "mips64el" => Mips64el,
1355            "mipsisa64r6" => Mipsisa64r6,
1356            "mipsisa64r6el" => Mipsisa64r6el,
1357            _ => return Err(()),
1358        })
1359    }
1360}
1361
1362#[cfg(feature = "arch_z80")]
1363impl FromStr for Z80Architecture {
1364    type Err = ();
1365
1366    fn from_str(s: &str) -> Result<Self, ()> {
1367        use Z80Architecture::*;
1368
1369        Ok(match s {
1370            "z80" => Z80,
1371            "z180" => Z180,
1372            "ez80" => Ez80,
1373            "sm83" => Sm83,
1374            "rabbit2000" => Rabbit2000,
1375            "rabbit2000a" => Rabbit2000A,
1376            "rabbit3000" => Rabbit3000,
1377            "rabbit3000a" => Rabbit3000A,
1378            "tlcs90" => Tlcs90,
1379            "r800" => R800,
1380            _ => return Err(()),
1381        })
1382    }
1383}
1384
1385impl FromStr for Architecture {
1386    type Err = ();
1387
1388    fn from_str(s: &str) -> Result<Self, ()> {
1389        use Architecture::*;
1390
1391        Ok(match s {
1392            "unknown" => Unknown,
1393            "amdgcn" => AmdGcn,
1394            "asmjs" => Asmjs,
1395            "avr" => Avr,
1396            "bpfeb" => Bpfeb,
1397            "bpfel" => Bpfel,
1398            "hexagon" => Hexagon,
1399            "loongarch64" => LoongArch64,
1400            "m68k" => M68k,
1401            "msp430" => Msp430,
1402            "nvptx64" => Nvptx64,
1403            "pulley32" => Pulley32,
1404            "pulley64" => Pulley64,
1405            "pulley32be" => Pulley32be,
1406            "pulley64be" => Pulley64be,
1407            "powerpc" => Powerpc,
1408            "powerpc64" => Powerpc64,
1409            "powerpc64le" => Powerpc64le,
1410            "s390x" => S390x,
1411            "sparc" => Sparc,
1412            "sparc64" => Sparc64,
1413            "sparcv9" => Sparcv9,
1414            "wasm32" => Wasm32,
1415            "wasm64" => Wasm64,
1416            "x86_64" => X86_64,
1417            "x86_64h" => X86_64h,
1418            "xtensa" => XTensa,
1419            #[cfg(feature = "arch_zkasm")]
1420            "zkasm" => ZkAsm,
1421            _ => {
1422                if let Ok(arm) = ArmArchitecture::from_str(s) {
1423                    Arm(arm)
1424                } else if let Ok(aarch64) = Aarch64Architecture::from_str(s) {
1425                    Aarch64(aarch64)
1426                } else if let Ok(riscv32) = Riscv32Architecture::from_str(s) {
1427                    Riscv32(riscv32)
1428                } else if let Ok(riscv64) = Riscv64Architecture::from_str(s) {
1429                    Riscv64(riscv64)
1430                } else if let Ok(x86_32) = X86_32Architecture::from_str(s) {
1431                    X86_32(x86_32)
1432                } else if let Ok(mips32) = Mips32Architecture::from_str(s) {
1433                    Mips32(mips32)
1434                } else if let Ok(mips64) = Mips64Architecture::from_str(s) {
1435                    Mips64(mips64)
1436                } else if let Ok(clever) = CleverArchitecture::from_str(s) {
1437                    Clever(clever)
1438                } else {
1439                    #[cfg(feature = "arch_z80")]
1440                    {
1441                        if let Ok(z80) = Z80Architecture::from_str(s) {
1442                            return Ok(Architecture::Z80(z80));
1443                        }
1444                    }
1445                    return Err(());
1446                }
1447            }
1448        })
1449    }
1450}
1451
1452impl fmt::Display for Vendor {
1453    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1454        f.write_str(self.as_str())
1455    }
1456}
1457
1458impl FromStr for Vendor {
1459    type Err = ();
1460
1461    fn from_str(s: &str) -> Result<Self, ()> {
1462        use Vendor::*;
1463
1464        Ok(match s {
1465            "unknown" => Unknown,
1466            "amd" => Amd,
1467            "apple" => Apple,
1468            "espressif" => Espressif,
1469            "experimental" => Experimental,
1470            "fortanix" => Fortanix,
1471            "ibm" => Ibm,
1472            "kmc" => Kmc,
1473            "nintendo" => Nintendo,
1474            "nvidia" => Nvidia,
1475            "pc" => Pc,
1476            "rumprun" => Rumprun,
1477            "sun" => Sun,
1478            "uwp" => Uwp,
1479            "wrs" => Wrs,
1480            custom => {
1481                #[cfg(not(feature = "std"))]
1482                use alloc::borrow::ToOwned;
1483
1484                // A custom vendor. Since triple syntax is so loosely defined,
1485                // be as conservative as we can to avoid potential ambiguities.
1486                // We err on the side of being too strict here, as we can
1487                // always relax it if needed.
1488
1489                // Don't allow empty string names.
1490                if custom.is_empty() {
1491                    return Err(());
1492                }
1493
1494                // Don't allow any other recognized name as a custom vendor,
1495                // since vendors can be omitted in some contexts.
1496                if Architecture::from_str(custom).is_ok()
1497                    || OperatingSystem::from_str(custom).is_ok()
1498                    || Environment::from_str(custom).is_ok()
1499                    || BinaryFormat::from_str(custom).is_ok()
1500                {
1501                    return Err(());
1502                }
1503
1504                // Require the first character to be an ascii lowercase.
1505                if !custom.chars().next().unwrap().is_ascii_lowercase() {
1506                    return Err(());
1507                }
1508
1509                // Restrict the set of characters permitted in a custom vendor.
1510                let has_restricted = custom.chars().any(|c: char| {
1511                    !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '.')
1512                });
1513
1514                if has_restricted {
1515                    return Err(());
1516                }
1517
1518                Custom(CustomVendor::Owned(Box::new(custom.to_owned())))
1519            }
1520        })
1521    }
1522}
1523
1524impl fmt::Display for OperatingSystem {
1525    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1526        use OperatingSystem::*;
1527
1528        let mut with_version = |name, deployment_target| {
1529            if let Some(DeploymentTarget {
1530                major,
1531                minor,
1532                patch,
1533            }) = deployment_target
1534            {
1535                write!(f, "{}{}.{}.{}", name, major, minor, patch)
1536            } else {
1537                write!(f, "{}", name)
1538            }
1539        };
1540
1541        match *self {
1542            Darwin(deployment_target) => with_version("darwin", deployment_target),
1543            IOS(deployment_target) => with_version("ios", deployment_target),
1544            MacOSX(deployment_target) => with_version("macosx", deployment_target),
1545            TvOS(deployment_target) => with_version("tvos", deployment_target),
1546            VisionOS(deployment_target) => with_version("visionos", deployment_target),
1547            WatchOS(deployment_target) => with_version("watchos", deployment_target),
1548            XROS(deployment_target) => with_version("xros", deployment_target),
1549            os => f.write_str(&os.into_str()),
1550        }
1551    }
1552}
1553
1554impl FromStr for OperatingSystem {
1555    type Err = ();
1556
1557    fn from_str(s: &str) -> Result<Self, ()> {
1558        use OperatingSystem::*;
1559
1560        let parse_darwin = |name: &str| {
1561            let s = &s[name.len()..];
1562            let mut parts = s.split('.');
1563
1564            if s.is_empty() {
1565                // Not specifying a version is allowed!
1566                return Ok(None);
1567            }
1568
1569            let major = if let Some(part) = parts.next() {
1570                part.parse().map_err(|_| ())?
1571            } else {
1572                // If the string was just `.`, with no major version, that's
1573                // clearly an error.
1574                return Err(());
1575            };
1576            let minor = if let Some(part) = parts.next() {
1577                part.parse().map_err(|_| ())?
1578            } else {
1579                // Fall back to 0 if no minor version was set
1580                0
1581            };
1582            let patch = if let Some(part) = parts.next() {
1583                part.parse().map_err(|_| ())?
1584            } else {
1585                // Fall back to 0 if no patch version was set
1586                0
1587            };
1588
1589            if parts.next().is_some() {
1590                // Too many parts
1591                return Err(());
1592            }
1593
1594            Ok(Some(DeploymentTarget {
1595                major,
1596                minor,
1597                patch,
1598            }))
1599        };
1600
1601        // Parse operating system names that contain a version, like `macosx10.7.0`.
1602        if s.starts_with("darwin") {
1603            return Ok(Darwin(parse_darwin("darwin")?));
1604        }
1605        if s.starts_with("ios") {
1606            return Ok(IOS(parse_darwin("ios")?));
1607        }
1608        if s.starts_with("macosx") {
1609            return Ok(MacOSX(parse_darwin("macosx")?));
1610        }
1611        if s.starts_with("tvos") {
1612            return Ok(TvOS(parse_darwin("tvos")?));
1613        }
1614        if s.starts_with("visionos") {
1615            return Ok(VisionOS(parse_darwin("visionos")?));
1616        }
1617        if s.starts_with("watchos") {
1618            return Ok(WatchOS(parse_darwin("watchos")?));
1619        }
1620        if s.starts_with("xros") {
1621            return Ok(XROS(parse_darwin("xros")?));
1622        }
1623
1624        Ok(match s {
1625            "unknown" => Unknown,
1626            "aix" => Aix,
1627            "amdhsa" => AmdHsa,
1628            "bitrig" => Bitrig,
1629            "cloudabi" => Cloudabi,
1630            "cuda" => Cuda,
1631            "cygwin" => Cygwin,
1632            "dragonfly" => Dragonfly,
1633            "emscripten" => Emscripten,
1634            "freebsd" => Freebsd,
1635            "fuchsia" => Fuchsia,
1636            "haiku" => Haiku,
1637            "hermit" => Hermit,
1638            "horizon" => Horizon,
1639            "hurd" => Hurd,
1640            "illumos" => Illumos,
1641            "l4re" => L4re,
1642            "linux" => Linux,
1643            "nebulet" => Nebulet,
1644            "netbsd" => Netbsd,
1645            "none" => None_,
1646            "openbsd" => Openbsd,
1647            "psp" => Psp,
1648            "redox" => Redox,
1649            "solaris" => Solaris,
1650            "solid_asp3" => SolidAsp3,
1651            "uefi" => Uefi,
1652            "vxworks" => VxWorks,
1653            "wasi" => Wasi,
1654            "wasip1" => WasiP1,
1655            "wasip2" => WasiP2,
1656            "windows" => Windows,
1657            "espidf" => Espidf,
1658            _ => return Err(()),
1659        })
1660    }
1661}
1662
1663impl fmt::Display for Environment {
1664    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1665        f.write_str(&self.into_str())
1666    }
1667}
1668
1669impl FromStr for Environment {
1670    type Err = ();
1671
1672    fn from_str(s: &str) -> Result<Self, ()> {
1673        use Environment::*;
1674
1675        Ok(match s {
1676            "unknown" => Unknown,
1677            "amdgiz" => AmdGiz,
1678            "android" => Android,
1679            "androideabi" => Androideabi,
1680            "eabi" => Eabi,
1681            "eabihf" => Eabihf,
1682            "gnu" => Gnu,
1683            "gnuabi64" => Gnuabi64,
1684            "gnueabi" => Gnueabi,
1685            "gnueabihf" => Gnueabihf,
1686            "gnuspe" => Gnuspe,
1687            "gnux32" => Gnux32,
1688            "gnu_ilp32" => GnuIlp32,
1689            "gnullvm" => GnuLlvm,
1690            "hermitkernel" => HermitKernel,
1691            "hurdkernel" => HurdKernel,
1692            "linuxkernel" => LinuxKernel,
1693            "macabi" => Macabi,
1694            "musl" => Musl,
1695            "musleabi" => Musleabi,
1696            "musleabihf" => Musleabihf,
1697            "muslabi64" => Muslabi64,
1698            "msvc" => Msvc,
1699            "newlib" => Newlib,
1700            "none" => None,
1701            "kernel" => Kernel,
1702            "uclibc" => Uclibc,
1703            "uclibceabi" => Uclibceabi,
1704            "uclibceabihf" => Uclibceabihf,
1705            "sgx" => Sgx,
1706            "sim" => Sim,
1707            "softfloat" => Softfloat,
1708            "spe" => Spe,
1709            "threads" => Threads,
1710            "ohos" => Ohos,
1711            _ => return Err(()),
1712        })
1713    }
1714}
1715
1716impl fmt::Display for BinaryFormat {
1717    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1718        f.write_str(&self.into_str())
1719    }
1720}
1721
1722impl FromStr for BinaryFormat {
1723    type Err = ();
1724
1725    fn from_str(s: &str) -> Result<Self, ()> {
1726        use BinaryFormat::*;
1727
1728        Ok(match s {
1729            "unknown" => Unknown,
1730            "elf" => Elf,
1731            "coff" => Coff,
1732            "macho" => Macho,
1733            "wasm" => Wasm,
1734            "xcoff" => Xcoff,
1735            _ => return Err(()),
1736        })
1737    }
1738}
1739
1740#[cfg(test)]
1741mod tests {
1742    use super::*;
1743    use alloc::string::ToString;
1744
1745    #[test]
1746    fn roundtrip_known_triples() {
1747        // This list is constructed from:
1748        //  - targets emitted by "rustup target list"
1749        //  - targets emitted by "rustc +nightly --print target-list"
1750        //  - targets contributors have added
1751        let targets = [
1752            "aarch64-apple-darwin",
1753            "aarch64-apple-ios",
1754            "aarch64-apple-ios-macabi",
1755            "aarch64-apple-ios-sim",
1756            "aarch64-apple-tvos",
1757            "aarch64-apple-tvos-sim",
1758            "aarch64-apple-visionos",
1759            "aarch64-apple-visionos-sim",
1760            "aarch64-apple-watchos",
1761            "aarch64-apple-watchos-sim",
1762            "aarch64_be-unknown-linux-gnu",
1763            "aarch64_be-unknown-linux-gnu_ilp32",
1764            "aarch64_be-unknown-netbsd",
1765            "aarch64-kmc-solid_asp3",
1766            "aarch64-linux-android",
1767            //"aarch64-nintendo-switch-freestanding", // TODO
1768            "aarch64-pc-windows-gnullvm",
1769            "aarch64-pc-windows-msvc",
1770            "aarch64-unknown-cloudabi",
1771            "aarch64-unknown-freebsd",
1772            "aarch64-unknown-fuchsia",
1773            "aarch64-unknown-hermit",
1774            "aarch64-unknown-illumos",
1775            "aarch64-unknown-linux-gnu",
1776            "aarch64-unknown-linux-gnu_ilp32",
1777            "aarch64-unknown-linux-musl",
1778            "aarch64-unknown-linux-ohos",
1779            "aarch64-unknown-netbsd",
1780            "aarch64-unknown-none",
1781            "aarch64-unknown-none-softfloat",
1782            //"aarch64-unknown-nto-qnx710", // TODO
1783            "aarch64-unknown-openbsd",
1784            "aarch64-unknown-redox",
1785            //"aarch64-unknown-teeos", // TODO
1786            "aarch64-unknown-uefi",
1787            "aarch64-uwp-windows-msvc",
1788            "aarch64-wrs-vxworks",
1789            //"arm64_32-apple-watchos", // TODO
1790            //"arm64e-apple-darwin", // TODO
1791            "amdgcn-amd-amdhsa",
1792            "amdgcn-amd-amdhsa-amdgiz",
1793            //"arm64e-apple-ios", // TODO
1794            //"arm64ec-pc-windows-msvc", // TODO
1795            "armeb-unknown-linux-gnueabi",
1796            "armebv7r-none-eabi",
1797            "armebv7r-none-eabihf",
1798            "arm-linux-androideabi",
1799            "arm-unknown-linux-gnueabi",
1800            "arm-unknown-linux-gnueabihf",
1801            "arm-unknown-linux-musleabi",
1802            "arm-unknown-linux-musleabihf",
1803            "armv4t-none-eabi",
1804            "armv4t-unknown-linux-gnueabi",
1805            "armv5te-none-eabi",
1806            "armv5te-unknown-linux-gnueabi",
1807            "armv5te-unknown-linux-musleabi",
1808            "armv5te-unknown-linux-uclibceabi",
1809            "armv6k-nintendo-3ds",
1810            "armv6-unknown-freebsd",
1811            "armv6-unknown-netbsd-eabihf",
1812            "armv7a-kmc-solid_asp3-eabi",
1813            "armv7a-kmc-solid_asp3-eabihf",
1814            "armv7a-none-eabi",
1815            "armv7a-none-eabihf",
1816            "armv7-apple-ios",
1817            "armv7k-apple-watchos",
1818            "armv7-linux-androideabi",
1819            "armv7r-none-eabi",
1820            "armv7r-none-eabihf",
1821            "armv7s-apple-ios",
1822            "armv7-unknown-cloudabi-eabihf",
1823            //"armv7-sony-vita-newlibeabihf", // TODO
1824            "armv7-unknown-freebsd",
1825            "armv7-unknown-linux-gnueabi",
1826            "armv7-unknown-linux-gnueabihf",
1827            "armv7-unknown-linux-musleabi",
1828            "armv7-unknown-linux-musleabihf",
1829            "armv7-unknown-linux-ohos",
1830            "armv7-unknown-linux-uclibceabi",
1831            "armv7-unknown-linux-uclibceabihf",
1832            "armv7-unknown-netbsd-eabihf",
1833            "armv7-wrs-vxworks-eabihf",
1834            "asmjs-unknown-emscripten",
1835            "armv8r-none-eabihf",
1836            //"avr-unknown-gnu-atmega328", // TODO
1837            "avr-unknown-unknown",
1838            "bpfeb-unknown-none",
1839            "bpfel-unknown-none",
1840            //"csky-unknown-linux-gnuabiv2", // TODO
1841            //"csky-unknown-linux-gnuabiv2hf", // TODO
1842            "hexagon-unknown-linux-musl",
1843            "hexagon-unknown-none-elf",
1844            "i386-apple-ios",
1845            //"i586-pc-nto-qnx700", // TODO
1846            "i586-pc-windows-msvc",
1847            "i586-unknown-linux-gnu",
1848            "i586-unknown-linux-musl",
1849            "i586-unknown-netbsd",
1850            "i686-apple-darwin",
1851            "i686-linux-android",
1852            "i686-apple-macosx10.7.0",
1853            "i686-pc-windows-gnu",
1854            "i686-pc-windows-gnullvm",
1855            "i686-pc-windows-msvc",
1856            "i686-unknown-cloudabi",
1857            "i686-unknown-dragonfly",
1858            "i686-unknown-freebsd",
1859            "i686-unknown-haiku",
1860            "i686-unknown-hurd-gnu",
1861            "i686-unknown-linux-gnu",
1862            "i686-unknown-linux-musl",
1863            "i686-unknown-netbsd",
1864            "i686-unknown-openbsd",
1865            "i686-unknown-redox",
1866            "i686-unknown-uefi",
1867            "i686-uwp-windows-gnu",
1868            "i686-uwp-windows-msvc",
1869            "i686-win7-windows-msvc",
1870            "i686-wrs-vxworks",
1871            "loongarch64-unknown-linux-gnu",
1872            "loongarch64-unknown-linux-musl",
1873            "loongarch64-unknown-none",
1874            "loongarch64-unknown-none-softfloat",
1875            "m68k-unknown-linux-gnu",
1876            "mips64el-unknown-linux-gnuabi64",
1877            "mips64el-unknown-linux-muslabi64",
1878            "mips64-openwrt-linux-musl",
1879            "mips64-unknown-linux-gnuabi64",
1880            "mips64-unknown-linux-muslabi64",
1881            "mipsel-sony-psp",
1882            //"mipsel-sony-psx", // TODO
1883            "mipsel-unknown-linux-gnu",
1884            "mipsel-unknown-linux-musl",
1885            "mipsel-unknown-linux-uclibc",
1886            "mipsel-unknown-netbsd",
1887            "mipsel-unknown-none",
1888            "mipsisa32r6el-unknown-linux-gnu",
1889            "mipsisa32r6-unknown-linux-gnu",
1890            "mipsisa64r6el-unknown-linux-gnuabi64",
1891            "mipsisa64r6-unknown-linux-gnuabi64",
1892            "mips-unknown-linux-gnu",
1893            "mips-unknown-linux-musl",
1894            "mips-unknown-linux-uclibc",
1895            "msp430-none-elf",
1896            "nvptx64-nvidia-cuda",
1897            "powerpc64-ibm-aix",
1898            "powerpc64le-unknown-freebsd",
1899            "powerpc64le-unknown-linux-gnu",
1900            "powerpc64le-unknown-linux-musl",
1901            "powerpc64-unknown-freebsd",
1902            "powerpc64-unknown-linux-gnu",
1903            "powerpc64-unknown-linux-musl",
1904            "powerpc64-unknown-openbsd",
1905            "powerpc64-wrs-vxworks",
1906            "powerpc-ibm-aix",
1907            "powerpc-unknown-freebsd",
1908            "powerpc-unknown-linux-gnu",
1909            "powerpc-unknown-linux-gnuspe",
1910            "powerpc-unknown-linux-musl",
1911            "powerpc-unknown-netbsd",
1912            "powerpc-unknown-openbsd",
1913            "powerpc-wrs-vxworks",
1914            "powerpc-wrs-vxworks-spe",
1915            "riscv32gc-unknown-linux-gnu",
1916            "riscv32gc-unknown-linux-musl",
1917            "riscv32imac-esp-espidf",
1918            "riscv32imac-unknown-none-elf",
1919            //"riscv32imac-unknown-xous-elf", // TODO
1920            "riscv32imafc-esp-espidf",
1921            "riscv32imafc-unknown-none-elf",
1922            "riscv32ima-unknown-none-elf",
1923            "riscv32imc-esp-espidf",
1924            "riscv32imc-unknown-none-elf",
1925            //"riscv32im-risc0-zkvm-elf", // TODO
1926            "riscv32im-unknown-none-elf",
1927            "riscv32i-unknown-none-elf",
1928            "riscv64gc-unknown-freebsd",
1929            "riscv64gc-unknown-fuchsia",
1930            "riscv64gc-unknown-hermit",
1931            "riscv64gc-unknown-linux-gnu",
1932            "riscv64a23-unknown-linux-gnu",
1933            "riscv64gc-unknown-linux-musl",
1934            "riscv64gc-unknown-netbsd",
1935            "riscv64gc-unknown-none-elf",
1936            "riscv64gc-unknown-openbsd",
1937            "riscv64imac-unknown-none-elf",
1938            "riscv64-linux-android",
1939            "s390x-unknown-linux-gnu",
1940            "s390x-unknown-linux-musl",
1941            "sparc64-unknown-linux-gnu",
1942            "sparc64-unknown-netbsd",
1943            "sparc64-unknown-openbsd",
1944            "sparc-unknown-linux-gnu",
1945            "sparc-unknown-none-elf",
1946            "sparcv9-sun-solaris",
1947            "thumbv4t-none-eabi",
1948            "thumbv5te-none-eabi",
1949            "thumbv6m-none-eabi",
1950            "thumbv7a-pc-windows-msvc",
1951            "thumbv7a-uwp-windows-msvc",
1952            "thumbv7em-none-eabi",
1953            "thumbv7em-none-eabihf",
1954            "thumbv7m-none-eabi",
1955            "thumbv7neon-linux-androideabi",
1956            "thumbv7neon-unknown-linux-gnueabihf",
1957            "thumbv7neon-unknown-linux-musleabihf",
1958            "thumbv8m.base-none-eabi",
1959            "thumbv8m.main-none-eabi",
1960            "thumbv8m.main-none-eabihf",
1961            "wasm32-experimental-emscripten",
1962            "wasm32-unknown-emscripten",
1963            "wasm32-unknown-unknown",
1964            "wasm32-wasi",
1965            "wasm32-wasip1",
1966            "wasm32-wasip1-threads",
1967            "wasm32-wasip2",
1968            "wasm64-unknown-unknown",
1969            "wasm64-wasi",
1970            "x86_64-apple-darwin",
1971            "x86_64-apple-darwin23.6.0",
1972            "x86_64-apple-ios",
1973            "x86_64-apple-ios-macabi",
1974            "x86_64-apple-tvos",
1975            "x86_64-apple-watchos-sim",
1976            "x86_64-fortanix-unknown-sgx",
1977            "x86_64h-apple-darwin",
1978            "x86_64-linux-android",
1979            //"x86_64-pc-nto-qnx710", // TODO
1980            "x86_64-linux-kernel", // Changed to x86_64-unknown-none-linuxkernel in 1.53.0
1981            "x86_64-apple-macosx",
1982            "x86_64-apple-macosx10.7.0",
1983            "x86_64-pc-cygwin",
1984            "x86_64-pc-solaris",
1985            "x86_64-pc-windows-gnu",
1986            "x86_64-pc-windows-gnullvm",
1987            "x86_64-pc-windows-msvc",
1988            "x86_64-rumprun-netbsd", // Removed in 1.53.0
1989            "x86_64-sun-solaris",
1990            "x86_64-unknown-bitrig",
1991            "x86_64-unknown-cloudabi",
1992            "x86_64-unikraft-linux-musl",
1993            "x86_64-unknown-dragonfly",
1994            "x86_64-unknown-freebsd",
1995            "x86_64-unknown-fuchsia",
1996            "x86_64-unknown-haiku",
1997            "x86_64-unknown-hermit-kernel", // Changed to x86_64-unknown-none-hermitkernel in 1.53.0
1998            "x86_64-unknown-hermit",
1999            "x86_64-unknown-illumos",
2000            "x86_64-unknown-l4re-uclibc",
2001            "x86_64-unknown-linux-gnu",
2002            "x86_64-unknown-linux-gnux32",
2003            "x86_64-unknown-linux-musl",
2004            "x86_64-unknown-linux-none",
2005            "x86_64-unknown-linux-ohos",
2006            "x86_64-unknown-netbsd",
2007            "x86_64-unknown-none",
2008            "x86_64-unknown-none-hermitkernel",
2009            "x86_64-unknown-none-linuxkernel",
2010            "x86_64-unknown-openbsd",
2011            "x86_64-unknown-redox",
2012            "x86_64-unknown-uefi",
2013            "x86_64-uwp-windows-gnu",
2014            "x86_64-uwp-windows-msvc",
2015            "x86_64-win7-windows-msvc",
2016            "x86_64-wrs-vxworks",
2017            "xtensa-esp32-espidf",
2018            "clever-unknown-elf",
2019            "xtensa-esp32-none-elf",
2020            "xtensa-esp32s2-espidf",
2021            "xtensa-esp32s2-none-elf",
2022            "xtensa-esp32s3-espidf",
2023            "xtensa-esp32s3-none-elf",
2024            #[cfg(feature = "arch_zkasm")]
2025            "zkasm-unknown-unknown",
2026            #[cfg(feature = "arch_z80")]
2027            "z80-zilog-none",
2028            #[cfg(feature = "arch_z80")]
2029            "sm83-nintendo-none",
2030            #[cfg(feature = "arch_z80")]
2031            "tlcs90-toshiba-none",
2032        ];
2033
2034        for target in targets.iter() {
2035            let t = Triple::from_str(target).expect("can't parse target");
2036            assert_ne!(t.architecture, Architecture::Unknown);
2037            assert_eq!(t.to_string(), *target, "{:#?}", t);
2038        }
2039    }
2040
2041    #[test]
2042    fn default_format_to_elf() {
2043        let t = Triple::from_str("riscv64").expect("can't parse target");
2044        assert_eq!(
2045            t.architecture,
2046            Architecture::Riscv64(Riscv64Architecture::Riscv64),
2047        );
2048        assert_eq!(t.vendor, Vendor::Unknown);
2049        assert_eq!(t.operating_system, OperatingSystem::Unknown);
2050        assert_eq!(t.environment, Environment::Unknown);
2051        assert_eq!(t.binary_format, BinaryFormat::Elf);
2052    }
2053
2054    #[test]
2055    fn thumbv7em_none_eabihf() {
2056        let t = Triple::from_str("thumbv7em-none-eabihf").expect("can't parse target");
2057        assert_eq!(
2058            t.architecture,
2059            Architecture::Arm(ArmArchitecture::Thumbv7em)
2060        );
2061        assert_eq!(t.vendor, Vendor::Unknown);
2062        assert_eq!(t.operating_system, OperatingSystem::None_);
2063        assert_eq!(t.environment, Environment::Eabihf);
2064        assert_eq!(t.binary_format, BinaryFormat::Elf);
2065    }
2066
2067    #[test]
2068    fn fuchsia_rename() {
2069        // Fuchsia targets were renamed to add the `unknown`.
2070        assert_eq!(
2071            Triple::from_str("aarch64-fuchsia"),
2072            Triple::from_str("aarch64-unknown-fuchsia")
2073        );
2074        assert_eq!(
2075            Triple::from_str("x86_64-fuchsia"),
2076            Triple::from_str("x86_64-unknown-fuchsia")
2077        );
2078    }
2079
2080    #[test]
2081    fn custom_vendors() {
2082        // Test various invalid cases.
2083        assert!(Triple::from_str("x86_64--linux").is_err());
2084        assert!(Triple::from_str("x86_64-42-linux").is_err());
2085        assert!(Triple::from_str("x86_64-__customvendor__-linux").is_err());
2086        assert!(Triple::from_str("x86_64-^-linux").is_err());
2087        assert!(Triple::from_str("x86_64- -linux").is_err());
2088        assert!(Triple::from_str("x86_64-CustomVendor-linux").is_err());
2089        assert!(Triple::from_str("x86_64-linux-linux").is_err());
2090        assert!(Triple::from_str("x86_64-x86_64-linux").is_err());
2091        assert!(Triple::from_str("x86_64-elf-linux").is_err());
2092        assert!(Triple::from_str("x86_64-gnu-linux").is_err());
2093        assert!(Triple::from_str("x86_64-linux-customvendor").is_err());
2094        assert!(Triple::from_str("customvendor").is_err());
2095        assert!(Triple::from_str("customvendor-x86_64").is_err());
2096        assert!(Triple::from_str("x86_64-").is_err());
2097        assert!(Triple::from_str("x86_64--").is_err());
2098
2099        // Test various Unicode things.
2100        assert!(
2101            Triple::from_str("x86_64-𝓬𝓾𝓼𝓽𝓸𝓶𝓿𝓮𝓷𝓭𝓸𝓻-linux").is_err(),
2102            "unicode font hazard"
2103        );
2104        assert!(
2105            Triple::from_str("x86_64-ćúśtőḿvéńdőŕ-linux").is_err(),
2106            "diacritical mark stripping hazard"
2107        );
2108        assert!(
2109            Triple::from_str("x86_64-customvendοr-linux").is_err(),
2110            "homoglyph hazard"
2111        );
2112        assert!(Triple::from_str("x86_64-customvendor-linux").is_ok());
2113        assert!(
2114            Triple::from_str("x86_64-ffi-linux").is_err(),
2115            "normalization hazard"
2116        );
2117        assert!(Triple::from_str("x86_64-ffi-linux").is_ok());
2118        assert!(
2119            Triple::from_str("x86_64-custom‍vendor-linux").is_err(),
2120            "zero-width character hazard"
2121        );
2122        assert!(
2123            Triple::from_str("x86_64-customvendor-linux").is_err(),
2124            "BOM hazard"
2125        );
2126
2127        // Test some valid cases.
2128        let t = Triple::from_str("x86_64-customvendor-linux")
2129            .expect("can't parse target with custom vendor");
2130        assert_eq!(t.architecture, Architecture::X86_64);
2131        assert_eq!(
2132            t.vendor,
2133            Vendor::Custom(CustomVendor::Static("customvendor"))
2134        );
2135        assert_eq!(t.operating_system, OperatingSystem::Linux);
2136        assert_eq!(t.environment, Environment::Unknown);
2137        assert_eq!(t.binary_format, BinaryFormat::Elf);
2138        assert_eq!(t.to_string(), "x86_64-customvendor-linux");
2139
2140        let t =
2141            Triple::from_str("x86_64-customvendor").expect("can't parse target with custom vendor");
2142        assert_eq!(t.architecture, Architecture::X86_64);
2143        assert_eq!(
2144            t.vendor,
2145            Vendor::Custom(CustomVendor::Static("customvendor"))
2146        );
2147        assert_eq!(t.operating_system, OperatingSystem::Unknown);
2148        assert_eq!(t.environment, Environment::Unknown);
2149        assert_eq!(t.binary_format, BinaryFormat::Elf);
2150
2151        assert_eq!(
2152            Triple::from_str("unknown-foo"),
2153            Ok(Triple {
2154                architecture: Architecture::Unknown,
2155                vendor: Vendor::Custom(CustomVendor::Static("foo")),
2156                operating_system: OperatingSystem::Unknown,
2157                environment: Environment::Unknown,
2158                binary_format: BinaryFormat::Unknown,
2159            })
2160        );
2161    }
2162
2163    #[test]
2164    fn deployment_version_parsing() {
2165        assert_eq!(
2166            Triple::from_str("aarch64-apple-macosx"),
2167            Ok(Triple {
2168                architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64),
2169                vendor: Vendor::Apple,
2170                operating_system: OperatingSystem::MacOSX(None),
2171                environment: Environment::Unknown,
2172                binary_format: BinaryFormat::Macho,
2173            })
2174        );
2175
2176        assert_eq!(
2177            Triple::from_str("aarch64-apple-macosx10.14.6"),
2178            Ok(Triple {
2179                architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64),
2180                vendor: Vendor::Apple,
2181                operating_system: OperatingSystem::MacOSX(Some(DeploymentTarget {
2182                    major: 10,
2183                    minor: 14,
2184                    patch: 6,
2185                })),
2186                environment: Environment::Unknown,
2187                binary_format: BinaryFormat::Macho,
2188            })
2189        );
2190
2191        let expected = Triple {
2192            architecture: Architecture::X86_64,
2193            vendor: Vendor::Apple,
2194            operating_system: OperatingSystem::Darwin(Some(DeploymentTarget {
2195                major: 23,
2196                minor: 0,
2197                patch: 0,
2198            })),
2199            environment: Environment::Unknown,
2200            binary_format: BinaryFormat::Macho,
2201        };
2202        assert_eq!(
2203            Triple::from_str("x86_64-apple-darwin23"),
2204            Ok(expected.clone())
2205        );
2206        assert_eq!(
2207            Triple::from_str("x86_64-apple-darwin23.0"),
2208            Ok(expected.clone())
2209        );
2210        assert_eq!(Triple::from_str("x86_64-apple-darwin23.0.0"), Ok(expected));
2211
2212        assert!(Triple::from_str("x86_64-apple-darwin.").is_err());
2213        assert!(Triple::from_str("x86_64-apple-darwin23.0.0.0").is_err());
2214    }
2215}