conjure_cp_core/ast/declaration.rs
1pub mod serde;
2
3use std::any::TypeId;
4// allow use of Declaration in this file, and nowhere else
5use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::fmt::{Debug, Display};
7use std::rc::Rc;
8
9use ::serde::{Deserialize, Serialize};
10
11use uniplate::{Biplate, Tree, Uniplate};
12
13use super::categories::{Category, CategoryOf};
14use super::name::Name;
15use super::serde::{DefaultWithId, HasId, ObjId};
16use super::types::Typeable;
17use super::{DecisionVariable, Domain, Expression, RecordEntry, ReturnType};
18
19thread_local! {
20 // make each thread have its own id counter.
21 static DECLARATION_PTR_ID_COUNTER: Cell<u32> = const { Cell::new(0) };
22
23 // We run integration tests in parallel threads - making this thread local ensures that
24 // declarations in a test always have the same id, instead of the ids depending on how many
25 // threads are running, how they are scheduled, etc.
26}
27
28#[doc(hidden)]
29/// Resets the id counter of `DeclarationPtr` to 0.
30///
31/// This is probably always a bad idea.
32pub fn reset_declaration_id_unchecked() {
33 DECLARATION_PTR_ID_COUNTER.set(0);
34}
35
36/// A shared pointer to a [`Declaration`].
37///
38/// Two declaration pointers are equal if they point to the same underlying declaration.
39///
40/// # Id
41///
42/// The id of `DeclarationPtr` obeys the following invariants:
43///
44/// 1. Declaration pointers have the same id if they point to the same
45/// underlying declaration.
46///
47/// 2. The id is immutable.
48///
49/// 3. Changing the declaration pointed to by the declaration pointer does not change the id. This
50/// allows declarations to be updated by replacing them with a newer version of themselves.
51///
52/// `Ord`, `Hash`, and `Eq` use id for comparisons.
53/// # Serde
54///
55/// Declaration pointers can be serialised using the following serializers:
56///
57/// + [`DeclarationPtrFull`](serde::DeclarationPtrFull)
58/// + [`DeclarationPtrAsId`](serde::DeclarationPtrAsId)
59///
60/// See their documentation for more information.
61#[derive(Clone, Debug)]
62pub struct DeclarationPtr {
63 // the shared bits of the pointer
64 inner: Rc<DeclarationPtrInner>,
65}
66
67// The bits of a declaration that are shared between all pointers.
68#[derive(Clone, Debug)]
69struct DeclarationPtrInner {
70 // We don't want this to be mutable, as `HashMap` and `BTreeMap` rely on the hash or order of
71 // keys to be unchanging.
72 //
73 // See: https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
74 id: ObjId,
75
76 // The contents of the declaration itself should be mutable.
77 value: RefCell<Declaration>,
78}
79
80impl DeclarationPtrInner {
81 fn new(value: RefCell<Declaration>) -> Rc<DeclarationPtrInner> {
82 Rc::new(DeclarationPtrInner {
83 id: DECLARATION_PTR_ID_COUNTER.replace(DECLARATION_PTR_ID_COUNTER.get() + 1),
84 value,
85 })
86 }
87
88 // SAFETY: only use if you are really really sure you arn't going to break the id invariants of
89 // DeclarationPtr and HasId!
90 fn new_with_id_unchecked(value: RefCell<Declaration>, id: ObjId) -> Rc<DeclarationPtrInner> {
91 Rc::new(DeclarationPtrInner { id, value })
92 }
93}
94
95#[allow(dead_code)]
96impl DeclarationPtr {
97 /******************************/
98 /* Constructors */
99 /******************************/
100
101 /// Creates a `DeclarationPtr` for the given `Declaration`.
102 fn from_declaration(declaration: Declaration) -> DeclarationPtr {
103 DeclarationPtr {
104 inner: DeclarationPtrInner::new(RefCell::new(declaration)),
105 }
106 }
107
108 /// Creates a new declaration.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
114 ///
115 /// // letting MyDomain be int(1..5)
116 /// let declaration = DeclarationPtr::new(
117 /// Name::User("MyDomain".into()),
118 /// DeclarationKind::DomainLetting(Domain::Int(vec![
119 /// Range::Bounded(1,5)])));
120 /// ```
121 pub fn new(name: Name, kind: DeclarationKind) -> DeclarationPtr {
122 DeclarationPtr::from_declaration(Declaration::new(name, kind))
123 }
124
125 /// Creates a new decision variable declaration with the decision category.
126 ///
127 /// # Examples
128 ///
129 /// ```
130 /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
131 ///
132 /// // find x: int(1..5)
133 /// let declaration = DeclarationPtr::new_var(
134 /// Name::User("x".into()),
135 /// Domain::Int(vec![Range::Bounded(1,5)]));
136 ///
137 /// ```
138 pub fn new_var(name: Name, domain: Domain) -> DeclarationPtr {
139 let kind =
140 DeclarationKind::DecisionVariable(DecisionVariable::new(domain, Category::Decision));
141 DeclarationPtr::new(name, kind)
142 }
143
144 /// Creates a new decision variable with the quantified category.
145 ///
146 /// This is useful to represent a quantified / induction variable in a comprehension.
147 pub fn new_var_quantified(name: Name, domain: Domain) -> DeclarationPtr {
148 let kind =
149 DeclarationKind::DecisionVariable(DecisionVariable::new(domain, Category::Quantified));
150
151 DeclarationPtr::new(name, kind)
152 }
153
154 /// Creates a new domain letting declaration.
155 ///
156 /// # Examples
157 ///
158 /// ```
159 /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
160 ///
161 /// // letting MyDomain be int(1..5)
162 /// let declaration = DeclarationPtr::new_domain_letting(
163 /// Name::User("MyDomain".into()),
164 /// Domain::Int(vec![Range::Bounded(1,5)]));
165 ///
166 /// ```
167 pub fn new_domain_letting(name: Name, domain: Domain) -> DeclarationPtr {
168 let kind = DeclarationKind::DomainLetting(domain);
169 DeclarationPtr::new(name, kind)
170 }
171
172 /// Creates a new value letting declaration.
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range, Expression,
178 /// Literal,Atom,Moo};
179 /// use conjure_cp_core::{matrix_expr,metadata::Metadata};
180 ///
181 /// // letting n be 10 + 10
182 /// let ten = Expression::Atomic(Metadata::new(),Atom::Literal(Literal::Int(10)));
183 /// let expression = Expression::Sum(Metadata::new(),Moo::new(matrix_expr![ten.clone(),ten]));
184 /// let declaration = DeclarationPtr::new_value_letting(
185 /// Name::User("n".into()),
186 /// expression);
187 ///
188 /// ```
189 pub fn new_value_letting(name: Name, expression: Expression) -> DeclarationPtr {
190 let kind = DeclarationKind::ValueLetting(expression);
191 DeclarationPtr::new(name, kind)
192 }
193
194 /// Creates a new given declaration.
195 ///
196 /// # Examples
197 ///
198 /// ```
199 /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
200 ///
201 /// // given n: int(1..5)
202 /// let declaration = DeclarationPtr::new_given(
203 /// Name::User("n".into()),
204 /// Domain::Int(vec![Range::Bounded(1,5)]));
205 ///
206 /// ```
207 pub fn new_given(name: Name, domain: Domain) -> DeclarationPtr {
208 let kind = DeclarationKind::Given(domain);
209 DeclarationPtr::new(name, kind)
210 }
211
212 /// Creates a new record field declaration.
213 ///
214 /// # Examples
215 ///
216 /// ```
217 /// use conjure_cp_core::ast::{DeclarationPtr,Name,records::RecordEntry,Domain,Range};
218 ///
219 /// // create declaration for field A in `find rec: record {A: int(0..1), B: int(0..2)}`
220 ///
221 /// let field = RecordEntry {
222 /// name: Name::User("n".into()),
223 /// domain: Domain::Int(vec![Range::Bounded(1,5)])
224 /// };
225 ///
226 /// let declaration = DeclarationPtr::new_record_field(field);
227 /// ```
228 pub fn new_record_field(entry: RecordEntry) -> DeclarationPtr {
229 let kind = DeclarationKind::RecordField(entry.domain);
230 DeclarationPtr::new(entry.name, kind)
231 }
232
233 /**********************************************/
234 /* Declaration accessor methods */
235 /**********************************************/
236
237 /// Gets the domain of the declaration, if it has one.
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
243 ///
244 /// // find a: int(1..5)
245 /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::Int(vec![Range::Bounded(1,5)]));
246 ///
247 /// assert!(declaration.domain().is_some_and(|x| x == Domain::Int(vec![Range::Bounded(1,5)])))
248 ///
249 /// ```
250 pub fn domain(&self) -> Option<Domain> {
251 match &self.kind() as &DeclarationKind {
252 DeclarationKind::DecisionVariable(var) => Some(var.domain.clone()),
253 DeclarationKind::ValueLetting(e) => e.domain_of(),
254 DeclarationKind::DomainLetting(domain) => Some(domain.clone()),
255 DeclarationKind::Given(domain) => Some(domain.clone()),
256 DeclarationKind::RecordField(domain) => Some(domain.clone()),
257 }
258 }
259
260 /// Gets the kind of the declaration.
261 ///
262 /// # Examples
263 ///
264 /// ```
265 /// use conjure_cp_core::ast::{DeclarationPtr,DeclarationKind,Name,Domain,Range};
266 ///
267 /// // find a: int(1..5)
268 /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::Int(vec![Range::Bounded(1,5)]));
269 /// assert!(matches!(&declaration.kind() as &DeclarationKind, DeclarationKind::DecisionVariable(_)))
270 /// ```
271 pub fn kind(&self) -> Ref<DeclarationKind> {
272 self.map(|x| &x.kind)
273 }
274
275 /// Gets the name of the declaration.
276 ///
277 /// # Examples
278 ///
279 /// ```
280 /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
281 ///
282 /// // find a: int(1..5)
283 /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::Int(vec![Range::Bounded(1,5)]));
284 ///
285 /// assert_eq!(&declaration.name() as &Name, &Name::User("a".into()))
286 /// ```
287 pub fn name(&self) -> Ref<Name> {
288 self.map(|x| &x.name)
289 }
290
291 /// This declaration as a decision variable, if it is one.
292 pub fn as_var(&self) -> Option<Ref<DecisionVariable>> {
293 Ref::filter_map(self.borrow(), |x| {
294 if let DeclarationKind::DecisionVariable(var) = &x.kind {
295 Some(var)
296 } else {
297 None
298 }
299 })
300 .ok()
301 }
302
303 /// This declaration as a mutable decision variable, if it is one.
304 pub fn as_var_mut(&mut self) -> Option<RefMut<DecisionVariable>> {
305 RefMut::filter_map(self.borrow_mut(), |x| {
306 if let DeclarationKind::DecisionVariable(var) = &mut x.kind {
307 Some(var)
308 } else {
309 None
310 }
311 })
312 .ok()
313 }
314
315 /// This declaration as a domain letting, if it is one.
316 pub fn as_domain_letting(&self) -> Option<Ref<Domain>> {
317 Ref::filter_map(self.borrow(), |x| {
318 if let DeclarationKind::DomainLetting(domain) = &x.kind {
319 Some(domain)
320 } else {
321 None
322 }
323 })
324 .ok()
325 }
326
327 /// This declaration as a mutable domain letting, if it is one.
328 pub fn as_domain_letting_mut(&mut self) -> Option<RefMut<Domain>> {
329 RefMut::filter_map(self.borrow_mut(), |x| {
330 if let DeclarationKind::DomainLetting(domain) = &mut x.kind {
331 Some(domain)
332 } else {
333 None
334 }
335 })
336 .ok()
337 }
338
339 /// This declaration as a value letting, if it is one.
340 pub fn as_value_letting(&self) -> Option<Ref<Expression>> {
341 Ref::filter_map(self.borrow(), |x| {
342 if let DeclarationKind::ValueLetting(e) = &x.kind {
343 Some(e)
344 } else {
345 None
346 }
347 })
348 .ok()
349 }
350
351 /// This declaration as a mutable value letting, if it is one.
352 pub fn as_value_letting_mut(&mut self) -> Option<RefMut<Expression>> {
353 RefMut::filter_map(self.borrow_mut(), |x| {
354 if let DeclarationKind::ValueLetting(e) = &mut x.kind {
355 Some(e)
356 } else {
357 None
358 }
359 })
360 .ok()
361 }
362
363 /// Changes the name in this declaration, returning the old one.
364 ///
365 /// # Examples
366 ///
367 /// ```
368 /// use conjure_cp_core::ast::{DeclarationPtr, Domain, Range, Name};
369 ///
370 /// // find a: int(1..5)
371 /// let mut declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::Int(vec![Range::Bounded(1,5)]));
372 ///
373 /// let old_name = declaration.replace_name(Name::User("b".into()));
374 /// assert_eq!(old_name,Name::User("a".into()));
375 /// assert_eq!(&declaration.name() as &Name,&Name::User("b".into()));
376 /// ```
377 pub fn replace_name(&mut self, name: Name) -> Name {
378 let mut decl = self.borrow_mut();
379 std::mem::replace(&mut decl.name, name)
380 }
381
382 /*****************************************/
383 /* Pointer utility methods */
384 /*****************************************/
385
386 // These are mostly wrappers over RefCell, Ref, and RefMut methods, re-exported here for
387 // convenience.
388
389 /// Immutably borrows the declaration.
390 fn borrow(&self) -> Ref<Declaration> {
391 // unlike refcell.borrow(), this never panics
392 self.inner.value.borrow()
393 }
394
395 /// Mutably borrows the declaration.
396 fn borrow_mut(&mut self) -> RefMut<Declaration> {
397 // unlike refcell.borrow_mut(), this never panics
398 self.inner.value.borrow_mut()
399 }
400
401 /// Creates a new declaration pointer with the same contents as `self` that is not shared with
402 /// anyone else.
403 ///
404 /// As the resulting pointer is unshared, it will have a new id.
405 ///
406 /// # Examples
407 ///
408 /// ```
409 /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
410 ///
411 /// // find a: int(1..5)
412 /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::Int(vec![Range::Bounded(1,5)]));
413 ///
414 /// let mut declaration2 = declaration.clone();
415 ///
416 /// declaration2.replace_name(Name::User("b".into()));
417 ///
418 /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
419 /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
420 ///
421 /// declaration2 = declaration2.detach();
422 ///
423 /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
424 ///
425 /// declaration2.replace_name(Name::User("c".into()));
426 ///
427 /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
428 /// assert_eq!(&declaration2.name() as &Name, &Name::User("c".into()));
429 /// ```
430 pub fn detach(self) -> DeclarationPtr {
431 // despite having the same contents, the new declaration pointer is unshared, so it should
432 // get a new id.
433 DeclarationPtr {
434 inner: DeclarationPtrInner::new(self.inner.value.clone()),
435 }
436 }
437
438 /// Applies `f` to the declaration, returning the result as a reference.
439 fn map<U>(&self, f: impl FnOnce(&Declaration) -> &U) -> Ref<U> {
440 Ref::map(self.borrow(), f)
441 }
442
443 /// Applies mutable function `f` to the declaration, returning the result as a mutable reference.
444 fn map_mut<U>(&mut self, f: impl FnOnce(&mut Declaration) -> &mut U) -> RefMut<U> {
445 RefMut::map(self.borrow_mut(), f)
446 }
447
448 /// Replaces the declaration with a new one, returning the old value, without deinitialising
449 /// either one.
450 fn replace(&mut self, declaration: Declaration) -> Declaration {
451 self.inner.value.replace(declaration)
452 }
453}
454
455impl CategoryOf for DeclarationPtr {
456 fn category_of(&self) -> Category {
457 match &self.kind() as &DeclarationKind {
458 DeclarationKind::DecisionVariable(decision_variable) => decision_variable.category_of(),
459 DeclarationKind::ValueLetting(expression) => expression.category_of(),
460 DeclarationKind::DomainLetting(_) => Category::Constant,
461 DeclarationKind::Given(_) => Category::Parameter,
462 DeclarationKind::RecordField(_) => Category::Bottom,
463 }
464 }
465}
466impl HasId for DeclarationPtr {
467 fn id(&self) -> ObjId {
468 self.inner.id
469 }
470}
471
472impl DefaultWithId for DeclarationPtr {
473 fn default_with_id(id: ObjId) -> Self {
474 DeclarationPtr {
475 inner: DeclarationPtrInner::new_with_id_unchecked(
476 RefCell::new(Declaration {
477 name: Name::User("_UNKNOWN".into()),
478 kind: DeclarationKind::ValueLetting(false.into()),
479 }),
480 id,
481 ),
482 }
483 }
484}
485
486impl Typeable for DeclarationPtr {
487 fn return_type(&self) -> Option<ReturnType> {
488 match &self.kind() as &DeclarationKind {
489 DeclarationKind::DecisionVariable(var) => var.return_type(),
490 DeclarationKind::ValueLetting(expression) => expression.return_type(),
491 DeclarationKind::DomainLetting(domain) => domain.return_type(),
492 DeclarationKind::Given(domain) => domain.return_type(),
493 DeclarationKind::RecordField(domain) => domain.return_type(),
494 }
495 }
496}
497
498impl Uniplate for DeclarationPtr {
499 fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
500 let decl = self.borrow();
501 let (tree, recons) = Biplate::<DeclarationPtr>::biplate(&decl as &Declaration);
502
503 let self2 = self.clone();
504 (
505 tree,
506 Box::new(move |x| {
507 let mut self3 = self2.clone();
508 let inner = recons(x);
509 *(&mut self3.borrow_mut() as &mut Declaration) = inner;
510 self3
511 }),
512 )
513 }
514}
515
516impl<To> Biplate<To> for DeclarationPtr
517where
518 Declaration: Biplate<To>,
519 To: Uniplate,
520{
521 fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
522 if TypeId::of::<To>() == TypeId::of::<Self>() {
523 unsafe {
524 let self_as_to = std::mem::transmute::<&Self, &To>(self).clone();
525 (
526 Tree::One(self_as_to),
527 Box::new(move |x| {
528 let Tree::One(x) = x else { panic!() };
529
530 let x_as_self = std::mem::transmute::<&To, &Self>(&x);
531 x_as_self.clone()
532 }),
533 )
534 }
535 } else {
536 // call biplate on the enclosed declaration
537 let decl = self.borrow();
538 let (tree, recons) = Biplate::<To>::biplate(&decl as &Declaration);
539
540 let self2 = self.clone();
541 (
542 tree,
543 Box::new(move |x| {
544 let mut self3 = self2.clone();
545 let inner = recons(x);
546 *(&mut self3.borrow_mut() as &mut Declaration) = inner;
547 self3
548 }),
549 )
550 }
551 }
552}
553
554impl Ord for DeclarationPtr {
555 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
556 self.inner.id.cmp(&other.inner.id)
557 }
558}
559
560impl PartialOrd for DeclarationPtr {
561 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
562 Some(self.cmp(other))
563 }
564}
565
566impl PartialEq for DeclarationPtr {
567 fn eq(&self, other: &Self) -> bool {
568 self.inner.id == other.inner.id
569 }
570}
571
572impl Eq for DeclarationPtr {}
573
574impl std::hash::Hash for DeclarationPtr {
575 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
576 // invariant: x == y -> hash(x) == hash(y)
577 self.inner.id.hash(state);
578 }
579}
580
581impl Display for DeclarationPtr {
582 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
583 let value: &Declaration = &self.borrow();
584 value.fmt(f)
585 }
586}
587
588#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq, Uniplate)]
589#[biplate(to=Expression)]
590#[biplate(to=DeclarationPtr)]
591#[biplate(to=Name)]
592/// The contents of a declaration
593struct Declaration {
594 /// The name of the declared symbol.
595 name: Name,
596
597 /// The kind of the declaration.
598 kind: DeclarationKind,
599}
600
601impl Declaration {
602 /// Creates a new declaration.
603 fn new(name: Name, kind: DeclarationKind) -> Declaration {
604 Declaration { name, kind }
605 }
606}
607
608/// A specific kind of declaration.
609#[non_exhaustive]
610#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
611#[biplate(to=Expression)]
612#[biplate(to=DeclarationPtr)]
613#[biplate(to=Declaration)]
614pub enum DeclarationKind {
615 DecisionVariable(DecisionVariable),
616 ValueLetting(Expression),
617 DomainLetting(Domain),
618 Given(Domain),
619
620 /// A named field inside a record type.
621 /// e.g. A, B in record{A: int(0..1), B: int(0..2)}
622 RecordField(Domain),
623}