1
#![forbid(unsafe_code)]
2

            
3
use std::fmt;
4

            
5
use delegate::delegate;
6

            
7
use merc_macros::merc_derive_terms;
8
use merc_macros::merc_ignore;
9
use merc_macros::merc_term;
10
use merc_utilities::MercError;
11

            
12
use crate::ATerm;
13

            
14
use crate::ATermArgs;
15
use crate::ATermIndex;
16
use crate::ATermRead;
17
use crate::ATermRef;
18
use crate::ATermStreamable;
19
use crate::ATermWrite;
20
use crate::Markable;
21
use crate::Symb;
22
use crate::Symbol;
23
use crate::SymbolRef;
24
use crate::Term;
25
use crate::TermIterator;
26
use crate::Transmutable;
27
use crate::storage::Marker;
28
use crate::storage::THREAD_TERM_POOL;
29

            
30
/// Returns true if the term is a string term
31
17220
fn is_string_term<'a, 'b, T: Term<'a, 'b>>(t: &'b T) -> bool {
32
17220
    t.get_head_symbol().arity() == 0
33
17220
}
34

            
35
#[merc_derive_terms]
36
mod inner {
37
    use super::*;
38

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

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

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

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

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

            
75
pub use inner::*;
76

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

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

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

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

            
104
#[cfg(test)]
105
mod tests {
106
    use super::*;
107

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

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