1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::rc::Rc;

pub type TabledData<T> = Rc<RefCell<HashSet<Rc<T>>>>;

pub struct TabledRc<T: Hash + Eq> {
    atom: Rc<T>,
    table: TabledData<T>
}

// this Clone instance is manually defined to prevent the compiler
// from complaining when deriving Clone for StringList.
impl<T: Hash + Eq> Clone for TabledRc<T> {
    fn clone(&self) -> Self {
        TabledRc { atom: self.atom.clone(), table: self.table().clone() }
    }
}

impl<T: Ord + Hash + Eq> PartialOrd for TabledRc<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering>
    {
        Some(self.atom.cmp(&other.atom))
    }
}

impl<T: Ord + Hash + Eq> Ord for TabledRc<T> {
    fn cmp(&self, other: &Self) -> Ordering
    {
        self.atom.cmp(&other.atom)
    }
}

impl<T: Hash + Eq> PartialEq for TabledRc<T> {
    fn eq(&self, other: &TabledRc<T>) -> bool
    {
        self.atom == other.atom
    }
}

impl<T: Hash + Eq> Eq for TabledRc<T> {}

impl<T: Hash + Eq> Hash for TabledRc<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.atom.hash(state)
    }
}

impl<T: Hash + Eq> TabledRc<T> {
    pub fn new(atom: T, table: TabledData<T>) -> Self {
        let atom = match table.borrow_mut().take(&atom) {
            Some(atom) => atom.clone(),
            None => Rc::new(atom)
        };

        table.borrow_mut().insert(atom.clone());

        TabledRc { atom, table }
    }

    pub fn table(&self) -> TabledData<T> {
        self.table.clone()
    }
}

impl<T: Hash + Eq> Drop for TabledRc<T> {
    fn drop(&mut self) {
        if Rc::strong_count(&self.atom) == 2 {
            self.table.borrow_mut().remove(&self.atom);
        }
    }
}

impl<T: Hash + Eq> Deref for TabledRc<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &*self.atom
    }
}

impl<T: Hash + Eq + fmt::Display> fmt::Display for TabledRc<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &*self.atom)
    }
}

#[macro_export]
macro_rules! tabled_rc {
    ($e:expr, $tbl:expr) => (
        TabledRc::new(String::from($e), $tbl.clone())
    )
}