string_intern/
base_type.rs

1use 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
22/// Base symbol type
23///
24/// To use this type you should define your own type of symbol:
25///
26/// ```ignore
27/// type MySymbol = Symbol<MyValidator>;
28/// ```
29// TODO(tailhook) optimize Eq to compare pointers
30pub 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            // We may get a race condition where atom has no strong references
79            // any more, but weak reference is still no removed because
80            // destructor is waiting for a lock in another thread.
81            //
82            // That's fine we'll get a write lock and recheck it later.
83        }
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    /// Create a symbol from a static string
217    ///
218    /// # Panics
219    ///
220    /// When symbol is of invalid format. We assume that this is used for
221    /// constant strings in source code, so we assert that they are valid.
222    ///
223    /// Use `FromStr::from_str(x)` or `x.parse()` to parse user input
224    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        // Use an error from standard library to make example shorter
246        type Err = ::std::string::ParseError;
247        fn validate_symbol(_: &str) -> Result<(), Self::Err> {
248            Ok(())
249        }
250    }
251
252    impl Validator for AlphaNumString {
253        // Use an error from standard library to make example shorter
254        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        // This should fail on invalid value, but didn't fail in <= v0.1.2
320        let _yn = AlphaNum::from("a-b");
321    }
322}