1
use std::borrow::Borrow;
2

            
3
use super::{literals::AbstractLiteral, Expression, Literal, Name};
4
use serde::{Deserialize, Serialize};
5
use uniplate::derive::Uniplate;
6

            
7
/// An `Atom` is an indivisible expression, such as a literal or a reference.
8
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
9
#[uniplate()]
10
#[biplate(to=Literal)]
11
#[biplate(to=Expression)]
12
#[biplate(to=AbstractLiteral<Literal>,walk_into=[Literal])]
13
#[biplate(to=Name)]
14
pub enum Atom {
15
    Literal(Literal),
16
    Reference(Name),
17
}
18

            
19
impl Atom {
20
    /// Shorthand to create a reference by user name.
21
144
    pub fn new_uref(name: &str) -> Atom {
22
144
        Atom::Reference(Name::UserName(name.to_string()))
23
144
    }
24
}
25

            
26
impl std::fmt::Display for Atom {
27
160884
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28
160884
        match self {
29
64872
            Atom::Literal(x) => x.fmt(f),
30
96012
            Atom::Reference(x) => x.fmt(f),
31
        }
32
160884
    }
33
}
34

            
35
impl From<Literal> for Atom {
36
    fn from(value: Literal) -> Self {
37
        Atom::Literal(value)
38
    }
39
}
40

            
41
impl From<Name> for Atom {
42
9270
    fn from(value: Name) -> Self {
43
9270
        Atom::Reference(value)
44
9270
    }
45
}
46

            
47
impl From<i32> for Atom {
48
    fn from(value: i32) -> Self {
49
        Atom::Literal(value.into())
50
    }
51
}
52

            
53
impl From<bool> for Atom {
54
    fn from(value: bool) -> Self {
55
        Atom::Literal(value.into())
56
    }
57
}
58

            
59
impl TryFrom<Expression> for Atom {
60
    type Error = &'static str;
61

            
62
666
    fn try_from(value: Expression) -> Result<Self, Self::Error> {
63
666
        match value {
64
576
            Expression::Atomic(_, atom) => Ok(atom),
65
90
            _ => Err("Cannot convert non-atomic expression to Atom"),
66
        }
67
666
    }
68
}
69

            
70
impl<'a> TryFrom<&'a Expression> for &'a Atom {
71
    type Error = &'static str;
72

            
73
216900
    fn try_from(value: &'a Expression) -> Result<Self, Self::Error> {
74
216900
        match value {
75
119412
            Expression::Atomic(_, atom) => Ok(atom),
76
97488
            _ => Err("Cannot convert non-atomic expression to Atom"),
77
        }
78
216900
    }
79
}
80

            
81
impl TryFrom<Box<Expression>> for Atom {
82
    type Error = &'static str;
83

            
84
162
    fn try_from(value: Box<Expression>) -> Result<Self, Self::Error> {
85
162
        (*value).try_into()
86
162
    }
87
}
88

            
89
impl<'a> TryFrom<&'a Box<Expression>> for &'a Atom {
90
    type Error = &'static str;
91

            
92
45558
    fn try_from(value: &'a Box<Expression>) -> Result<Self, Self::Error> {
93
45558
        let expr: &'a Expression = value.borrow();
94
45558
        expr.try_into()
95
45558
    }
96
}
97

            
98
impl TryFrom<Atom> for Literal {
99
    type Error = &'static str;
100

            
101
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
102
        match value {
103
            Atom::Literal(l) => Ok(l),
104
            _ => Err("Cannot convert non-literal atom to Literal"),
105
        }
106
    }
107
}
108

            
109
impl<'a> TryFrom<&'a Atom> for &'a Literal {
110
    type Error = &'static str;
111

            
112
51624
    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
113
51624
        match value {
114
1782
            Atom::Literal(l) => Ok(l),
115
49842
            _ => Err("Cannot convert non-literal atom to Literal"),
116
        }
117
51624
    }
118
}
119

            
120
impl TryFrom<Atom> for Name {
121
    type Error = &'static str;
122

            
123
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
124
        match value {
125
            Atom::Reference(n) => Ok(n),
126
            _ => Err("Cannot convert non-reference atom to Name"),
127
        }
128
    }
129
}
130

            
131
impl<'a> TryFrom<&'a Atom> for &'a Name {
132
    type Error = &'static str;
133

            
134
    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
135
        match value {
136
            Atom::Reference(n) => Ok(n),
137
            _ => Err("Cannot convert non-reference atom to Name"),
138
        }
139
    }
140
}
141

            
142
impl TryFrom<Atom> for i32 {
143
    type Error = &'static str;
144

            
145
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
146
        let lit: Literal = value.try_into()?;
147
        lit.try_into()
148
    }
149
}
150

            
151
impl TryFrom<&Atom> for i32 {
152
    type Error = &'static str;
153

            
154
45144
    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
155
45144
        let lit: &Literal = value.try_into()?;
156
1782
        lit.try_into()
157
45144
    }
158
}
159

            
160
impl TryFrom<Atom> for bool {
161
    type Error = &'static str;
162

            
163
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
164
        let lit: Literal = value.try_into()?;
165
        lit.try_into()
166
    }
167
}
168

            
169
impl TryFrom<&Atom> for bool {
170
    type Error = &'static str;
171

            
172
6480
    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
173
6480
        let lit: &Literal = value.try_into()?;
174
        lit.try_into()
175
6480
    }
176
}