use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;
use std::rc::Rc;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Name(pub u32);
impl Name {
pub fn is_case_sensitive(&self) -> bool {
self.0 & 1 == 1
}
pub fn as_str(self) -> RcStr {
get_name_table().get(self)
}
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}({})", self, self.0)
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.as_str(), f)
}
}
impl Encodable for Name {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_bool(self.is_case_sensitive())?;
s.emit_str(self.as_str().borrow())?;
Ok(())
}
}
impl Decodable for Name {
fn decode<S: Decoder>(s: &mut S) -> Result<Name, S::Error> {
let case = s.read_bool()?;
let name = s.read_str()?;
Ok(get_name_table().intern(&name, case))
}
}
impl Into<String> for Name {
fn into(self) -> String {
self.as_str().into()
}
}
impl<'a> From<&'a str> for Name {
fn from(s: &'a str) -> Name {
get_name_table().intern(s, true)
}
}
#[derive(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr(Rc<String>);
impl RcStr {
pub fn new(value: &str) -> RcStr {
RcStr(Rc::new(value.to_string()))
}
pub fn from(value: String) -> RcStr {
RcStr(Rc::new(value))
}
}
impl Eq for RcStr {}
impl Ord for RcStr {
fn cmp(&self, other: &RcStr) -> Ordering {
self[..].cmp(&other[..])
}
}
impl fmt::Debug for RcStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self[..].fmt(f)
}
}
impl fmt::Display for RcStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self[..].fmt(f)
}
}
impl Borrow<str> for RcStr {
fn borrow(&self) -> &str {
&self.0[..]
}
}
impl Deref for RcStr {
type Target = str;
fn deref(&self) -> &str {
&self.0[..]
}
}
impl Into<String> for RcStr {
fn into(self) -> String {
(*self.0).clone()
}
}
pub struct NameTable {
map: RefCell<HashMap<RcStr, Name>>,
vect: RefCell<Vec<RcStr>>,
}
impl NameTable {
pub fn new() -> NameTable {
NameTable {
map: RefCell::new(HashMap::new()),
vect: RefCell::new(Vec::new()),
}
}
pub fn intern(&self, value: &str, case_sensitive: bool) -> Name {
let mut map = self.map.borrow_mut();
if let Some(&idx) = map.get(value) {
return idx;
}
let mut vect = self.vect.borrow_mut();
if case_sensitive {
let new_idx = Name((vect.len() as u32) << 1 | 1);
let v = RcStr::new(value);
map.insert(v.clone(), new_idx);
vect.push(v);
new_idx
} else {
let new_idx = Name((vect.len() as u32) << 1 | 0);
let lower = value.to_lowercase();
if let Some(&idx) = map.get(lower.as_str()) {
return idx;
}
let v = RcStr::new(value);
map.insert(RcStr::from(lower), new_idx);
map.insert(v.clone(), new_idx);
vect.push(v);
new_idx
}
}
pub fn get(&self, idx: Name) -> RcStr {
(*self.vect.borrow())[(idx.0 >> 1) as usize].clone()
}
pub fn find<Q: ?Sized>(&self, value: &Q) -> Option<Name>
where
RcStr: Borrow<Q>,
Q: Eq + Hash,
{
(*self.map.borrow()).get(value).map(|v| *v)
}
}
pub fn get_name_table() -> Rc<NameTable> {
thread_local!(static TBL: Rc<NameTable> = {
let nt = NameTable::new();
Rc::new(nt)
});
TBL.with(|x| x.clone())
}