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 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 core::u32;
245 use cranelift_entity::EntityRef as _;
246
247 #[cfg(target_pointer_width = "64")]
248 #[test]
249 fn externalname_size() {
250 assert_eq!(core::mem::size_of::<ExternalName>(), 24);
251 }
252
253 #[test]
254 fn display_testcase() {
255 assert_eq!(ExternalName::testcase("").display(None).to_string(), "%");
256 assert_eq!(ExternalName::testcase("x").display(None).to_string(), "%x");
257 assert_eq!(
258 ExternalName::testcase("x_1").display(None).to_string(),
259 "%x_1"
260 );
261 assert_eq!(
262 ExternalName::testcase("longname12345678")
263 .display(None)
264 .to_string(),
265 "%longname12345678"
266 );
267 assert_eq!(
268 ExternalName::testcase("longname123456789")
269 .display(None)
270 .to_string(),
271 "%longname123456789"
272 );
273 }
274
275 #[test]
276 fn display_user() {
277 assert_eq!(
278 ExternalName::user(UserExternalNameRef::new(0))
279 .display(None)
280 .to_string(),
281 "userextname0"
282 );
283 assert_eq!(
284 ExternalName::user(UserExternalNameRef::new(1))
285 .display(None)
286 .to_string(),
287 "userextname1"
288 );
289 assert_eq!(
290 ExternalName::user(UserExternalNameRef::new((u32::MAX - 1) as _))
291 .display(None)
292 .to_string(),
293 "userextname4294967294"
294 );
295
296 let mut func_params = FunctionParameters::new();
297
298 func_params.ensure_user_func_name(UserExternalName {
300 namespace: 13,
301 index: 37,
302 });
303
304 func_params.ensure_user_func_name(UserExternalName {
306 namespace: 2,
307 index: 4,
308 });
309
310 assert_eq!(
311 ExternalName::user(UserExternalNameRef::new(0))
312 .display(Some(&func_params))
313 .to_string(),
314 "u13:37"
315 );
316
317 assert_eq!(
318 ExternalName::user(UserExternalNameRef::new(1))
319 .display(Some(&func_params))
320 .to_string(),
321 "u2:4"
322 );
323 }
324
325 #[test]
326 fn parsing() {
327 assert_eq!(
328 "FloorF32".parse(),
329 Ok(ExternalName::LibCall(LibCall::FloorF32))
330 );
331 assert_eq!(
332 ExternalName::LibCall(LibCall::FloorF32)
333 .display(None)
334 .to_string(),
335 "%FloorF32"
336 );
337 }
338}