use crate::ir::LibCall;
use core::cmp;
use core::fmt::{self, Write};
use core::str::FromStr;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
const TESTCASE_NAME_LENGTH: usize = 16;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum ExternalName {
User {
namespace: u32,
index: u32,
},
TestCase {
length: u8,
ascii: [u8; TESTCASE_NAME_LENGTH],
},
LibCall(LibCall),
}
impl ExternalName {
pub fn testcase<T: AsRef<[u8]>>(v: T) -> Self {
let vec = v.as_ref();
let len = cmp::min(vec.len(), TESTCASE_NAME_LENGTH);
let mut bytes = [0u8; TESTCASE_NAME_LENGTH];
bytes[0..len].copy_from_slice(&vec[0..len]);
Self::TestCase {
length: len as u8,
ascii: bytes,
}
}
pub fn user(namespace: u32, index: u32) -> Self {
Self::User { namespace, index }
}
}
impl Default for ExternalName {
fn default() -> Self {
Self::user(0, 0)
}
}
impl fmt::Display for ExternalName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::User { namespace, index } => write!(f, "u{}:{}", namespace, index),
Self::TestCase { length, ascii } => {
f.write_char('%')?;
for byte in ascii.iter().take(length as usize) {
f.write_char(*byte as char)?;
}
Ok(())
}
Self::LibCall(lc) => write!(f, "%{}", lc),
}
}
}
impl FromStr for ExternalName {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.parse() {
Ok(lc) => Ok(Self::LibCall(lc)),
Err(_) => Ok(Self::testcase(s.as_bytes())),
}
}
}
#[cfg(test)]
mod tests {
use super::ExternalName;
use crate::ir::LibCall;
use alloc::string::ToString;
use core::u32;
#[test]
fn display_testcase() {
assert_eq!(ExternalName::testcase("").to_string(), "%");
assert_eq!(ExternalName::testcase("x").to_string(), "%x");
assert_eq!(ExternalName::testcase("x_1").to_string(), "%x_1");
assert_eq!(
ExternalName::testcase("longname12345678").to_string(),
"%longname12345678"
);
assert_eq!(
ExternalName::testcase("longname123456789").to_string(),
"%longname12345678"
);
}
#[test]
fn display_user() {
assert_eq!(ExternalName::user(0, 0).to_string(), "u0:0");
assert_eq!(ExternalName::user(1, 1).to_string(), "u1:1");
assert_eq!(
ExternalName::user(u32::MAX, u32::MAX).to_string(),
"u4294967295:4294967295"
);
}
#[test]
fn parsing() {
assert_eq!(
"FloorF32".parse(),
Ok(ExternalName::LibCall(LibCall::FloorF32))
);
assert_eq!(
ExternalName::LibCall(LibCall::FloorF32).to_string(),
"%FloorF32"
);
}
}