1use crate::ir::{KnownSymbol, LibCall};
8use alloc::boxed::Box;
9use core::fmt::{self, Write};
10use core::str::FromStr;
11
12use cranelift_entity::EntityRef as _;
13#[cfg(feature = "enable-serde")]
14use serde_derive::{Deserialize, Serialize};
15
16use super::entities::UserExternalNameRef;
17use super::function::FunctionParameters;
18
19#[derive(Clone, Debug, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
26pub enum UserFuncName {
27 User(UserExternalName),
29 Testcase(TestcaseName),
31}
32
33impl UserFuncName {
34 pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {
37 Self::Testcase(TestcaseName::new(v))
38 }
39
40 pub fn user(namespace: u32, index: u32) -> Self {
42 Self::User(UserExternalName::new(namespace, index))
43 }
44
45 pub fn get_user(&self) -> Option<&UserExternalName> {
47 match self {
48 UserFuncName::User(user) => Some(user),
49 UserFuncName::Testcase(_) => None,
50 }
51 }
52}
53
54impl Default for UserFuncName {
55 fn default() -> Self {
56 UserFuncName::User(UserExternalName::default())
57 }
58}
59
60impl fmt::Display for UserFuncName {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 match self {
63 UserFuncName::User(user) => user.fmt(f),
64 UserFuncName::Testcase(testcase) => testcase.fmt(f),
65 }
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
73#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
74pub struct UserExternalName {
75 pub namespace: u32,
77 pub index: u32,
79}
80
81impl UserExternalName {
82 pub fn new(namespace: u32, index: u32) -> Self {
84 Self { namespace, index }
85 }
86}
87
88impl fmt::Display for UserExternalName {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(f, "u{}:{}", self.namespace, self.index)
91 }
92}
93
94#[derive(Clone, PartialEq, Eq, Hash)]
96#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
97pub struct TestcaseName(Box<[u8]>);
98
99impl fmt::Display for TestcaseName {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.write_char('%')?;
102 f.write_str(std::str::from_utf8(&self.0).unwrap())
103 }
104}
105
106impl fmt::Debug for TestcaseName {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 write!(f, "{self}")
109 }
110}
111
112impl TestcaseName {
113 pub(crate) fn new<T: AsRef<[u8]>>(v: T) -> Self {
114 Self(v.as_ref().into())
115 }
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, Hash)]
130#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
131pub enum ExternalName {
132 User(UserExternalNameRef),
134 TestCase(TestcaseName),
137 LibCall(LibCall),
139 KnownSymbol(KnownSymbol),
141}
142
143impl Default for ExternalName {
144 fn default() -> Self {
145 Self::User(UserExternalNameRef::new(0))
146 }
147}
148
149impl ExternalName {
150 pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {
162 Self::TestCase(TestcaseName::new(v))
163 }
164
165 pub fn user(func_ref: UserExternalNameRef) -> Self {
175 Self::User(func_ref)
176 }
177
178 pub fn display<'a>(
181 &'a self,
182 params: Option<&'a FunctionParameters>,
183 ) -> DisplayableExternalName<'a> {
184 DisplayableExternalName { name: self, params }
185 }
186}
187
188pub struct DisplayableExternalName<'a> {
190 name: &'a ExternalName,
191 params: Option<&'a FunctionParameters>,
192}
193
194impl<'a> fmt::Display for DisplayableExternalName<'a> {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 match &self.name {
197 ExternalName::User(func_ref) => {
198 if let Some(params) = self.params {
199 let name = ¶ms.user_named_funcs()[*func_ref];
200 write!(f, "u{}:{}", name.namespace, name.index)
201 } else {
202 write!(f, "{}", *func_ref)
204 }
205 }
206 ExternalName::TestCase(testcase) => testcase.fmt(f),
207 ExternalName::LibCall(lc) => write!(f, "%{lc}"),
208 ExternalName::KnownSymbol(ks) => write!(f, "%{ks}"),
209 }
210 }
211}
212
213impl FromStr for ExternalName {
214 type Err = ();
215
216 fn from_str(s: &str) -> Result<Self, Self::Err> {
217 if let Ok(ks) = s.parse() {
219 return Ok(Self::KnownSymbol(ks));
220 }
221
222 if let Ok(lc) = s.parse() {
224 return Ok(Self::LibCall(lc));
225 }
226
227 Ok(Self::testcase(s.as_bytes()))
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::ExternalName;
235 use crate::ir::{
236 entities::UserExternalNameRef, function::FunctionParameters, LibCall, UserExternalName,
237 };
238 use alloc::string::ToString;
239 use core::u32;
240 use cranelift_entity::EntityRef as _;
241
242 #[cfg(target_pointer_width = "64")]
243 #[test]
244 fn externalname_size() {
245 assert_eq!(core::mem::size_of::<ExternalName>(), 24);
246 }
247
248 #[test]
249 fn display_testcase() {
250 assert_eq!(ExternalName::testcase("").display(None).to_string(), "%");
251 assert_eq!(ExternalName::testcase("x").display(None).to_string(), "%x");
252 assert_eq!(
253 ExternalName::testcase("x_1").display(None).to_string(),
254 "%x_1"
255 );
256 assert_eq!(
257 ExternalName::testcase("longname12345678")
258 .display(None)
259 .to_string(),
260 "%longname12345678"
261 );
262 assert_eq!(
263 ExternalName::testcase("longname123456789")
264 .display(None)
265 .to_string(),
266 "%longname123456789"
267 );
268 }
269
270 #[test]
271 fn display_user() {
272 assert_eq!(
273 ExternalName::user(UserExternalNameRef::new(0))
274 .display(None)
275 .to_string(),
276 "userextname0"
277 );
278 assert_eq!(
279 ExternalName::user(UserExternalNameRef::new(1))
280 .display(None)
281 .to_string(),
282 "userextname1"
283 );
284 assert_eq!(
285 ExternalName::user(UserExternalNameRef::new((u32::MAX - 1) as _))
286 .display(None)
287 .to_string(),
288 "userextname4294967294"
289 );
290
291 let mut func_params = FunctionParameters::new();
292
293 func_params.ensure_user_func_name(UserExternalName {
295 namespace: 13,
296 index: 37,
297 });
298
299 func_params.ensure_user_func_name(UserExternalName {
301 namespace: 2,
302 index: 4,
303 });
304
305 assert_eq!(
306 ExternalName::user(UserExternalNameRef::new(0))
307 .display(Some(&func_params))
308 .to_string(),
309 "u13:37"
310 );
311
312 assert_eq!(
313 ExternalName::user(UserExternalNameRef::new(1))
314 .display(Some(&func_params))
315 .to_string(),
316 "u2:4"
317 );
318 }
319
320 #[test]
321 fn parsing() {
322 assert_eq!(
323 "FloorF32".parse(),
324 Ok(ExternalName::LibCall(LibCall::FloorF32))
325 );
326 assert_eq!(
327 ExternalName::LibCall(LibCall::FloorF32)
328 .display(None)
329 .to_string(),
330 "%FloorF32"
331 );
332 }
333}