oftlisp/
symbol.rs

1// TODO Have this reviewed.
2
3use std::cmp::Ordering;
4use std::collections::BTreeSet;
5use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
6use std::mem::{forget, transmute};
7use std::ops::Deref;
8
9use gc::Trace;
10use spin::Mutex;
11
12lazy_static! {
13    static ref SYMBOL_HEAP: Mutex<BTreeSet<&'static str>> = Mutex::new(BTreeSet::new());
14}
15
16/// An interned string with O(1) equality.
17#[derive(Clone, Copy, Eq, Finalize, Hash, PartialOrd)]
18pub struct Symbol {
19    s: &'static str,
20}
21
22impl Symbol {
23    /// Retrieves the address of the backing string.
24    pub fn addr(self) -> usize {
25        self.s.as_ptr() as usize
26    }
27
28    /// Retrieves the string from the Symbol.
29    pub fn as_str(self) -> &'static str {
30        self.s
31    }
32}
33
34impl Debug for Symbol {
35    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
36        fmt.debug_tuple("Symbol").field(&self.s).finish()
37    }
38}
39
40impl Deref for Symbol {
41    type Target = str;
42    fn deref(&self) -> &str {
43        self.s
44    }
45}
46
47impl Display for Symbol {
48    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
49        fmt.write_str(self.s)
50    }
51}
52
53impl<S: AsRef<str>> From<S> for Symbol {
54    fn from(s: S) -> Symbol {
55        let s = s.as_ref();
56        {
57            let mut heap = SYMBOL_HEAP.lock();
58            if heap.get(s).is_none() {
59                let string = s.to_owned();
60                let s = unsafe { transmute(&string as &str) };
61                forget(string);
62                heap.insert(s);
63            }
64        }
65        let s = {
66            let heap = SYMBOL_HEAP.lock();
67            heap.get(s).unwrap().clone()
68        };
69        Symbol { s }
70    }
71}
72
73impl Ord for Symbol {
74    fn cmp(&self, other: &Self) -> Ordering {
75        let l = self.addr();
76        let r = other.addr();
77        l.cmp(&r)
78    }
79}
80
81impl PartialEq for Symbol {
82    fn eq(&self, other: &Self) -> bool {
83        self.cmp(other) == Ordering::Equal
84    }
85}
86
87unsafe impl Trace for Symbol {
88    unsafe_empty_trace!();
89}