1#[cfg(nightly_build)]
2use core::marker::ConstParamTy;
3use core::{
4 fmt::{Debug, Display},
5 str::FromStr,
6};
7
8use const_panic::concat_panic;
9
10#[repr(u8)]
12#[cfg_attr(nightly_build, derive(ConstParamTy))]
13#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
14pub enum Abi {
15 Rust = 0,
17 C = 1,
19 System = 2,
21 Win64 = 3,
23 Sysv64 = 4,
25 Aapcs = 5,
27 Cdecl = 6,
29 Stdcall = 7,
31 Fastcall = 8,
33 Vectorcall = 9,
35}
36
37impl Abi {
38 #[must_use]
40 pub const fn to_str(&self) -> &'static str {
41 match self {
42 Abi::Rust => "Rust",
43 Abi::C => "C",
44 Abi::System => "system",
45 Abi::Win64 => "win64",
46 Abi::Sysv64 => "sysv64",
47 Abi::Aapcs => "aapcs",
48 Abi::Cdecl => "cdecl",
49 Abi::Stdcall => "stdcall",
50 Abi::Fastcall => "fastcall",
51 Abi::Vectorcall => "vectorcall",
52 }
53 }
54}
55
56impl Abi {
57 #[must_use]
59 pub fn is_alias(&self) -> bool {
60 matches!(self, Abi::C | Abi::System)
61 }
62
63 #[must_use]
65 pub fn is_concrete(&self) -> bool {
66 !self.is_alias()
67 }
68
69 #[must_use]
71 pub fn concrete(&self) -> Abi {
72 match self {
73 Abi::C => {
74 if cfg!(target_os = "windows") && cfg!(target_arch = "x86_64") {
76 Abi::Win64
77 } else if cfg!(target_arch = "x86_64") {
78 Abi::Sysv64
79 } else if cfg!(target_arch = "x86") {
80 Abi::Cdecl
81 } else if cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64") {
82 Abi::Aapcs
83 } else {
84 Abi::Cdecl }
86 }
87 Abi::System => {
88 if cfg!(target_os = "windows") && cfg!(target_arch = "x86_64") {
89 Abi::Win64
90 } else if cfg!(target_os = "windows") && cfg!(target_arch = "x86") {
91 Abi::Stdcall
92 } else if cfg!(target_arch = "x86_64") {
93 Abi::Sysv64
94 } else if cfg!(target_arch = "x86") {
95 Abi::Cdecl
96 } else if cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64") {
97 Abi::Aapcs
98 } else {
99 Abi::Cdecl }
101 }
102 other => *other,
103 }
104 }
105}
106
107impl FromStr for Abi {
108 type Err = ();
109
110 fn from_str(s: &str) -> Result<Self, Self::Err> {
111 match s {
112 "" | "Rust" => Ok(Abi::Rust),
113 "C" => Ok(Abi::C),
114 "system" => Ok(Abi::System),
115 "win64" => Ok(Abi::Win64),
116 "sysv64" => Ok(Abi::Sysv64),
117 "aapcs" => Ok(Abi::Aapcs),
118 "cdecl" => Ok(Abi::Cdecl),
119 "stdcall" => Ok(Abi::Stdcall),
120 "fastcall" => Ok(Abi::Fastcall),
121 "vectorcall" => Ok(Abi::Vectorcall),
122 _ => Err(()),
123 }
124 }
125}
126
127impl Display for Abi {
128 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
129 write!(f, "{}", self.to_str())
130 }
131}
132
133#[must_use]
135pub const fn parse(conv: &'static str) -> Option<Abi> {
136 if konst::eq_str(conv, "") || konst::eq_str(conv, "Rust") {
137 Some(Abi::Rust)
138 } else if konst::eq_str(conv, "C") {
139 Some(Abi::C)
140 } else if konst::eq_str(conv, "system") {
141 Some(Abi::System)
142 } else if konst::eq_str(conv, "win64") {
143 Some(Abi::Win64)
144 } else if konst::eq_str(conv, "sysv64") {
145 Some(Abi::Sysv64)
146 } else if konst::eq_str(conv, "aapcs") {
147 Some(Abi::Aapcs)
148 } else if konst::eq_str(conv, "cdecl") {
149 Some(Abi::Cdecl)
150 } else if konst::eq_str(conv, "stdcall") {
151 Some(Abi::Stdcall)
152 } else if konst::eq_str(conv, "fastcall") {
153 Some(Abi::Fastcall)
154 } else if konst::eq_str(conv, "vectorcall") {
155 Some(Abi::Vectorcall)
156 } else {
157 None
158 }
159}
160
161#[must_use]
163pub const fn parse_or_fail(conv: &'static str) -> Abi {
164 if let Some(c) = parse(conv) {
165 c
166 } else {
167 concat_panic!("invalid or unknown abi", conv)
168 }
169}
170
171#[cfg(nightly_build)]
172pub(crate) type AbiKey = Abi;
173#[cfg(not(nightly_build))]
174pub(crate) type AbiKey = u8;
175
176#[must_use]
179pub const fn key(abi: Abi) -> AbiKey {
180 abi as _
181}
182
183#[macro_export]
204macro_rules! abi {
205 ( $abi:literal ) => {
206 $crate::abi::key($crate::abi::parse_or_fail($abi))
207 };
208}