1
use std::borrow::Borrow;
2

            
3
use crate::metadata::Metadata;
4

            
5
use super::{Expression, Literal, Name};
6
use serde::{Deserialize, Serialize};
7
use uniplate::derive::Uniplate;
8

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

            
21
impl std::fmt::Display for Atom {
22
115022
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23
115022
        match self {
24
40273
            Atom::Literal(x) => x.fmt(f),
25
74749
            Atom::Reference(x) => x.fmt(f),
26
        }
27
115022
    }
28
}
29

            
30
impl From<Literal> for Atom {
31
    fn from(value: Literal) -> Self {
32
        Atom::Literal(value)
33
    }
34
}
35

            
36
impl From<Name> for Atom {
37
7990
    fn from(value: Name) -> Self {
38
7990
        Atom::Reference(value)
39
7990
    }
40
}
41

            
42
impl From<i32> for Atom {
43
    fn from(value: i32) -> Self {
44
        Atom::Literal(value.into())
45
    }
46
}
47

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

            
54
impl TryFrom<Expression> for Atom {
55
    type Error = &'static str;
56

            
57
629
    fn try_from(value: Expression) -> Result<Self, Self::Error> {
58
629
        match value {
59
544
            Expression::Atomic(_, atom) => Ok(atom),
60
85
            _ => Err("Cannot convert non-atomic expression to Atom"),
61
        }
62
629
    }
63
}
64

            
65
impl<'a> TryFrom<&'a Expression> for &'a Atom {
66
    type Error = &'static str;
67

            
68
234889
    fn try_from(value: &'a Expression) -> Result<Self, Self::Error> {
69
234889
        match value {
70
87839
            Expression::Atomic(_, atom) => Ok(atom),
71
147050
            _ => Err("Cannot convert non-atomic expression to Atom"),
72
        }
73
234889
    }
74
}
75

            
76
impl TryFrom<Box<Expression>> for Atom {
77
    type Error = &'static str;
78

            
79
153
    fn try_from(value: Box<Expression>) -> Result<Self, Self::Error> {
80
153
        (*value).try_into()
81
153
    }
82
}
83

            
84
impl<'a> TryFrom<&'a Box<Expression>> for &'a Atom {
85
    type Error = &'static str;
86

            
87
35887
    fn try_from(value: &'a Box<Expression>) -> Result<Self, Self::Error> {
88
35887
        let expr: &'a Expression = value.borrow();
89
35887
        expr.try_into()
90
35887
    }
91
}
92

            
93
impl TryFrom<Atom> for Literal {
94
    type Error = &'static str;
95

            
96
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
97
        match value {
98
            Atom::Literal(l) => Ok(l),
99
            _ => Err("Cannot convert non-literal atom to Literal"),
100
        }
101
    }
102
}
103

            
104
impl<'a> TryFrom<&'a Atom> for &'a Literal {
105
    type Error = &'static str;
106

            
107
30277
    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
108
30277
        match value {
109
1258
            Atom::Literal(l) => Ok(l),
110
29019
            _ => Err("Cannot convert non-literal atom to Literal"),
111
        }
112
30277
    }
113
}
114

            
115
impl TryFrom<Atom> for Name {
116
    type Error = &'static str;
117

            
118
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
119
        match value {
120
            Atom::Reference(n) => Ok(n),
121
            _ => Err("Cannot convert non-reference atom to Name"),
122
        }
123
    }
124
}
125

            
126
impl<'a> TryFrom<&'a Atom> for &'a Name {
127
    type Error = &'static str;
128

            
129
    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
130
        match value {
131
            Atom::Reference(n) => Ok(n),
132
            _ => Err("Cannot convert non-reference atom to Name"),
133
        }
134
    }
135
}
136

            
137
impl TryFrom<Atom> for i32 {
138
    type Error = &'static str;
139

            
140
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
141
        let lit: Literal = value.try_into()?;
142
        lit.try_into()
143
    }
144
}
145

            
146
impl TryFrom<&Atom> for i32 {
147
    type Error = &'static str;
148

            
149
29410
    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
150
29410
        let lit: &Literal = value.try_into()?;
151
1258
        lit.try_into()
152
29410
    }
153
}
154

            
155
impl TryFrom<Atom> for bool {
156
    type Error = &'static str;
157

            
158
    fn try_from(value: Atom) -> Result<Self, Self::Error> {
159
        let lit: Literal = value.try_into()?;
160
        lit.try_into()
161
    }
162
}
163

            
164
impl TryFrom<&Atom> for bool {
165
    type Error = &'static str;
166

            
167
867
    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
168
867
        let lit: &Literal = value.try_into()?;
169
        lit.try_into()
170
867
    }
171
}