racer_interner/
lib.rs

1//! string interner
2//! same as cargo::core::interning.rs, but thread local and Deserializable
3
4extern crate serde;
5use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
6
7use std::cell::RefCell;
8use std::cmp::Ordering;
9use std::collections::HashSet;
10use std::error::Error;
11use std::fmt;
12use std::hash::{Hash, Hasher};
13use std::ops::Deref;
14use std::ptr;
15use std::str;
16
17fn leak(s: String) -> &'static str {
18    Box::leak(s.into_boxed_str())
19}
20
21thread_local! {
22    static STRING_CACHE: RefCell<HashSet<&'static str>> = Default::default();
23}
24
25#[derive(Clone, Copy)]
26pub struct InternedString {
27    inner: &'static str,
28}
29
30impl PartialEq for InternedString {
31    fn eq(&self, other: &InternedString) -> bool {
32        ptr::eq(self.as_str(), other.as_str())
33    }
34}
35
36impl Eq for InternedString {}
37
38impl InternedString {
39    pub fn new(st: &str) -> InternedString {
40        STRING_CACHE.with(|cache| {
41            let mut cache = cache.borrow_mut();
42            let s = cache.get(st).map(|&s| s).unwrap_or_else(|| {
43                let s = leak(st.to_string());
44                cache.insert(s);
45                s
46            });
47            InternedString { inner: s }
48        })
49    }
50
51    pub fn new_if_exists(st: &str) -> Option<InternedString> {
52        STRING_CACHE.with(|cache| cache.borrow().get(st).map(|&s| InternedString { inner: s }))
53    }
54
55    pub fn as_str(&self) -> &'static str {
56        self.inner
57    }
58}
59
60impl Deref for InternedString {
61    type Target = str;
62
63    fn deref(&self) -> &'static str {
64        self.as_str()
65    }
66}
67
68impl Hash for InternedString {
69    fn hash<H: Hasher>(&self, state: &mut H) {
70        Hash::hash(&(self.inner as *const str), state)
71    }
72}
73
74impl fmt::Debug for InternedString {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        fmt::Debug::fmt(self.as_str(), f)
77    }
78}
79
80impl fmt::Display for InternedString {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        fmt::Display::fmt(self.as_str(), f)
83    }
84}
85
86impl Ord for InternedString {
87    fn cmp(&self, other: &InternedString) -> Ordering {
88        self.as_str().cmp(other.as_str())
89    }
90}
91
92impl PartialOrd for InternedString {
93    fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
94        Some(self.cmp(other))
95    }
96}
97
98impl Serialize for InternedString {
99    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
100    where
101        S: Serializer,
102    {
103        serializer.serialize_str(self.inner)
104    }
105}
106
107impl<'de> Deserialize<'de> for InternedString {
108    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
109    where
110        D: Deserializer<'de>,
111    {
112        struct VisStr;
113        impl<'de> Visitor<'de> for VisStr {
114            type Value = InternedString;
115            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
116                write!(f, "expecting string")
117            }
118            fn visit_borrowed_str<E: Error>(self, v: &'de str) -> Result<InternedString, E> {
119                Ok(InternedString::new(v))
120            }
121        }
122        deserializer.deserialize_str(VisStr {})
123    }
124}