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}