string_intern/
base_type.rs1use std::cmp::Ordering;
2use std::fmt;
3use std::ops::{Deref, Drop};
4use std::hash::{Hash, Hasher};
5use std::str::FromStr;
6use std::marker::PhantomData;
7use std::borrow::Borrow;
8use std::sync::{Arc, RwLock, Weak};
9use std::collections::HashMap;
10use std::collections::hash_map::Entry::{Occupied, Vacant};
11
12#[cfg(feature = "serde")] use serde::ser::{Serialize, Serializer};
13#[cfg(feature = "serde")] use serde::de::{self, Deserialize, Deserializer, Visitor};
14#[cfg(feature = "rustc-serialize")] use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
15use {Validator};
16
17lazy_static! {
18 static ref ATOMS: RwLock<HashMap<Buf, Weak<Value>>> =
19 RwLock::new(HashMap::new());
20}
21
22pub struct Symbol<V: Validator + ?Sized>(Arc<Value>, PhantomData<V>);
31
32#[derive(PartialEq, Eq, Hash)]
33struct Buf(Arc<String>);
34
35#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
36struct Value(Arc<String>);
37
38impl<V: Validator + ?Sized> Clone for Symbol<V> {
39 fn clone(&self) -> Symbol<V> {
40 Symbol(self.0.clone(), PhantomData)
41 }
42}
43
44impl<V: Validator + ?Sized> PartialEq for Symbol<V> {
45 fn eq(&self, other: &Symbol<V>) -> bool {
46 self.0.eq(&other.0)
47 }
48}
49impl<V: Validator + ?Sized> Eq for Symbol<V> {}
50
51impl<V: Validator + ?Sized> Hash for Symbol<V> {
52 fn hash<H: Hasher>(&self, hasher: &mut H) {
53 self.0.hash(hasher)
54 }
55}
56
57impl<V: Validator + ?Sized> PartialOrd for Symbol<V> {
58 fn partial_cmp(&self, other: &Symbol<V>) -> Option<Ordering> {
59 self.0.partial_cmp(&other.0)
60 }
61}
62
63impl<V: Validator + ?Sized> Ord for Symbol<V> {
64 fn cmp(&self, other: &Symbol<V>) -> Ordering {
65 self.0.cmp(&other.0)
66 }
67}
68
69
70impl<V: Validator + ?Sized> FromStr for Symbol<V> {
71 type Err = V::Err;
72 fn from_str(s: &str) -> Result<Symbol<V>, Self::Err> {
73 V::validate_symbol(s)?;
74 if let Some(a) = ATOMS.read().expect("atoms locked").get(s) {
75 if let Some(a) = a.upgrade() {
76 return Ok(Symbol(a.clone(), PhantomData));
77 }
78 }
84 let buf = Arc::new(String::from(s));
85 let mut atoms = ATOMS.write().expect("atoms locked");
86 let val = match atoms.entry(Buf(buf.clone())) {
87 Occupied(mut e) => match e.get().upgrade() {
88 Some(a) => a,
89 None => {
90 let result = Arc::new(Value(buf));
91 e.insert(Arc::downgrade(&result));
92 result
93 }
94 },
95 Vacant(e) => {
96 let result = Arc::new(Value(buf));
97 e.insert(Arc::downgrade(&result));
98 result
99 }
100 };
101 Ok(Symbol(val, PhantomData))
102 }
103}
104
105impl Drop for Value {
106 fn drop(&mut self) {
107 let mut atoms = ATOMS.write().expect("atoms locked");
108 atoms.remove(&self.0[..]);
109 }
110}
111
112impl<V: Validator + ?Sized> AsRef<str> for Symbol<V> {
113 fn as_ref(&self) -> &str {
114 &(self.0).0[..]
115 }
116}
117
118impl<V: Validator + ?Sized> Borrow<str> for Symbol<V> {
119 fn borrow(&self) -> &str {
120 &(self.0).0[..]
121 }
122}
123
124impl<V: Validator + ?Sized> Borrow<String> for Symbol<V> {
125 fn borrow(&self) -> &String {
126 &(self.0).0
127 }
128}
129
130impl Borrow<str> for Buf {
131 fn borrow(&self) -> &str {
132 &self.0
133 }
134}
135
136impl Borrow<String> for Buf {
137 fn borrow(&self) -> &String {
138 &self.0
139 }
140}
141
142
143impl<V: Validator + ?Sized> fmt::Debug for Symbol<V> {
144 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
145 V::display(self, fmt)
146 }
147}
148
149impl<V: Validator + ?Sized> fmt::Display for Symbol<V> {
150 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
151 (self.0).0.fmt(fmt)
152 }
153}
154
155#[cfg(feature = "rustc-serialize")]
156impl<V: Validator> Decodable for Symbol<V> {
157 fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
158 use std::error::Error;
159 d.read_str()?
160 .parse::<Symbol<V>>()
161 .map_err(|e| d.error(e.description()))
162 }
163}
164
165#[cfg(feature = "rustc-serialize")]
166impl<V: Validator> Encodable for Symbol<V> {
167 fn encode<E: Encoder>(&self, d: &mut E) -> Result<(), E::Error> {
168 d.emit_str(&(self.0).0)
169 }
170}
171
172#[cfg(feature = "serde")]
173struct SymbolVisitor<V: Validator>(PhantomData<V>);
174
175#[cfg(feature = "serde")]
176impl<'de, V: Validator> Visitor<'de> for SymbolVisitor<V> {
177 type Value = Symbol<V>;
178
179 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
180 formatter.write_str("a valid symbol")
181 }
182
183 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
184 where E: de::Error
185 {
186 v.parse().map_err(de::Error::custom)
187 }
188}
189
190#[cfg(feature = "serde")]
191impl<'de, V: Validator> Deserialize<'de> for Symbol<V> {
192 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
193 where D: Deserializer<'de>
194 {
195 deserializer.deserialize_str(SymbolVisitor(PhantomData))
196 }
197}
198
199#[cfg(feature = "serde")]
200impl<V: Validator> Serialize for Symbol<V> {
201 fn serialize<S: Serializer>(&self, serializer: S)
202 -> Result<S::Ok, S::Error>
203 {
204 serializer.serialize_str(&(self.0).0)
205 }
206}
207
208impl<V: Validator + ?Sized> Deref for Symbol<V> {
209 type Target = str;
210 fn deref(&self) -> &str {
211 &(self.0).0
212 }
213}
214
215impl<V: Validator + ?Sized> Symbol<V> {
216 pub fn from(s: &'static str) -> Symbol<V> {
225 FromStr::from_str(s)
226 .expect("static string used as atom is invalid")
227 }
228}
229
230#[cfg(test)]
231mod test {
232 use std::io;
233 use rustc_serialize::json;
234 use {Validator, Symbol};
235 use serde_json;
236
237 #[allow(dead_code)]
238 struct AnyString;
239 #[allow(dead_code)]
240 struct AlphaNumString;
241 type Atom = Symbol<AnyString>;
242 type AlphaNum = Symbol<AlphaNumString>;
243
244 impl Validator for AnyString {
245 type Err = ::std::string::ParseError;
247 fn validate_symbol(_: &str) -> Result<(), Self::Err> {
248 Ok(())
249 }
250 }
251
252 impl Validator for AlphaNumString {
253 type Err = io::Error;
255 fn validate_symbol(s: &str) -> Result<(), Self::Err> {
256 if s.chars().any(|c| !c.is_alphanumeric()) {
257 return Err(io::Error::new(io::ErrorKind::InvalidData,
258 "Character is not alphanumeric"));
259 }
260 Ok(())
261 }
262 }
263
264 #[test]
265 fn eq() {
266 assert_eq!(Atom::from("x"), Atom::from("x"));
267 }
268
269 #[test]
270 fn ord() {
271 assert!(Atom::from("a") < Atom::from("b"));
272 }
273
274 #[test]
275 fn clone() {
276 assert_eq!(Atom::from("x").clone(), Atom::from("x"));
277 }
278
279 #[test]
280 fn hash() {
281 use std::collections::HashMap;
282 let mut h = HashMap::new();
283 h.insert(Atom::from("x"), 123);
284 assert_eq!(h.get("x"), Some(&123));
285 assert_eq!(h.get(&Atom::from("x")), Some(&123));
286 assert_eq!(h.get("y"), None);
287 assert_eq!(h.get(&Atom::from("y")), None);
288 }
289
290 #[test]
291 fn encode() {
292 assert_eq!(json::encode(&Atom::from("xyz")).unwrap(),
293 r#""xyz""#);
294 }
295 #[test]
296 fn decode() {
297 assert_eq!(json::decode::<Atom>(r#""xyz""#).unwrap(),
298 Atom::from("xyz"));
299 }
300
301 #[test]
302 fn encode_serde() {
303 assert_eq!(serde_json::to_string(&Atom::from("xyz")).unwrap(),
304 r#""xyz""#);
305 }
306
307 #[test]
308 fn decode_serde() {
309 assert_eq!(serde_json::from_str::<Atom>(r#""xyz""#).unwrap(),
310 Atom::from("xyz"));
311 }
312
313 #[test]
314 #[should_panic(message="static strings used as atom is invalid")]
315 fn distinct_validators() {
316 let _xa = Atom::from("x");
317 let _xn = AlphaNum::from("x");
318 let _ya = Atom::from("a-b");
319 let _yn = AlphaNum::from("a-b");
321 }
322}