1use core::{
2 fmt::{self, Debug, Display},
3 str::FromStr,
4};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub enum AbiValue {
10 C {
13 unwind: bool,
15 },
16 System {
19 unwind: bool,
21 },
22
23 Rust,
25
26 Aapcs {
29 unwind: bool,
31 },
32
33 Cdecl {
36 unwind: bool,
38 },
39 Stdcall {
41 unwind: bool,
43 },
44 Fastcall {
46 unwind: bool,
48 },
49 Thiscall {
51 unwind: bool,
53 },
54 Vectorcall {
56 unwind: bool,
58 },
59
60 SysV64 {
63 unwind: bool,
65 },
66 Win64 {
68 unwind: bool,
70 },
71
72 EfiApi,
75}
76
77impl AbiValue {
78 #[must_use]
80 pub const fn allows_unwind(&self) -> bool {
81 match *self {
82 AbiValue::Rust => true,
83 AbiValue::EfiApi => false,
84 AbiValue::C { unwind }
85 | AbiValue::System { unwind }
86 | AbiValue::Aapcs { unwind }
87 | AbiValue::Cdecl { unwind }
88 | AbiValue::Stdcall { unwind }
89 | AbiValue::Fastcall { unwind }
90 | AbiValue::Thiscall { unwind }
91 | AbiValue::Vectorcall { unwind }
92 | AbiValue::SysV64 { unwind }
93 | AbiValue::Win64 { unwind } => unwind,
94 }
95 }
96
97 #[must_use]
104 pub fn canonize(self, has_c_varargs: bool) -> Option<AbiValue> {
105 let os_windows = cfg!(target_os = "windows");
107 let os_vexos = cfg!(target_os = "vexos");
108
109 let arch_x86 = cfg!(target_arch = "x86");
110 let arch_x86_64 = cfg!(target_arch = "x86_64");
111 let arch_arm = cfg!(target_arch = "arm");
112 let arch_aarch64 = cfg!(target_arch = "aarch64");
113 let arch_arm_any = arch_arm || arch_aarch64;
114 let arch_riscv32 = cfg!(target_arch = "riscv32");
115 let arch_riscv64 = cfg!(target_arch = "riscv64");
116
117 #[allow(clippy::match_same_arms)]
118 let out = match self {
119 AbiValue::C { unwind } => AbiValue::C { unwind },
120 AbiValue::Rust => AbiValue::Rust,
121 AbiValue::System { unwind } if arch_x86 && os_windows && !has_c_varargs => {
122 AbiValue::Stdcall { unwind }
123 }
124 AbiValue::System { unwind } if arch_arm && os_vexos => AbiValue::Aapcs { unwind },
125 AbiValue::System { unwind } => AbiValue::C { unwind },
126
127 AbiValue::Aapcs { unwind } if arch_arm_any => AbiValue::Aapcs { unwind },
129 AbiValue::Aapcs { .. } => return None,
130
131 AbiValue::Cdecl { unwind } if arch_x86 => AbiValue::C { unwind },
133 AbiValue::Cdecl { unwind } => AbiValue::C { unwind },
134
135 AbiValue::Fastcall { unwind } if arch_x86 => AbiValue::Fastcall { unwind },
136 AbiValue::Fastcall { unwind } if os_windows => AbiValue::C { unwind },
137 AbiValue::Fastcall { .. } => return None,
138
139 AbiValue::Stdcall { unwind } if arch_x86 => AbiValue::Stdcall { unwind },
140 AbiValue::Stdcall { unwind } if os_windows => AbiValue::C { unwind },
141 AbiValue::Stdcall { .. } => return None,
142
143 AbiValue::Thiscall { unwind } if arch_x86 => AbiValue::Thiscall { unwind },
144 AbiValue::Thiscall { .. } => return None,
145
146 AbiValue::Vectorcall { unwind } if arch_x86 || arch_x86_64 => {
147 AbiValue::Vectorcall { unwind }
148 }
149 AbiValue::Vectorcall { .. } => return None,
150
151 AbiValue::SysV64 { unwind } if arch_x86_64 => AbiValue::SysV64 { unwind },
152 AbiValue::Win64 { unwind } if arch_x86_64 => AbiValue::Win64 { unwind },
153 AbiValue::SysV64 { .. } | AbiValue::Win64 { .. } => return None,
154
155 AbiValue::EfiApi if arch_x86_64 => AbiValue::Win64 { unwind: false },
156 AbiValue::EfiApi if arch_arm => AbiValue::Aapcs { unwind: false },
157 AbiValue::EfiApi if arch_x86 || arch_aarch64 || arch_riscv32 || arch_riscv64 => {
158 AbiValue::C { unwind: false }
159 }
160 AbiValue::EfiApi => return None,
161 };
162
163 Some(out)
164 }
165}
166
167impl Display for AbiValue {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 write!(f, "{}", self.to_str())
170 }
171}
172
173macro_rules! abi_kind_impl {
174 (
175 $t:ty => {
176 $(
177 $variant:ident $( { unwind: $uw:literal } )? => $tok:literal
178 ),* $(,)?
179 }
180 ) => {
181 impl $t {
182 #[must_use]
184 pub const fn to_str(&self) -> &'static str {
185 match self {
186 $( Self::$variant $( { unwind: $uw } )? => $tok, )*
187 }
188 }
189
190 #[must_use]
192 pub const fn from_str_const(conv: &'static str) -> Option<Self> {
193 $(
194 if konst::eq_str(conv, $tok) {
195 return Some(Self::$variant $( { unwind: $uw } )?);
196 }
197 )*
198 None
199 }
200 }
201
202 impl FromStr for $t {
203 type Err = ();
204
205 fn from_str(s: &str) -> Result<Self, Self::Err> {
206 match s {
207 $( $tok => Ok(Self::$variant $( { unwind: $uw } )?), )*
208 _ => Err(()),
209 }
210 }
211 }
212 };
213}
214
215abi_kind_impl!(AbiValue => {
216 Rust => "Rust",
217 C { unwind: false } => "C",
218 C { unwind: true } => "C-unwind",
219 System { unwind: false } => "system",
220 System { unwind: true } => "system-unwind",
221 Aapcs { unwind: false } => "aapcs",
222 Aapcs { unwind: true } => "aapcs-unwind",
223 Cdecl { unwind: false } => "cdecl",
224 Cdecl { unwind: true } => "cdecl-unwind",
225 Stdcall { unwind: false } => "stdcall",
226 Stdcall { unwind: true } => "stdcall-unwind",
227 Fastcall { unwind: false } => "fastcall",
228 Fastcall { unwind: true } => "fastcall-unwind",
229 Thiscall { unwind: false } => "thiscall",
230 Thiscall { unwind: true } => "thiscall-unwind",
231 Vectorcall { unwind: false } => "vectorcall",
232 Vectorcall { unwind: true } => "vectorcall-unwind",
233 SysV64 { unwind: false } => "sysv64",
234 SysV64 { unwind: true } => "sysv64-unwind",
235 Win64 { unwind: false } => "win64",
236 Win64 { unwind: true } => "win64-unwind",
237 EfiApi => "efiapi"
238});