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(core::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 pub fn raw(&self) -> &[u8] {
119 &self.0
120 }
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
135#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
136pub enum ExternalName {
137 User(UserExternalNameRef),
139 TestCase(TestcaseName),
142 LibCall(LibCall),
144 KnownSymbol(KnownSymbol),
146}
147
148impl Default for ExternalName {
149 fn default() -> Self {
150 Self::User(UserExternalNameRef::new(0))
151 }
152}
153
154impl ExternalName {
155 pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {
167 Self::TestCase(TestcaseName::new(v))
168 }
169
170 pub fn user(func_ref: UserExternalNameRef) -> Self {
180 Self::User(func_ref)
181 }
182
183 pub fn display<'a>(
186 &'a self,
187 params: Option<&'a FunctionParameters>,
188 ) -> DisplayableExternalName<'a> {
189 DisplayableExternalName { name: self, params }
190 }
191}
192
193pub struct DisplayableExternalName<'a> {
195 name: &'a ExternalName,
196 params: Option<&'a FunctionParameters>,
197}
198
199impl<'a> fmt::Display for DisplayableExternalName<'a> {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match &self.name {
202 ExternalName::User(func_ref) => {
203 if let Some(params) = self.params {
204 let name = ¶ms.user_named_funcs()[*func_ref];
205 write!(f, "u{}:{}", name.namespace, name.index)
206 } else {
207 write!(f, "{}", *func_ref)
209 }
210 }
211 ExternalName::TestCase(testcase) => testcase.fmt(f),
212 ExternalName::LibCall(lc) => write!(f, "%{lc}"),
213 ExternalName::KnownSymbol(ks) => write!(f, "%{ks}"),
214 }
215 }
216}
217
218impl FromStr for ExternalName {
219 type Err = ();
220
221 fn from_str(s: &str) -> Result<Self, Self::Err> {
222 if let Ok(ks) = s.parse() {
224 return Ok(Self::KnownSymbol(ks));
225 }
226
227 if let Ok(lc) = s.parse() {
229 return Ok(Self::LibCall(lc));
230 }
231
232 Ok(Self::testcase(s.as_bytes()))
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::ExternalName;
240 use crate::ir::{
241 LibCall, UserExternalName, entities::UserExternalNameRef, function::FunctionParameters,
242 };
243 use alloc::string::ToString;
244 use cranelift_entity::EntityRef as _;
245
246 #[cfg(target_pointer_width = "64")]
247 #[test]
248 fn externalname_size() {
249 assert_eq!(core::mem::size_of::<ExternalName>(), 24);
250 }
251
252 #[test]
253 fn display_testcase() {
254 assert_eq!(ExternalName::testcase("").display(None).to_string(), "%");
255 assert_eq!(ExternalName::testcase("x").display(None).to_string(), "%x");
256 assert_eq!(
257 ExternalName::testcase("x_1").display(None).to_string(),
258 "%x_1"
259 );
260 assert_eq!(
261 ExternalName::testcase("longname12345678")
262 .display(None)
263 .to_string(),
264 "%longname12345678"
265 );
266 assert_eq!(
267 ExternalName::testcase("longname123456789")
268 .display(None)
269 .to_string(),
270 "%longname123456789"
271 );
272 }
273
274 #[test]
275 fn display_user() {
276 assert_eq!(
277 ExternalName::user(UserExternalNameRef::new(0))
278 .display(None)
279 .to_string(),
280 "userextname0"
281 );
282 assert_eq!(
283 ExternalName::user(UserExternalNameRef::new(1))
284 .display(None)
285 .to_string(),
286 "userextname1"
287 );
288 assert_eq!(
289 ExternalName::user(UserExternalNameRef::new((u32::MAX - 1) as _))
290 .display(None)
291 .to_string(),
292 "userextname4294967294"
293 );
294
295 let mut func_params = FunctionParameters::new();
296
297 func_params.ensure_user_func_name(UserExternalName {
299 namespace: 13,
300 index: 37,
301 });
302
303 func_params.ensure_user_func_name(UserExternalName {
305 namespace: 2,
306 index: 4,
307 });
308
309 assert_eq!(
310 ExternalName::user(UserExternalNameRef::new(0))
311 .display(Some(&func_params))
312 .to_string(),
313 "u13:37"
314 );
315
316 assert_eq!(
317 ExternalName::user(UserExternalNameRef::new(1))
318 .display(Some(&func_params))
319 .to_string(),
320 "u2:4"
321 );
322 }
323
324 #[test]
325 fn parsing() {
326 assert_eq!(
327 "FloorF32".parse(),
328 Ok(ExternalName::LibCall(LibCall::FloorF32))
329 );
330 assert_eq!(
331 ExternalName::LibCall(LibCall::FloorF32)
332 .display(None)
333 .to_string(),
334 "%FloorF32"
335 );
336 }
337}