1
use std::fmt;
2

            
3
use merc_macros::merc_derive_terms;
4

            
5
use crate::Symb;
6
use crate::Term;
7
use crate::storage::THREAD_TERM_POOL;
8

            
9
/// Returns true if the term is an [ATermInt] term.
10
1094333353
pub fn is_int_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
11
1094333353
    THREAD_TERM_POOL.with_borrow(|tp| *tp.int_symbol() == t.get_head_symbol())
12
1094333353
}
13

            
14
/// Returns true if the given symbol is the special integer symbol used by [ATermInt].
15
245363
pub fn is_int_symbol<'a, 'b, S: Symb<'a, 'b>>(f: &'b S) -> bool {
16
245363
    THREAD_TERM_POOL.with_borrow(|tp| *tp.int_symbol() == f.copy())
17
245363
}
18

            
19
#[merc_derive_terms]
20
mod inner {
21
    use delegate::delegate;
22

            
23
    use merc_macros::merc_ignore;
24
    use merc_macros::merc_term;
25

            
26
    use crate::ATerm;
27
    use crate::ATermArgs;
28
    use crate::ATermIndex;
29
    use crate::ATermRef;
30
    use crate::Markable;
31
    use crate::SymbolRef;
32
    use crate::Term;
33
    use crate::TermIterator;
34
    use crate::Transmutable;
35
    use crate::is_int_term;
36
    use crate::storage::Marker;
37
    use crate::storage::SharedTermInt;
38
    use crate::storage::THREAD_TERM_POOL;
39

            
40
    /// This is a wrapper around the [ATerm] type that stores a single `u64` using an annotation.
41
    #[merc_term(is_int_term)]
42
    pub struct ATermInt {
43
        term: ATerm,
44
    }
45

            
46
    impl ATermInt {
47
        #[merc_ignore]
48
6438188
        pub fn new(value: usize) -> ATermInt {
49
6438188
            THREAD_TERM_POOL.with_borrow(|tp| ATermInt {
50
6438188
                term: tp.create_int(value),
51
6438188
            })
52
6438188
        }
53

            
54
        /// Returns the value of the integer term.
55
        ///
56
        /// # Safety
57
        ///
58
        /// This method assumes that the term is indeed an integer term, which
59
        /// should be guaranteed by the constructor and the `is_int_term`
60
        /// function. Otherwise, it leads to undefined behaviour.
61
6438844
        pub fn value(&self) -> usize {
62
6438844
            unsafe { self.shared().ptr().cast::<SharedTermInt>().as_ref().value() }
63
6438844
        }
64
    }
65
}
66

            
67
impl fmt::Display for ATermInt {
68
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69
        write!(f, "{}", self.value())
70
    }
71
}
72

            
73
impl fmt::Display for ATermIntRef<'_> {
74
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75
        write!(f, "{}", self.value())
76
    }
77
}
78

            
79
pub use inner::*;
80

            
81
#[cfg(test)]
82
mod tests {
83
    use merc_utilities::test_logger;
84

            
85
    use crate::ATermInt;
86
    use crate::is_int_term;
87

            
88
    #[test]
89
1
    fn test_int_term() {
90
1
        let _ = test_logger();
91

            
92
1
        let int_term = ATermInt::new(42);
93
1
        assert_eq!(int_term.value(), 42);
94
1
        assert!(is_int_term(&int_term));
95
1
    }
96
}