1#[derive(Debug, Clone, Copy, PartialOrd, Ord)]
10pub struct Symbol<'a>(&'a str);
11
12impl<'a> Symbol<'a> {
13 pub fn new(data: &'a str) -> Self {
14 Self(data)
15 }
16 pub fn name(&self) -> &'a str {
17 self.0
18 }
19}
20
21impl<'a> std::hash::Hash for Symbol<'a> {
22 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
23 self.0.as_ptr().hash(state);
24 self.0.len().hash(state);
25 }
26}
27
28fn is_ascii_ident_body(x: char) -> bool {
29 x.is_ascii_alphanumeric() || x == '_'
30}
31
32fn is_ascii_ident_head(x: char) -> bool {
33 x.is_ascii_alphabetic() || x == '_'
34}
35
36fn is_ascii_ident(x: &str) -> bool {
37 !x.is_empty()
38 && is_ascii_ident_head(unsafe { x.chars().next().unwrap_unchecked() })
39 && x[1..].chars().all(is_ascii_ident_body)
40}
41
42impl<'a> std::fmt::Display for Symbol<'a> {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 if is_ascii_ident(self.0) {
45 write!(f, "{}", self.0)
46 } else {
47 write!(f, "S{:X}_{}", self.0.as_ptr() as usize, self.0.len())
48 }
49 }
50}
51
52impl<'a, 'b> PartialEq<Symbol<'b>> for Symbol<'a> {
53 fn eq(&self, other: &Symbol<'b>) -> bool {
54 self.0.as_ptr().eq(&other.0.as_ptr()) && self.0.len() == other.0.len()
55 }
56}
57
58impl<'a> Eq for Symbol<'a> {}
59
60macro_rules! unreachable_branch {
61 ($($arg:tt)*) => {
62 if cfg!(debug_assertions) {
63 unreachable!($($arg)*)
64 } else {
65 unsafe { std::hint::unreachable_unchecked() }
66 }
67 };
68}
69
70pub(crate) use unreachable_branch;