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
4240
fn is_string_term<'a, 'b>(t: &'b impl Term<'a, 'b>) -> bool {
32
4240
    t.get_head_symbol().arity() == 0
33
4240
}
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
211181
        pub fn new(string: impl Into<String> + AsRef<str>) -> Self {
47
211181
            THREAD_TERM_POOL.with_borrow(|tp| ATermString {
48
211181
                term: tp.create_constant(&Symbol::new(string, 0)),
49
211181
            })
50
211181
        }
51

            
52
        /// Get the value of the string
53
2242
        pub fn value(&self) -> &str {
54
2242
            self.term.get_head_symbol().name()
55
2242
        }
56
    }
57

            
58
    #[merc_ignore]
59
    impl From<&str> for ATermString {
60
22070
        fn from(s: &str) -> Self {
61
22070
            ATermString::new(s)
62
22070
        }
63
    }
64

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

            
72
pub use inner::*;
73

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

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

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

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

            
101
#[cfg(test)]
102
mod tests {
103
    use super::*;
104

            
105
    #[test]
106
1
    fn test_string() {
107
1
        let _ = merc_utilities::test_logger();
108

            
109
1
        let s = ATermString::new("test");
110
1
        assert_eq!(s.value(), "test");
111
1
        assert_eq!(s.to_string(), "test");
112
1
    }
113
}