1use std::cmp::Ordering;
2use std::fmt;
3use std::hash::{Hash, Hasher};
4
5#[cfg(feature = "nightly")]
6use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd};
7#[cfg(feature = "nightly")]
8use rustc_macros::{Decodable, Encodable};
9
10use crate::AbiFromStrErr;
11
12#[cfg(test)]
13mod tests;
14
15#[derive(Clone, Copy, Debug)]
17#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
18pub enum ExternAbi {
19 C {
22 unwind: bool,
23 },
24 System {
26 unwind: bool,
27 },
28
29 Rust,
31 RustCall,
34 RustCold,
38
39 RustInvalid,
42
43 Unadjusted,
46
47 Custom,
51
52 EfiApi,
55
56 Aapcs {
59 unwind: bool,
60 },
61 CmseNonSecureCall,
63 CmseNonSecureEntry,
65
66 GpuKernel,
70 PtxKernel,
73
74 AvrInterrupt,
76 AvrNonBlockingInterrupt,
77 Msp430Interrupt,
78 RiscvInterruptM,
79 RiscvInterruptS,
80 X86Interrupt,
81
82 Cdecl {
85 unwind: bool,
86 },
87 Stdcall {
89 unwind: bool,
90 },
91 Fastcall {
93 unwind: bool,
94 },
95 Thiscall {
97 unwind: bool,
98 },
99 Vectorcall {
101 unwind: bool,
102 },
103
104 SysV64 {
106 unwind: bool,
107 },
108 Win64 {
109 unwind: bool,
110 },
111}
112
113macro_rules! abi_impls {
114 ($e_name:ident = {
115 $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
116 }) => {
117 impl $e_name {
118 pub const ALL_VARIANTS: &[Self] = &[
119 $($e_name::$variant $({ unwind: $uw })*,)*
120 ];
121 pub const fn as_str(&self) -> &'static str {
122 match self {
123 $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
124 }
125 }
126 }
127
128 impl ::core::str::FromStr for $e_name {
129 type Err = AbiFromStrErr;
130 fn from_str(s: &str) -> Result<$e_name, Self::Err> {
131 match s {
132 $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
133 _ => Err(AbiFromStrErr::Unknown),
134 }
135 }
136 }
137 }
138}
139
140abi_impls! {
141 ExternAbi = {
142 C { unwind: false } =><= "C",
143 C { unwind: true } =><= "C-unwind",
144 Rust =><= "Rust",
145 Aapcs { unwind: false } =><= "aapcs",
146 Aapcs { unwind: true } =><= "aapcs-unwind",
147 AvrInterrupt =><= "avr-interrupt",
148 AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
149 Cdecl { unwind: false } =><= "cdecl",
150 Cdecl { unwind: true } =><= "cdecl-unwind",
151 CmseNonSecureCall =><= "cmse-nonsecure-call",
152 CmseNonSecureEntry =><= "cmse-nonsecure-entry",
153 Custom =><= "custom",
154 EfiApi =><= "efiapi",
155 Fastcall { unwind: false } =><= "fastcall",
156 Fastcall { unwind: true } =><= "fastcall-unwind",
157 GpuKernel =><= "gpu-kernel",
158 Msp430Interrupt =><= "msp430-interrupt",
159 PtxKernel =><= "ptx-kernel",
160 RiscvInterruptM =><= "riscv-interrupt-m",
161 RiscvInterruptS =><= "riscv-interrupt-s",
162 RustCall =><= "rust-call",
163 RustCold =><= "rust-cold",
164 RustInvalid =><= "rust-invalid",
165 Stdcall { unwind: false } =><= "stdcall",
166 Stdcall { unwind: true } =><= "stdcall-unwind",
167 System { unwind: false } =><= "system",
168 System { unwind: true } =><= "system-unwind",
169 SysV64 { unwind: false } =><= "sysv64",
170 SysV64 { unwind: true } =><= "sysv64-unwind",
171 Thiscall { unwind: false } =><= "thiscall",
172 Thiscall { unwind: true } =><= "thiscall-unwind",
173 Unadjusted =><= "unadjusted",
174 Vectorcall { unwind: false } =><= "vectorcall",
175 Vectorcall { unwind: true } =><= "vectorcall-unwind",
176 Win64 { unwind: false } =><= "win64",
177 Win64 { unwind: true } =><= "win64-unwind",
178 X86Interrupt =><= "x86-interrupt",
179 }
180}
181
182impl Ord for ExternAbi {
183 fn cmp(&self, rhs: &Self) -> Ordering {
184 self.as_str().cmp(rhs.as_str())
185 }
186}
187
188impl PartialOrd for ExternAbi {
189 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
190 Some(self.cmp(rhs))
191 }
192}
193
194impl PartialEq for ExternAbi {
195 fn eq(&self, rhs: &Self) -> bool {
196 self.cmp(rhs) == Ordering::Equal
197 }
198}
199
200impl Eq for ExternAbi {}
201
202impl Hash for ExternAbi {
203 fn hash<H: Hasher>(&self, state: &mut H) {
204 self.as_str().hash(state);
205 u32::from_be_bytes(*b"ABI\0").hash(state);
207 }
208}
209
210#[cfg(feature = "nightly")]
211impl<C> HashStable<C> for ExternAbi {
212 #[inline]
213 fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
214 Hash::hash(self, hasher);
215 }
216}
217
218#[cfg(feature = "nightly")]
219impl StableOrd for ExternAbi {
220 const CAN_USE_UNSTABLE_SORT: bool = true;
221
222 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
224}
225
226impl ExternAbi {
227 pub fn is_rustic_abi(self) -> bool {
234 use ExternAbi::*;
235 matches!(self, Rust | RustCall | RustCold)
236 }
237
238 pub fn supports_varargs(self) -> bool {
239 match self {
248 Self::C { .. }
249 | Self::Cdecl { .. }
250 | Self::Aapcs { .. }
251 | Self::Win64 { .. }
252 | Self::SysV64 { .. }
253 | Self::EfiApi => true,
254 _ => false,
255 }
256 }
257}
258
259pub fn all_names() -> Vec<&'static str> {
260 ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
261}
262
263impl ExternAbi {
264 pub const FALLBACK: ExternAbi = ExternAbi::C { unwind: false };
266
267 pub fn name(self) -> &'static str {
268 self.as_str()
269 }
270}
271
272impl fmt::Display for ExternAbi {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 write!(f, "\"{}\"", self.as_str())
275 }
276}