1
use std::cmp::Ordering;
2
use std::fmt;
3
use std::hash::Hash;
4
use std::hash::Hasher;
5
use std::marker::PhantomData;
6

            
7
use delegate::delegate;
8

            
9
use merc_unsafety::ProtectionIndex;
10
use merc_unsafety::StablePointer;
11

            
12
use crate::Markable;
13
use crate::storage::Marker;
14
use crate::storage::SharedSymbol;
15
use crate::storage::THREAD_TERM_POOL;
16

            
17
/// The public interface for a function symbol. Can be used to write generic
18
/// functions that accept both [Symbol] and [SymbolRef].
19
///
20
/// See [crate::Term] for more information on how to use this trait with two lifetimes.
21
pub trait Symb<'a, 'b> {
22
    /// Obtain the symbol's name.
23
    fn name(&'b self) -> &'a str;
24

            
25
    /// Obtain the symbol's arity.
26
    fn arity(&self) -> usize;
27

            
28
    /// Create a copy of the symbol reference.
29
    fn copy(&'b self) -> SymbolRef<'a>;
30

            
31
    /// Returns a unique index for the symbol.
32
    fn index(&self) -> usize;
33

            
34
    /// TODO: How to actually hide this implementation?
35
    fn shared(&self) -> &SymbolIndex;
36
}
37

            
38
/// An alias for the type that is used to reference into the [SharedSymbol] set.
39
pub type SymbolIndex = StablePointer<SharedSymbol>;
40

            
41
/// A reference to a function symbol in the symbol pool.
42
#[repr(transparent)]
43
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
44
pub struct SymbolRef<'a> {
45
    shared: SymbolIndex,
46
    marker: PhantomData<&'a ()>,
47
}
48

            
49
/// Check that the SymbolRef is the same size as a usize.
50
#[cfg(not(debug_assertions))]
51
const _: () = assert!(std::mem::size_of::<SymbolRef>() == std::mem::size_of::<usize>());
52

            
53
/// Check that the Option<SymbolRef> is the same size as a usize using niche value optimisation.
54
#[cfg(not(debug_assertions))]
55
const _: () = assert!(std::mem::size_of::<Option<SymbolRef>>() == std::mem::size_of::<usize>());
56

            
57
/// A reference to a function symbol with a known lifetime.
58
impl<'a> SymbolRef<'a> {
59
    /// Protects the symbol from garbage collection, yielding a `Symbol`.
60
    pub fn protect(&self) -> Symbol {
61
        THREAD_TERM_POOL.with(|tp| tp.protect_symbol(self))
62
    }
63

            
64
    /// Internal constructor to create a [SymbolRef] from a [SymbolIndex].
65
    ///
66
    /// # Safety
67
    ///
68
    /// We must ensure that the lifetime `'a` is valid for the returned `SymbolRef`.
69
26292370495
    pub unsafe fn from_index(index: &SymbolIndex) -> SymbolRef<'a> {
70
26292370495
        SymbolRef {
71
26292370495
            // SAFETY: the caller guarantees the index remains valid for `'a`.
72
26292370495
            shared: unsafe { index.copy() },
73
26292370495
            marker: PhantomData,
74
26292370495
        }
75
26292370495
    }
76
}
77

            
78
impl SymbolRef<'_> {
79
    /// Internal constructor to convert any `Symb` to a `SymbolRef`.
80
105659003
    pub(crate) fn from_symbol<'a, 'b, S: Symb<'a, 'b>>(symbol: &'b S) -> Self {
81
105659003
        SymbolRef {
82
105659003
            // SAFETY: `symbol` keeps the index alive during this call.
83
105659003
            shared: unsafe { symbol.shared().copy() },
84
105659003
            marker: PhantomData,
85
105659003
        }
86
105659003
    }
87
}
88

            
89
impl<'a> Symb<'a, '_> for SymbolRef<'a> {
90
3172099
    fn name(&self) -> &'a str {
91
3172099
        unsafe { std::mem::transmute(self.shared.deref().name()) }
92
3172099
    }
93

            
94
4088965880
    fn arity(&self) -> usize {
95
        // SAFETY: `self` is a `SymbolRef<'a>`, so the symbol is kept alive for
96
        // `'a` and the pointee is valid to read.
97
4088965880
        unsafe { self.shared.deref() }.arity()
98
4088965880
    }
99

            
100
26260288290
    fn copy(&self) -> SymbolRef<'a> {
101
26260288290
        unsafe { SymbolRef::from_index(self.shared()) }
102
26260288290
    }
103

            
104
    fn index(&self) -> usize {
105
        // SAFETY: see `arity`; the symbol is alive for `'a`.
106
        unsafe { self.shared.deref() }.index()
107
    }
108

            
109
26449781603
    fn shared(&self) -> &SymbolIndex {
110
26449781603
        &self.shared
111
26449781603
    }
112
}
113

            
114
impl Markable for SymbolRef<'_> {
115
6805999
    fn mark(&self, marker: &mut Marker) {
116
6805999
        marker.mark_symbol(self);
117
6805999
    }
