conjure_cp_core/ast/
reference.rs1use crate::ast::serde::{AsId, HasId};
2use crate::{ast::DeclarationPtr, bug};
3use derivative::Derivative;
4use parking_lot::MappedRwLockReadGuard;
5use serde::{Deserialize, Serialize};
6use serde_with::serde_as;
7use std::fmt::{Display, Formatter};
8use uniplate::Uniplate;
9
10use super::{
11 Atom, DomainPtr, Expression, GroundDomain, Literal, Metadata, Moo, Name,
12 categories::{Category, CategoryOf},
13 domains::HasDomain,
14};
15
16#[serde_as]
22#[derive(
23 Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Uniplate, Derivative,
24)]
25#[derivative(Hash)]
26#[uniplate()]
27#[biplate(to=DeclarationPtr)]
28#[biplate(to=Name)]
29pub struct Reference {
30 #[serde_as(as = "AsId")]
31 pub ptr: DeclarationPtr,
32}
33
34impl Reference {
35 pub fn new(ptr: DeclarationPtr) -> Self {
36 Reference { ptr }
37 }
38
39 pub fn ptr(&self) -> &DeclarationPtr {
40 &self.ptr
41 }
42
43 pub fn into_ptr(self) -> DeclarationPtr {
44 self.ptr
45 }
46
47 pub fn name(&self) -> MappedRwLockReadGuard<'_, Name> {
48 self.ptr.name()
49 }
50
51 pub fn id(&self) -> crate::ast::serde::ObjId {
52 self.ptr.id()
53 }
54
55 pub fn domain(&self) -> Option<DomainPtr> {
56 self.ptr.domain()
57 }
58
59 pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
60 self.domain()?.resolve()
61 }
62
63 pub fn resolve_expression(&self) -> Option<Expression> {
65 self.ptr().as_value_letting().map(|expr| expr.clone())
66 }
67
68 pub fn resolve_constant(&self) -> Option<Literal> {
70 self.resolve_expression()
71 .and_then(|expr| super::eval::eval_constant(&expr))
72 }
73
74 pub fn resolve_atomic(&self) -> Option<Atom> {
76 self.resolve_expression().and_then(|expr| match expr {
77 Expression::Atomic(_, atom) => Some(atom),
78 _ => None,
79 })
80 }
81}
82
83impl From<Reference> for Expression {
84 fn from(value: Reference) -> Self {
85 Expression::Atomic(Metadata::new(), value.into())
86 }
87}
88
89impl From<DeclarationPtr> for Reference {
90 fn from(ptr: DeclarationPtr) -> Self {
91 Reference::new(ptr)
92 }
93}
94
95impl CategoryOf for Reference {
96 fn category_of(&self) -> Category {
97 self.ptr.category_of()
98 }
99}
100
101impl HasDomain for Reference {
102 fn domain_of(&self) -> DomainPtr {
103 self.ptr.domain().unwrap_or_else(|| {
104 bug!(
105 "reference ({name}) should have a domain",
106 name = self.ptr.name()
107 )
108 })
109 }
110}
111
112impl Display for Reference {
113 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
114 self.ptr.name().fmt(f)
115 }
116}