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