118

            
119
    fn contains_term(&self, _term: &crate::aterm::ATermRef<'_>) -> bool {
120
        false
121
    }
122

            
123
758879
    fn contains_symbol(&self, symbol: &SymbolRef<'_>) -> bool {
124
758879
        self == symbol
125
758879
    }
126

            
127
    fn len(&self) -> usize {
128
        1
129
    }
130
}
131

            
132
impl fmt::Display for SymbolRef<'_> {
133
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134
        write!(f, "{}", self.name())
135
    }
136
}
137

            
138
impl fmt::Debug for SymbolRef<'_> {
139
1466358
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140
1466358
        write!(f, "{}", self.name())
141
1466358
    }
142
}
143

            
144
/// A protected function symbol, with the same interface as [SymbolRef].
145
pub struct Symbol {
146
    symbol: SymbolRef<'static>,
147
    root: ProtectionIndex,
148
}
149

            
150
impl Symbol {
151
    /// Create a new symbol with the given name and arity.
152
6485410
    pub fn new<N>(name: N, arity: usize) -> Symbol
153
6485410
    where
154
6485410
        N: Into<String> + AsRef<str>,
155
    {
156
6485410
        THREAD_TERM_POOL.with(|tp| tp.create_symbol(name, arity))
157
6485410
    }
158
}
159

            
160
impl Symbol {
161
    /// Internal constructor to create a symbol from an index and a root.
162
6788112
    pub(crate) unsafe fn from_index(index: &SymbolIndex, root: ProtectionIndex) -> Symbol {
163
6788112
        Self {
164
6788112
            symbol: unsafe { SymbolRef::from_index(index) },
165
6788112
            root,
166
6788112
        }
167
6788112
    }
168

            
169
    /// Returns the root index, i.e., the index in the protection set. See [crate::storage::SharedTermProtection].
170
6761616
    pub fn root(&self) -> ProtectionIndex {
171
6761616
        self.root
172
6761616
    }
173

            
174
    /// Create a copy of the symbol reference.
175
9130658671
    pub fn copy(&self) -> SymbolRef<'_> {
176
9130658671
        self.symbol.copy()
177
9130658671
    }
178

            
179
    /// Returns the symbol as a borrowed [SymbolRef] whose lifetime is bounded
180
    /// by this protected symbol.
181
2552099067
    pub fn get(&self) -> &SymbolRef<'_> {
182
2552099067
        &self.symbol
183
2552099067
    }
184
}
185

            
186
impl<'a> Symb<'a, '_> for &'a Symbol {
187
    delegate! {
188
        to self.symbol {
189
            fn name(&self) -> &'a str;
190
            fn arity(&self) -> usize;
191
            fn copy(&self) -> SymbolRef<'a>;
192
            fn index(&self) -> usize;
193
            fn shared(&self) -> &SymbolIndex;
194
        }
195
    }
196
}
197

            
198
impl<'a, 'b> Symb<'a, 'b> for Symbol
199
where
200
    'b: 'a,
201
{
202
    delegate! {
203
        to self.symbol {
204
            fn name(&self) -> &'a str;
205
20838069
            fn arity(&self) -> usize;
206
15538
            fn copy(&self) -> SymbolRef<'a>;
207
            fn index(&self) -> usize;
208
7598380
            fn shared(&self) -> &SymbolIndex;
209
        }
210
    }
211
}
212

            
213
impl Drop for Symbol {
214
6761616
    fn drop(&mut self) {
215
6761616
        THREAD_TERM_POOL.with(|tp| {
216
6761616
            tp.drop_symbol(self);
217
6761616
        })
218
6761616
    }
219
}
220

            
221
impl From<&SymbolRef<'_>> for Symbol {
222
    fn from(value: &SymbolRef) -> Self {
223
        value.protect()
224
    }
225
}
226

            
227
impl Clone for Symbol {
228
    fn clone(&self) -> Self {
229
        self.copy().protect()
230
    }
231
}
232

            
233
impl fmt::Display for Symbol {
234
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235
        write!(f, "{}", self.name())
236
    }
237
}
238

            
239
impl fmt::Debug for Symbol {
240
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241
        write!(f, "{}", self.name())
242
    }
243
}
244

            
245
impl Hash for Symbol {
246
    fn hash<H: Hasher>(&self, state: &mut H) {
247
        self.copy().hash(state)
248
    }
249
}
250

            
251
impl PartialEq for Symbol {
252
1
    fn eq(&self, other: &Self) -> bool {
253
1
        self.copy().eq(&other.copy())
254
1
    }
255
}
256

            
257
impl PartialEq<SymbolRef<'_>> for Symbol {
258
    fn eq(&self, other: &SymbolRef<'_>) -> bool {
259
        self.copy().eq(other)
260
    }
261
}
262

            
263
impl PartialOrd for Symbol {
264
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
265
        Some(self.cmp(other))
266
    }
267
}
268

            
269
impl Ord for Symbol {
270
    fn cmp(&self, other: &Self) -> Ordering {
271
        self.copy().cmp(&other.copy())
272
    }
273
}
274

            
275
impl Eq for Symbol {}