1
#![forbid(unsafe_code)]
2

            
3
use merc_macros::merc_derive_terms;
4
use merc_utilities::MercError;
5

            
6
use crate::ATermRead;
7
use crate::ATermStreamable;
8
use crate::ATermWrite;
9
use crate::Symb;
10
use crate::Term;
11

            
12
/// Returns true if the term is a string term
13
28992
fn is_string_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
14
28992
    t.get_head_symbol().arity() == 0
15
28992
}
16

            
17
#[merc_derive_terms]
18
mod inner {
19
    use std::fmt;
20

            
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::Symb;
32
    use crate::Symbol;
33
    use crate::SymbolRef;
34
    use crate::Term;
35
    use crate::TermIterator;
36
    use crate::Transmutable;
37
    use crate::aterm_string::is_string_term;
38
    use crate::storage::Marker;
39
    use crate::storage::THREAD_TERM_POOL;
40

            
41
    #[merc_term(is_string_term)]
42
    pub struct ATermString {
43
        term: ATerm,
44
    }
45

            
46
    impl ATermString {
47
        #[merc_ignore]
48
398369
        pub fn new<S>(string: S) -> Self
49
398369
        where
50
398369
            S: Into<String> + AsRef<str>,
51
        {
52
398369
            THREAD_TERM_POOL.with_borrow(|tp| ATermString {
53
398369
                term: tp.create_constant(&Symbol::new(string, 0)),
54
398369
            })
55
398369
        }
56

            
57
        /// Get the value of the string
58
25794
        pub fn value(&self) -> &str {
59
25794
            self.term.get_head_symbol().name()
60
25794
        }
61
    }
62

            
63
    #[merc_ignore]
64
    impl From<&str> for ATermString {
65
173584
        fn from(s: &str) -> Self {
66
173584
            ATermString::new(s)
67
173584
        }
68
    }
69

            
70
    impl fmt::Display for ATermString {
71
25761
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72
25761
            write!(f, "{}", self.value())
73
25761
        }
74
    }
75
}
76

            
77
pub use inner::*;
78

            
79
impl PartialEq<str> for ATermString {
80
    fn eq(&self, other: &str) -> bool {
81
        self.value() == other
82
    }
83
}
84

            
85
impl PartialEq<&str> for ATermStringRef<'_> {
86
32
    fn eq(&self, other: &&str) -> bool {
87
32
        self.value() == *other
88
32
    }
89
}
90

            
91
// Helper to write a string immediately.
92
impl ATermStreamable for String {
93
    fn write<W: ATermWrite>(&self, writer: &mut W) -> Result<(), MercError> {
94
        writer.write_aterm(&ATermString::new(self.clone()))
95
    }
96

            
97
    fn read<R: ATermRead>(reader: &mut R) -> Result<Self, MercError>
98
    where
99
        Self: Sized,
100
    {
101
        let term: ATermString = reader.read_aterm()?.ok_or("Expected a string ATerm")?.into();
102
        Ok(term.value().to_string())
103
    }
104
}
105

            
106
#[cfg(test)]
107
mod tests {
108
    use crate::ATermString;
109

            
110
    #[test]
111
1
    fn test_string() {
112
1
        let _ = merc_utilities::test_logger();
113

            
114
1
        let s = ATermString::new("test");
115
1
        assert_eq!(s.value(), "test");
116
1
        assert_eq!(s.to_string(), "test");
117
1
    }
118
}