use super::intern::InternStr;
use std::fmt;
use std::sync::atomic;
static COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(1);
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Ident {
pub name: InternStr,
pub index: usize,
}
impl Ident {
pub fn fresh<S: AsRef<str>>(s: &S) -> Ident {
let name = InternStr::new(s.as_ref());
let index = COUNTER.fetch_add(1, atomic::Ordering::Relaxed);
Ident { name, index }
}
pub fn dummy<S: AsRef<str>>(s: &S) -> Ident {
let name = InternStr::new(s.as_ref());
Ident { name, index: 0 }
}
pub fn is_dummy(&self) -> bool {
self.index == 0
}
pub fn uniquify(&self) -> Ident {
let name = self.name;
let index = COUNTER.fetch_add(1, atomic::Ordering::Relaxed);
Ident { name, index }
}
pub fn as_str(&self) -> &'static str {
self.name.as_str()
}
pub fn tag_ctx(self, ctx: usize) -> IdentCtx {
IdentCtx { ident: self, ctx }
}
}
impl fmt::Debug for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_dummy() {
write!(f, "{:?}", self.name)
} else {
write!(f, "{:?}_{:?}", self.name, self.index)
}
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl AsRef<str> for Ident {
fn as_ref(&self) -> &str {
self.name.as_str()
}
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct IdentCtx {
pub ident: Ident,
pub ctx: usize,
}
impl fmt::Debug for IdentCtx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}_{:?}", self.ident, self.ctx)
}
}
impl fmt::Display for IdentCtx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}_{}", self.ident, self.ctx)
}
}
#[test]
fn ident_fresh_test() {
let s1 = InternStr::new("foo");
let x1 = Ident::fresh(&s1);
let x2 = Ident::fresh(&s1);
let x3 = Ident::fresh(&s1);
assert_ne!(x1, x2);
assert_ne!(x1, x3);
assert_ne!(x2, x3);
assert_eq!(x1.name, x2.name);
assert_eq!(x1.name, x3.name);
assert_eq!(x2.name, x3.name);
}
#[test]
fn ident_uniquify_test() {
let s1 = InternStr::new("foo");
let x1 = Ident::fresh(&s1);
let x2 = x1.uniquify();
assert_ne!(x1, x2);
assert_eq!(x1.name, x2.name);
}