conjure_cp_core/ast/
atom.rs1use std::borrow::Borrow;
2use uniplate::Uniplate;
3
4use super::{
5 AbstractLiteral, DeclarationPtr, DomainPtr, Expression, Literal, Moo, Name,
6 categories::{Category, CategoryOf},
7 domains::HasDomain,
8 records::RecordValue,
9};
10use derivative::Derivative;
11use parking_lot::MappedRwLockReadGuard;
12use polyquine::Quine;
13use serde::{Deserialize, Serialize};
14
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate, Derivative, Quine)]
17#[derivative(Hash)]
18#[uniplate()]
19#[biplate(to=Literal)]
20#[biplate(to=Expression)]
21#[biplate(to=AbstractLiteral<Literal>)]
22#[biplate(to=RecordValue<Literal>)]
23#[biplate(to=DeclarationPtr)]
24#[biplate(to=Name)]
25#[biplate(to=super::Reference)]
26#[path_prefix(conjure_cp::ast)]
27pub enum Atom {
28 Literal(Literal),
29 #[polyquine_skip]
30 Reference(super::Reference),
31}
32
33impl Atom {
34 pub fn new_ref(decl: DeclarationPtr) -> Atom {
35 Atom::Reference(super::Reference::new(decl))
36 }
37
38 pub fn into_declaration(self) -> DeclarationPtr {
39 match self {
40 Atom::Reference(reference) => reference.into_ptr(),
41 _ => panic!("Called into_declaration on a non-reference Atom"),
42 }
43 }
44}
45
46impl CategoryOf for Atom {
47 fn category_of(&self) -> Category {
48 match self {
49 Atom::Literal(_) => Category::Constant,
50 Atom::Reference(reference) => reference.category_of(),
51 }
52 }
53}
54
55impl HasDomain for Atom {
56 fn domain_of(&self) -> DomainPtr {
57 match self {
58 Atom::Literal(literal) => literal.domain_of(),
59 Atom::Reference(reference) => reference.domain_of(),
60 }
61 }
62}
63
64impl std::fmt::Display for Atom {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match self {
67 Atom::Literal(x) => x.fmt(f),
68 Atom::Reference(x) => x.fmt(f),
69 }
70 }
71}
72
73impl From<Literal> for Atom {
74 fn from(value: Literal) -> Self {
75 Atom::Literal(value)
76 }
77}
78
79impl From<DeclarationPtr> for Atom {
80 fn from(value: DeclarationPtr) -> Self {
81 Atom::Reference(super::Reference::new(value))
82 }
83}
84
85impl From<super::Reference> for Atom {
86 fn from(value: super::Reference) -> Self {
87 Atom::Reference(value)
88 }
89}
90
91impl From<i32> for Atom {
92 fn from(value: i32) -> Self {
93 Atom::Literal(value.into())
94 }
95}
96
97impl From<bool> for Atom {
98 fn from(value: bool) -> Self {
99 Atom::Literal(value.into())
100 }
101}
102
103impl TryFrom<Expression> for Atom {
104 type Error = &'static str;
105
106 fn try_from(value: Expression) -> Result<Self, Self::Error> {
107 match value {
108 Expression::Atomic(_, atom) => Ok(atom),
109 _ => Err("Cannot convert non-atomic expression to Atom"),
110 }
111 }
112}
113
114impl TryFrom<Box<Expression>> for Atom {
115 type Error = &'static str;
116
117 fn try_from(value: Box<Expression>) -> Result<Self, Self::Error> {
118 TryFrom::try_from(*value)
119 }
120}
121
122impl TryFrom<Moo<Expression>> for Atom {
123 type Error = &'static str;
124
125 fn try_from(value: Moo<Expression>) -> Result<Self, Self::Error> {
126 TryFrom::try_from(Moo::unwrap_or_clone(value))
127 }
128}
129impl<'a> TryFrom<&'a Expression> for &'a Atom {
130 type Error = &'static str;
131
132 fn try_from(value: &'a Expression) -> Result<Self, Self::Error> {
133 match value {
134 Expression::Atomic(_, atom) => Ok(atom),
135 _ => Err("Cannot convert non-atomic expression to Atom"),
136 }
137 }
138}
139
140impl<'a> TryFrom<&'a Box<Expression>> for &'a Atom {
141 type Error = &'static str;
142
143 fn try_from(value: &'a Box<Expression>) -> Result<Self, Self::Error> {
144 let expr: &'a Expression = value.borrow();
145 expr.try_into()
146 }
147}
148
149impl<'a> TryFrom<&'a Moo<Expression>> for &'a Atom {
150 type Error = &'static str;
151
152 fn try_from(value: &'a Moo<Expression>) -> Result<Self, Self::Error> {
153 let expr: &'a Expression = value.borrow();
154 expr.try_into()
155 }
156}
157
158impl TryFrom<Atom> for Literal {
159 type Error = &'static str;
160
161 fn try_from(value: Atom) -> Result<Self, Self::Error> {
162 match value {
163 Atom::Literal(l) => Ok(l),
164 _ => Err("Cannot convert non-literal atom to Literal"),
165 }
166 }
167}
168
169impl<'a> TryFrom<&'a Atom> for &'a Literal {
170 type Error = &'static str;
171
172 fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
173 match value {
174 Atom::Literal(l) => Ok(l),
175 _ => Err("Cannot convert non-literal atom to Literal"),
176 }
177 }
178}
179
180impl TryFrom<Atom> for Name {
181 type Error = &'static str;
182
183 fn try_from(value: Atom) -> Result<Self, Self::Error> {
184 match value {
185 Atom::Reference(x) => Ok(x.ptr().name().clone()),
186 _ => Err("Cannot convert non-reference atom to Name"),
187 }
188 }
189}
190
191impl<'a> TryFrom<&'a Atom> for MappedRwLockReadGuard<'a, Name> {
192 type Error = &'static str;
193
194 fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
195 match value {
196 Atom::Reference(x) => Ok(x.ptr().name()),
197 _ => Err("Cannot convert non-reference atom to Name"),
198 }
199 }
200}
201
202impl TryFrom<Atom> for i32 {
203 type Error = &'static str;
204
205 fn try_from(value: Atom) -> Result<Self, Self::Error> {
206 let lit: Literal = value.try_into()?;
207 lit.try_into()
208 }
209}
210
211impl TryFrom<&Box<Atom>> for i32 {
212 type Error = &'static str;
213
214 fn try_from(value: &Box<Atom>) -> Result<Self, Self::Error> {
215 TryFrom::<&Atom>::try_from(value.as_ref())
216 }
217}
218
219impl TryFrom<Box<Atom>> for i32 {
220 type Error = &'static str;
221
222 fn try_from(value: Box<Atom>) -> Result<Self, Self::Error> {
223 let lit: Literal = (*value).try_into()?;
224 lit.try_into()
225 }
226}
227
228impl TryFrom<&Moo<Atom>> for i32 {
229 type Error = &'static str;
230
231 fn try_from(value: &Moo<Atom>) -> Result<Self, Self::Error> {
232 TryFrom::<&Atom>::try_from(value.as_ref())
233 }
234}
235
236impl TryFrom<Moo<Atom>> for i32 {
237 type Error = &'static str;
238
239 fn try_from(value: Moo<Atom>) -> Result<Self, Self::Error> {
240 TryFrom::<&Atom>::try_from(value.as_ref())
241 }
242}
243
244impl TryFrom<&Atom> for i32 {
245 type Error = &'static str;
246
247 fn try_from(value: &Atom) -> Result<Self, Self::Error> {
248 match value {
249 Atom::Literal(lit) => lit.try_into(),
250 Atom::Reference(reference) => {
251 let lit = reference
252 .resolve_constant()
253 .ok_or("Cannot convert non-constant reference atom to literal")?;
254 lit.try_into()
255 .map_err(|_| "Cannot convert non-int reference atom to i32")
256 }
257 }
258 }
259}
260
261impl TryFrom<Atom> for bool {
262 type Error = &'static str;
263
264 fn try_from(value: Atom) -> Result<Self, Self::Error> {
265 let lit: Literal = value.try_into()?;
266 lit.try_into()
267 }
268}
269
270impl TryFrom<&Atom> for bool {
271 type Error = &'static str;
272
273 fn try_from(value: &Atom) -> Result<Self, Self::Error> {
274 match value {
275 Atom::Literal(lit) => lit.try_into(),
276 Atom::Reference(reference) => {
277 let lit = reference
278 .resolve_constant()
279 .ok_or("Cannot convert non-constant reference atom to literal")?;
280 lit.try_into()
281 .map_err(|_| "Cannot convert non-bool reference atom to bool")
282 }
283 }
284 }
285}