Skip to main content

conjure_cp_core/ast/domains/
domain.rs

1use super::attrs::SetAttr;
2use super::ground::GroundDomain;
3use super::range::Range;
4use super::unresolved::{IntVal, UnresolvedDomain};
5use crate::ast::domains::attrs::{MSetAttr, PartitionAttr};
6use crate::ast::{
7    DeclarationPtr, DomainOpError, Expression, FieldEntry, FieldEntryGround, FuncAttr, Literal,
8    Moo, Reference, RelAttr, ReturnType, SequenceAttr, Typeable,
9};
10use itertools::Itertools;
11use polyquine::Quine;
12use serde::{Deserialize, Serialize};
13use std::fmt::{Display, Formatter};
14use std::thread_local;
15use uniplate::Uniplate;
16
17/// The integer type used in all domain code (int ranges, set sizes, etc)
18pub type Int = i32;
19
20pub type DomainPtr = Moo<Domain>;
21
22impl DomainPtr {
23    pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
24        self.as_ref().resolve()
25    }
26
27    /// Convenience method to take [Domain::union] of the [Domain]s behind two [DomainPtr]s
28    /// and wrap the result in a new [DomainPtr].
29    pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
30        self.as_ref().union(other.as_ref()).map(DomainPtr::new)
31    }
32
33    /// Convenience method to take [Domain::intersect] of the [Domain]s behind two [DomainPtr]s
34    /// and wrap the result in a new [DomainPtr].
35    pub fn intersect(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
36        self.as_ref().intersect(other.as_ref()).map(DomainPtr::new)
37    }
38}
39
40impl From<Moo<GroundDomain>> for DomainPtr {
41    fn from(value: Moo<GroundDomain>) -> Self {
42        Moo::new(Domain::Ground(value))
43    }
44}
45
46impl From<Moo<UnresolvedDomain>> for DomainPtr {
47    fn from(value: Moo<UnresolvedDomain>) -> Self {
48        Moo::new(Domain::Unresolved(value))
49    }
50}
51
52impl From<GroundDomain> for DomainPtr {
53    fn from(value: GroundDomain) -> Self {
54        Moo::new(Domain::Ground(Moo::new(value)))
55    }
56}
57
58impl From<UnresolvedDomain> for DomainPtr {
59    fn from(value: UnresolvedDomain) -> Self {
60        Moo::new(Domain::Unresolved(Moo::new(value)))
61    }
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
65#[biplate(to=DomainPtr)]
66#[biplate(to=GroundDomain)]
67#[biplate(to=UnresolvedDomain)]
68#[biplate(to=Expression)]
69#[biplate(to=Reference)]
70#[biplate(to=FieldEntry)]
71#[biplate(to=IntVal)]
72#[path_prefix(conjure_cp::ast)]
73pub enum Domain {
74    /// A fully resolved domain
75    Ground(Moo<GroundDomain>),
76    /// A domain which may contain references
77    Unresolved(Moo<UnresolvedDomain>),
78}
79
80/// Types that have a [`Domain`].
81pub trait HasDomain {
82    /// Gets the [`Domain`] of `self`.
83    fn domain_of(&self) -> DomainPtr;
84}
85
86impl<T: HasDomain> Typeable for T {
87    fn return_type(&self) -> ReturnType {
88        self.domain_of().return_type()
89    }
90}
91
92// Domain::Bool is completely static, so reuse the same chunk of memory
93// for all bool domains to avoid many small memory allocations
94thread_local! {
95    static BOOL_DOMAIN: DomainPtr =
96        Moo::new(Domain::Ground(Moo::new(GroundDomain::Bool)));
97}
98
99impl Domain {
100    /// Create a new boolean domain and return a pointer to it.
101    /// Boolean domains are always ground (see [GroundDomain::Bool]).
102    pub fn bool() -> DomainPtr {
103        BOOL_DOMAIN.with(Clone::clone)
104    }
105
106    /// Create a new empty domain of the given type and return a pointer to it.
107    /// Empty domains are always ground (see [GroundDomain::Empty]).
108    pub fn empty(ty: ReturnType) -> DomainPtr {
109        Moo::new(Domain::Ground(Moo::new(GroundDomain::Empty(ty))))
110    }
111
112    /// Create a new int domain with the given ranges.
113    /// If the ranges are all ground, the variant will be [GroundDomain::Int].
114    /// Otherwise, it will be [UnresolvedDomain::Int].
115    pub fn int<T>(ranges: Vec<T>) -> DomainPtr
116    where
117        T: Into<Range<IntVal>> + TryInto<Range<Int>> + Clone,
118    {
119        if let Ok(int_rngs) = ranges
120            .iter()
121            .cloned()
122            .map(TryInto::try_into)
123            .collect::<Result<Vec<_>, _>>()
124        {
125            return Domain::int_ground(int_rngs);
126        }
127        let unresolved_rngs: Vec<Range<IntVal>> = ranges.into_iter().map(Into::into).collect();
128        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Int(
129            unresolved_rngs,
130        ))))
131    }
132
133    /// Create a new ground integer domain with the given ranges
134    pub fn int_ground(ranges: Vec<Range<Int>>) -> DomainPtr {
135        let rngs = Range::squeeze(&ranges);
136        Moo::new(Domain::Ground(Moo::new(GroundDomain::Int(rngs))))
137    }
138
139    /// Create a new set domain with the given element domain and attributes.
140    /// If the element domain and the attributes are ground, the variant
141    /// will be [GroundDomain::Set]. Otherwise, it will be [UnresolvedDomain::Set].
142    pub fn set<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
143    where
144        T: Into<SetAttr<IntVal>> + TryInto<SetAttr<Int>> + Clone,
145    {
146        if let Domain::Ground(gd) = inner_dom.as_ref()
147            && let Ok(int_attr) = attr.clone().try_into()
148        {
149            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Set(
150                int_attr,
151                gd.clone(),
152            ))));
153        }
154        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Set(
155            attr.into(),
156            inner_dom,
157        ))))
158    }
159
160    /// Create a new multiset domain with the given element domain and attributes
161    pub fn mset<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
162    where
163        T: Into<MSetAttr<IntVal>> + TryInto<MSetAttr<Int>> + Clone,
164    {
165        if let Domain::Ground(gd) = inner_dom.as_ref()
166            && let Ok(int_attr) = attr.clone().try_into()
167        {
168            return Moo::new(Domain::Ground(Moo::new(GroundDomain::MSet(
169                int_attr,
170                gd.clone(),
171            ))));
172        }
173        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(
174            attr.into(),
175            inner_dom,
176        ))))
177    }
178
179    /// Create a new matrix domain with the given element domain and index domains.
180    /// If the given domains are all ground, the variant will be [GroundDomain::Matrix].
181    /// Otherwise, it will be [UnresolvedDomain::Matrix].
182    pub fn matrix(inner_dom: DomainPtr, idx_doms: Vec<DomainPtr>) -> DomainPtr {
183        if let Domain::Ground(gd) = inner_dom.as_ref()
184            && let Some(idx_gds) = as_grounds(&idx_doms)
185        {
186            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Matrix(
187                gd.clone(),
188                idx_gds,
189            ))));
190        }
191        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
192            inner_dom, idx_doms,
193        ))))
194    }
195
196    /// Create a new tuple domain with the given element domains.
197    /// If the given domains are all ground, the variant will be [GroundDomain::Tuple].
198    /// Otherwise, it will be [UnresolvedDomain::Tuple].
199    pub fn tuple(inner_doms: Vec<DomainPtr>) -> DomainPtr {
200        if let Some(inner_gds) = as_grounds(&inner_doms) {
201            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Tuple(inner_gds))));
202        }
203        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
204            inner_doms,
205        ))))
206    }
207
208    /// Create a new tuple domain with the given entries.
209    /// If the entries are all ground, the variant will be [GroundDomain::Record].
210    /// Otherwise, it will be [UnresolvedDomain::Record].
211    pub fn record(entries: Vec<FieldEntry>) -> DomainPtr {
212        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
213            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Record(entries_gds))));
214        }
215        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
216            entries,
217        ))))
218    }
219
220    /// Create a new [UnresolvedDomain::Reference] domain from a domain letting
221    pub fn reference(ptr: DeclarationPtr) -> Option<DomainPtr> {
222        let _ = ptr.as_domain_letting()?;
223        Some(Moo::new(Domain::Unresolved(Moo::new(
224            UnresolvedDomain::Reference(Reference::new(ptr)),
225        ))))
226    }
227
228    /// Create a new multiset domain with the given element domain and attributes
229    pub fn partition<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
230    where
231        T: Into<PartitionAttr<IntVal>> + TryInto<PartitionAttr<Int>> + Clone,
232    {
233        if let Domain::Ground(gd) = inner_dom.as_ref()
234            && let Ok(int_attr) = attr.clone().try_into()
235        {
236            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Partition(
237                int_attr,
238                gd.clone(),
239            ))));
240        }
241        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(
242            attr.into(),
243            inner_dom,
244        ))))
245    }
246
247    /// Create a new function domain
248    pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
249    where
250        T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
251    {
252        if let Ok(attrs_gd) = attrs.clone().try_into()
253            && let Some(dom_gd) = dom.as_ground()
254            && let Some(cdom_gd) = cdom.as_ground()
255        {
256            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
257                attrs_gd,
258                Moo::new(dom_gd.clone()),
259                Moo::new(cdom_gd.clone()),
260            ))));
261        }
262
263        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
264            attrs.into(),
265            dom,
266            cdom,
267        ))))
268    }
269
270    /// Create a new variant domain with the given entries.
271    /// If the entries are all ground, the variant will be [GroundDomain::Variant].
272    /// Otherwise, it will be [UnresolvedDomain::Variant].
273    pub fn variant(entries: Vec<FieldEntry>) -> DomainPtr {
274        if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
275            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Variant(entries_gds))));
276        }
277        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(
278            entries,
279        ))))
280    }
281
282    /// Create a new relation domain
283    /// If the entries are all ground, the variant will be [GroundDomain::Relation].
284    /// Otherwise, it will be [UnresolvedDomain::Relation].
285    pub fn relation<T>(attrs: T, inner_doms: Vec<DomainPtr>) -> DomainPtr
286    where
287        T: Into<RelAttr<IntVal>> + TryInto<RelAttr<Int>> + Clone,
288    {
289        if let Ok(attrs_gd) = attrs.clone().try_into()
290            && let Some(doms_gd) = as_grounds(&inner_doms)
291        {
292            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Relation(
293                attrs_gd, doms_gd,
294            ))));
295        }
296
297        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
298            attrs.into(),
299            inner_doms,
300        ))))
301    }
302
303    /// Create a new Sequence domain
304    pub fn sequence<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
305    where
306        T: Into<SequenceAttr<IntVal>> + TryInto<SequenceAttr<Int>> + Clone,
307    {
308        if let Domain::Ground(gd) = inner_dom.as_ref()
309            && let Ok(int_attr) = attr.clone().try_into()
310        {
311            return Moo::new(Domain::Ground(Moo::new(GroundDomain::Sequence(
312                int_attr,
313                gd.clone(),
314            ))));
315        }
316        Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
317            attr.into(),
318            inner_dom,
319        ))))
320    }
321
322    /// If this domain is ground, return a [Moo] to the underlying [GroundDomain].
323    /// Otherwise, try to resolve it; Return None if this is not yet possible.
324    /// Domains which contain references to givens cannot be resolved until these
325    /// givens are substituted for their concrete values.
326    pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
327        match self {
328            Domain::Ground(gd) => Some(gd.clone()),
329            Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
330        }
331    }
332
333    /// If this domain is already ground, return a reference to the underlying [GroundDomain].
334    /// Otherwise, return None. This method does NOT perform any resolution.
335    /// See also: [Domain::resolve].
336    pub fn as_ground(&self) -> Option<&GroundDomain> {
337        match self {
338            Domain::Ground(gd) => Some(gd.as_ref()),
339            _ => None,
340        }
341    }
342
343    /// If this domain is already ground, return a mutable reference to the underlying [GroundDomain].
344    /// Otherwise, return None. This method does NOT perform any resolution.
345    pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
346        match self {
347            Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
348            _ => None,
349        }
350    }
351
352    /// If this domain is unresolved, return a reference to the underlying [UnresolvedDomain].
353    pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
354        match self {
355            Domain::Unresolved(ud) => Some(ud.as_ref()),
356            _ => None,
357        }
358    }
359
360    /// If this domain is unresolved, return a mutable reference to the underlying [UnresolvedDomain].
361    pub fn as_unresolved_mut(&mut self) -> Option<&mut UnresolvedDomain> {
362        match self {
363            Domain::Unresolved(ud) => Some(Moo::<UnresolvedDomain>::make_mut(ud)),
364            _ => None,
365        }
366    }
367
368    /// If this is [GroundDomain::Empty(ty)], get a reference to the return type `ty`
369    pub fn as_dom_empty(&self) -> Option<&ReturnType> {
370        if let Some(GroundDomain::Empty(ty)) = self.as_ground() {
371            return Some(ty);
372        }
373        None
374    }
375
376    /// If this is [GroundDomain::Empty(ty)], get a mutable reference to the return type `ty`
377    pub fn as_dom_empty_mut(&mut self) -> Option<&mut ReturnType> {
378        if let Some(GroundDomain::Empty(ty)) = self.as_ground_mut() {
379            return Some(ty);
380        }
381        None
382    }
383
384    /// True if this is [GroundDomain::Bool]
385    pub fn is_bool(&self) -> bool {
386        self.return_type() == ReturnType::Bool
387    }
388
389    /// True if this is a [GroundDomain::Int] or an [UnresolvedDomain::Int]
390    pub fn is_int(&self) -> bool {
391        self.return_type() == ReturnType::Int
392    }
393
394    /// If this domain is [GroundDomain::Int] or [UnresolveDomain::Int], get
395    /// its ranges. The ranges are cloned and upcast to Range<IntVal> if necessary.
396    pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
397        if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
398            return Some(rngs.iter().cloned().map(|r| r.into()).collect());
399        }
400        if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved() {
401            return Some(rngs.clone());
402        }
403        None
404    }
405
406    /// If this is an int domain, get a mutable reference to its ranges.
407    /// The domain always becomes [UnresolvedDomain::Int] after this operation.
408    pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
409        // We're "upcasting" ground ranges (Range<Int>) to the more general
410        // Range<IntVal>, which may contain references or expressions.
411        // We know that for now they are still ground, but we're giving the user a mutable
412        // reference, so they can overwrite the ranges with values that aren't ground.
413        // So, the entire domain has to become non-ground as well.
414        if let Some(GroundDomain::Int(rngs_gds)) = self.as_ground() {
415            let rngs: Vec<Range<IntVal>> = rngs_gds.iter().cloned().map(|r| r.into()).collect();
416            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Int(rngs)))
417        }
418
419        if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved_mut() {
420            return Some(rngs);
421        }
422        None
423    }
424
425    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
426    pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
427        if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
428            return Some(rngs);
429        }
430        None
431    }
432
433    /// If this is a [GroundDomain::Int(rngs)], get an immutable reference to rngs.
434    pub fn as_int_ground_mut(&mut self) -> Option<&mut Vec<Range<Int>>> {
435        if let Some(GroundDomain::Int(rngs)) = self.as_ground_mut() {
436            return Some(rngs);
437        }
438        None
439    }
440
441    /// If this is a matrix domain, get pointers to its element domain
442    /// and index domains.
443    pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
444        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
445            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
446            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
447            return Some((inner_dom, idx_doms));
448        }
449        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved() {
450            return Some((inner_dom.clone(), idx_doms.clone()));
451        }
452        None
453    }
454
455    /// If this is a matrix domain, get mutable references to its element
456    /// domain and its vector of index domains.
457    /// The domain always becomes [UnresolvedDomain::Matrix] after this operation.
458    pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
459        // "upcast" the entire domain to UnresolvedDomain
460        // See [Domain::as_dom_int_mut] for an explanation of why this is necessary
461        if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
462            let inner_dom: DomainPtr = inner_dom_gd.clone().into();
463            let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
464            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(inner_dom, idx_doms)));
465        }
466
467        if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved_mut() {
468            return Some((inner_dom, idx_doms));
469        }
470        None
471    }
472
473    /// If this is a [GroundDomain::Matrix], get immutable references to its element and index domains
474    pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
475        if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground() {
476            return Some((inner_dom, idx_doms));
477        }
478        None
479    }
480
481    /// If this is a [GroundDomain::Matrix], get mutable references to its element and index domains
482    pub fn as_matrix_ground_mut(
483        &mut self,
484    ) -> Option<(&mut Moo<GroundDomain>, &mut Vec<Moo<GroundDomain>>)> {
485        if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground_mut() {
486            return Some((inner_dom, idx_doms));
487        }
488        None
489    }
490
491    /// If this is a set domain, get its attributes and a pointer to its element domain.
492    pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
493        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
494            return Some((attr.clone().into(), inner_dom.clone().into()));
495        }
496        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
497            return Some((attr.clone(), inner_dom.clone()));
498        }
499        None
500    }
501
502    /// If this is a set domain, get mutable reference to its attributes and element domain.
503    /// The domain always becomes [UnresolvedDomain::Set] after this operation.
504    pub fn as_set_mut(&mut self) -> Option<(&mut SetAttr<IntVal>, &mut DomainPtr)> {
505        if let Some(GroundDomain::Set(attr_gd, inner_dom_gd)) = self.as_ground() {
506            let attr: SetAttr<IntVal> = attr_gd.clone().into();
507            let inner_dom = inner_dom_gd.clone().into();
508            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Set(attr, inner_dom)));
509        }
510
511        if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved_mut() {
512            return Some((attr, inner_dom));
513        }
514        None
515    }
516
517    /// If this is a [GroundDomain::Set], get immutable references to its attributes and inner domain
518    pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
519        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
520            return Some((attr, inner_dom));
521        }
522        None
523    }
524
525    /// If this is a [GroundDomain::Set], get mutable references to its attributes and inner domain
526    pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
527        if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
528            return Some((attr, inner_dom));
529        }
530        None
531    }
532
533    /// If this is a mset domain, get its attributes and a pointer to its element domain.
534    pub fn as_mset(&self) -> Option<(MSetAttr<IntVal>, DomainPtr)> {
535        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
536            return Some((attr.clone().into(), inner_dom.clone().into()));
537        }
538        if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved() {
539            return Some((attr.clone(), inner_dom.clone()));
540        }
541        None
542    }
543
544    /// If this is a set domain, get mutable reference to its attributes and element domain.
545    /// The domain always becomes [UnresolvedDomain::MSet] after this operation.
546    pub fn as_mset_mut(&mut self) -> Option<(&mut MSetAttr<IntVal>, &mut DomainPtr)> {
547        if let Some(GroundDomain::MSet(attr_gd, inner_dom_gd)) = self.as_ground() {
548            let attr: MSetAttr<IntVal> = attr_gd.clone().into();
549            let inner_dom = inner_dom_gd.clone().into();
550            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::MSet(attr, inner_dom)));
551        }
552
553        if let Some(UnresolvedDomain::MSet(attr, inner_dom)) = self.as_unresolved_mut() {
554            return Some((attr, inner_dom));
555        }
556        None
557    }
558
559    /// If this is a [GroundDomain::MSet], get immutable references to its attributes and inner domain
560    pub fn as_mset_ground(&self) -> Option<(&MSetAttr<Int>, &Moo<GroundDomain>)> {
561        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground() {
562            return Some((attr, inner_dom));
563        }
564        None
565    }
566
567    /// If this is a [GroundDomain::MSet], get mutable references to its attributes and inner domain
568    pub fn as_mset_ground_mut(&mut self) -> Option<(&mut MSetAttr<Int>, &mut Moo<GroundDomain>)> {
569        if let Some(GroundDomain::MSet(attr, inner_dom)) = self.as_ground_mut() {
570            return Some((attr, inner_dom));
571        }
572        None
573    }
574
575    /// If this is a tuple domain, get pointers to its element domains.
576    pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
577        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
578            return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
579        }
580        if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved() {
581            return Some(inner_doms.clone());
582        }
583        None
584    }
585
586    /// If this is a tuple domain, get a mutable reference to its vector of element domains.
587    /// The domain always becomes [UnresolvedDomain::Tuple] after this operation.
588    pub fn as_tuple_mut(&mut self) -> Option<&mut Vec<DomainPtr>> {
589        if let Some(GroundDomain::Tuple(inner_doms_gds)) = self.as_ground() {
590            let inner_doms: Vec<DomainPtr> =
591                inner_doms_gds.iter().cloned().map(|d| d.into()).collect();
592            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(inner_doms)));
593        }
594
595        if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved_mut() {
596            return Some(inner_doms);
597        }
598        None
599    }
600
601    /// If this is a [GroundDomain::Tuple], get immutable references to its element domains
602    pub fn as_tuple_ground(&self) -> Option<&Vec<Moo<GroundDomain>>> {
603        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
604            return Some(inner_doms);
605        }
606        None
607    }
608
609    /// If this is a [GroundDomain::Tuple], get mutable reference to its element domains
610    pub fn as_tuple_ground_mut(&mut self) -> Option<&mut Vec<Moo<GroundDomain>>> {
611        if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground_mut() {
612            return Some(inner_doms);
613        }
614        None
615    }
616
617    /// If this is a record domain, clone and return its entries.
618    pub fn as_record(&self) -> Option<Vec<FieldEntry>> {
619        if let Some(GroundDomain::Record(record_entries)) = self.as_ground() {
620            return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
621        }
622        if let Some(UnresolvedDomain::Record(record_entries)) = self.as_unresolved() {
623            return Some(record_entries.clone());
624        }
625        None
626    }
627
628    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
629    pub fn as_record_ground(&self) -> Option<&Vec<FieldEntryGround>> {
630        if let Some(GroundDomain::Record(entries)) = self.as_ground() {
631            return Some(entries);
632        }
633        None
634    }
635
636    /// If this is a record domain, get a mutable reference to its list of entries.
637    /// The domain always becomes [UnresolvedDomain::Record] after this operation.
638    pub fn as_record_mut(&mut self) -> Option<&mut Vec<FieldEntry>> {
639        if let Some(GroundDomain::Record(entries_gds)) = self.as_ground() {
640            let entries: Vec<FieldEntry> = entries_gds.iter().cloned().map(|r| r.into()).collect();
641            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Record(entries)));
642        }
643
644        if let Some(UnresolvedDomain::Record(entries_gds)) = self.as_unresolved_mut() {
645            return Some(entries_gds);
646        }
647        None
648    }
649
650    /// If this is a [GroundDomain::Record], get a mutable reference to its entries
651    pub fn as_record_ground_mut(&mut self) -> Option<&mut Vec<FieldEntryGround>> {
652        if let Some(GroundDomain::Record(entries)) = self.as_ground_mut() {
653            return Some(entries);
654        }
655        None
656    }
657
658    /// If this is a sequence domain, get its (attributes, domain)
659    pub fn as_sequence(&self) -> Option<(SequenceAttr<IntVal>, Moo<Domain>)> {
660        if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
661            return Some((attrs.clone().into(), dom.clone().into()));
662        }
663        if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved() {
664            return Some((attrs.clone(), dom.clone()));
665        }
666        None
667    }
668
669    /// If this is a function domain, convert it to unresolved and get mutable references to
670    /// its (attrs, domain, co-domain).
671    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
672    pub fn as_sequence_mut(&mut self) -> Option<(&mut SequenceAttr<IntVal>, &mut Moo<Domain>)> {
673        if let Some(GroundDomain::Sequence(attrs, dom)) = self.as_ground() {
674            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Sequence(
675                attrs.clone().into(),
676                dom.clone().into(),
677            )));
678        }
679
680        if let Some(UnresolvedDomain::Sequence(attrs, dom)) = self.as_unresolved_mut() {
681            return Some((attrs, dom));
682        }
683        None
684    }
685
686    /// If this is a function domain, get its (attributes, domain, co-domain)
687    pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
688        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
689            return Some((
690                attrs.clone().into(),
691                dom.clone().into(),
692                codom.clone().into(),
693            ));
694        }
695        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
696            return Some((attrs.clone(), dom.clone(), codom.clone()));
697        }
698        None
699    }
700
701    /// If this is a function domain, convert it to unresolved and get mutable references to
702    /// its (attrs, domain, co-domain).
703    /// The domain always becomes [UnresolvedDomain::Function] after this operation.
704    pub fn as_function_mut(
705        &mut self,
706    ) -> Option<(&mut FuncAttr<IntVal>, &mut Moo<Domain>, &mut Moo<Domain>)> {
707        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
708            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
709                attrs.clone().into(),
710                dom.clone().into(),
711                codom.clone().into(),
712            )));
713        }
714
715        if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved_mut() {
716            return Some((attrs, dom, codom));
717        }
718        None
719    }
720
721    /// If this is a [GroundDomain::Function], get its (attrs, domain, co-domain)
722    pub fn as_function_ground(
723        &self,
724    ) -> Option<(&FuncAttr, &Moo<GroundDomain>, &Moo<GroundDomain>)> {
725        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
726            return Some((attrs, dom, codom));
727        }
728        None
729    }
730
731    /// If this is a [GroundDomain::Function], get mutable references to its (attrs, domain, co-domain)
732    pub fn as_function_ground_mut(
733        &mut self,
734    ) -> Option<(
735        &mut FuncAttr,
736        &mut Moo<GroundDomain>,
737        &mut Moo<GroundDomain>,
738    )> {
739        if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground_mut() {
740            return Some((attrs, dom, codom));
741        }
742        None
743    }
744
745    /// If this is a partition domain, get its (attributes, domain)
746    pub fn as_partition(&self) -> Option<(PartitionAttr<IntVal>, Moo<Domain>)> {
747        if let Some(GroundDomain::Partition(attrs, doms)) = self.as_ground() {
748            return Some((attrs.clone().into(), doms.clone().into()));
749        }
750        if let Some(UnresolvedDomain::Partition(attrs, doms)) = self.as_unresolved() {
751            return Some((attrs.clone(), doms.clone()));
752        }
753        None
754    }
755
756    /// If this is a partition domain, get mutable reference to its attributes and element domain.
757    /// The domain always becomes [UnresolvedDomain::Partition] after this operation.
758    pub fn as_partition_mut(&mut self) -> Option<(&mut PartitionAttr<IntVal>, &mut DomainPtr)> {
759        if let Some(GroundDomain::Partition(attr_gd, inner_dom_gd)) = self.as_ground() {
760            let attr: PartitionAttr<IntVal> = attr_gd.clone().into();
761            let inner_dom = inner_dom_gd.clone().into();
762            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Partition(attr, inner_dom)));
763        }
764
765        if let Some(UnresolvedDomain::Partition(attr, inner_dom)) = self.as_unresolved_mut() {
766            return Some((attr, inner_dom));
767        }
768        None
769    }
770
771    /// If this is a [GroundDomain::Partition], get immutable references to its attributes and inner domain
772    pub fn as_partition_ground(&self) -> Option<(&PartitionAttr<Int>, &Moo<GroundDomain>)> {
773        if let Some(GroundDomain::Partition(attr, inner_dom)) = self.as_ground() {
774            return Some((attr, inner_dom));
775        }
776        None
777    }
778
779    /// If this is a [GroundDomain::Partition], get mutable references to its attributes and inner domain
780    pub fn as_partition_ground_mut(
781        &mut self,
782    ) -> Option<(&mut PartitionAttr<Int>, &mut Moo<GroundDomain>)> {
783        if let Some(GroundDomain::Partition(attr, inner_dom)) = self.as_ground_mut() {
784            return Some((attr, inner_dom));
785        }
786        None
787    }
788
789    /// If this is a variant domain, clone and return its entries.
790    pub fn as_variant(&self) -> Option<Vec<FieldEntry>> {
791        if let Some(GroundDomain::Variant(entries)) = self.as_ground() {
792            return Some(entries.iter().cloned().map(|r| r.into()).collect());
793        }
794        if let Some(UnresolvedDomain::Variant(entries)) = self.as_unresolved() {
795            return Some(entries.clone());
796        }
797        None
798    }
799
800    /// If this is a [GroundDomain::Variant], get a mutable reference to its entries
801    pub fn as_variant_ground(&self) -> Option<&Vec<FieldEntryGround>> {
802        if let Some(GroundDomain::Variant(entries)) = self.as_ground() {
803            return Some(entries);
804        }
805        None
806    }
807
808    /// If this is a variant domain, get a mutable reference to its list of entries.
809    /// The domain always becomes [UnresolvedDomain::Variant] after this operation.
810    pub fn as_variant_mut(&mut self) -> Option<&mut Vec<FieldEntry>> {
811        if let Some(GroundDomain::Variant(entries_gds)) = self.as_ground() {
812            let entries: Vec<FieldEntry> = entries_gds.iter().cloned().map(|r| r.into()).collect();
813            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Variant(entries)));
814        }
815
816        if let Some(UnresolvedDomain::Variant(entries_gds)) = self.as_unresolved_mut() {
817            return Some(entries_gds);
818        }
819        None
820    }
821
822    /// If this is a [GroundDomain::Variant], get a mutable reference to its entries
823    pub fn as_variant_ground_mut(&mut self) -> Option<&mut Vec<FieldEntryGround>> {
824        if let Some(GroundDomain::Variant(entries)) = self.as_ground_mut() {
825            return Some(entries);
826        }
827        None
828    }
829
830    /// If this is a relation domain, get its (attributes, [domains])
831    pub fn as_relation(&self) -> Option<(RelAttr<IntVal>, Vec<Moo<Domain>>)> {
832        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
833            return Some((
834                attrs.clone().into(),
835                doms.iter().cloned().map(|d| d.into()).collect(),
836            ));
837        }
838        if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved() {
839            return Some((attrs.clone(), doms.clone()));
840        }
841        None
842    }
843
844    /// If this is a relation domain, convert it to unresolved and get mutable references to
845    /// its (attrs, [domains]).
846    /// The domain always becomes [UnresolvedDomain::Relation] after this operation.
847    pub fn as_relation_mut(&mut self) -> Option<(&mut RelAttr<IntVal>, &mut Vec<Moo<Domain>>)> {
848        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
849            *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Relation(
850                attrs.clone().into(),
851                doms.iter().cloned().map(|d| d.into()).collect(),
852            )));
853        }
854
855        if let Some(UnresolvedDomain::Relation(attrs, doms)) = self.as_unresolved_mut() {
856            return Some((attrs, doms));
857        }
858        None
859    }
860
861    /// If this is a [GroundDomain::Relation], get its (attrs, [domains])
862    pub fn as_relation_ground(&self) -> Option<(&RelAttr, &Vec<Moo<GroundDomain>>)> {
863        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground() {
864            return Some((attrs, doms));
865        }
866        None
867    }
868
869    /// If this is a [GroundDomain::Relation], get mutable references to its (attrs, [domains])
870    pub fn as_relation_ground_mut(
871        &mut self,
872    ) -> Option<(&mut RelAttr, &mut Vec<Moo<GroundDomain>>)> {
873        if let Some(GroundDomain::Relation(attrs, doms)) = self.as_ground_mut() {
874            return Some((attrs, doms));
875        }
876        None
877    }
878
879    /// Compute the intersection of two domains
880    pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
881        match (self, other) {
882            (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
883            (Domain::Unresolved(a), Domain::Unresolved(b)) => {
884                Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
885            }
886            (Domain::Unresolved(u), Domain::Ground(g))
887            | (Domain::Ground(g), Domain::Unresolved(u)) => {
888                todo!("Union of unresolved domain {u} and ground domain {g} is not yet implemented")
889            }
890        }
891    }
892
893    /// Compute the intersection of two ground domains
894    pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
895        match (self, other) {
896            (Domain::Ground(a), Domain::Ground(b)) => {
897                a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
898            }
899            _ => Err(DomainOpError::NotGround),
900        }
901    }
902
903    /// If the domain is ground, return an iterator over its values
904    pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
905        if let Some(gd) = self.as_ground() {
906            return gd.values();
907        }
908        Err(DomainOpError::NotGround)
909    }
910
911    /// If the domain is ground, return its size bound
912    pub fn length(&self) -> Result<u64, DomainOpError> {
913        if let Some(gd) = self.as_ground() {
914            return gd.length();
915        }
916        Err(DomainOpError::NotGround)
917    }
918    /// Get the size of some domain
919    ///
920    /// As opposed to `Domain::length`, this function returns a signed integer (`i32`) rather than unsigned.
921    /// * `DomainOpError::NotGround` - This function only applies to `ground` domains
922    /// * `DomainOpError::TooLarge` - Converting to an integer my not be possible if the domain is too big
923    pub fn length_signed(&self) -> Result<i32, DomainOpError> {
924        let gd = self.as_ground().ok_or(DomainOpError::NotGround)?;
925        let len = gd.length()?;
926        len.try_into().map_err(|_| DomainOpError::TooLarge)
927    }
928
929    /// Construct a ground domain from a slice of values
930    pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
931        GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
932    }
933
934    /// Returns true if `lit` is a valid value of this domain
935    pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
936        if let Some(gd) = self.as_ground() {
937            return gd.contains(lit);
938        }
939        Err(DomainOpError::NotGround)
940    }
941
942    pub fn element_domain(&self) -> Option<DomainPtr> {
943        match self {
944            Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
945            Domain::Unresolved(ud) => ud.element_domain(),
946        }
947    }
948}
949
950impl Typeable for Domain {
951    fn return_type(&self) -> ReturnType {
952        match self {
953            Domain::Ground(dom) => dom.return_type(),
954            Domain::Unresolved(dom) => dom.return_type(),
955        }
956    }
957}
958
959impl Display for Domain {
960    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
961        match &self {
962            Domain::Ground(gd) => gd.fmt(f),
963            Domain::Unresolved(ud) => ud.fmt(f),
964        }
965    }
966}
967
968fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
969    doms.iter()
970        .map(|idx| match idx.as_ref() {
971            Domain::Ground(idx_gd) => Some(idx_gd.clone()),
972            _ => None,
973        })
974        .collect()
975}
976
977#[cfg(test)]
978mod tests {
979    use super::*;
980    use crate::ast::Name;
981    use crate::{domain_int, range};
982
983    #[test]
984    fn test_negative_product() {
985        let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
986        let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
987        let res = d1
988            .as_ground()
989            .unwrap()
990            .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
991            .unwrap();
992
993        assert!(matches!(res, GroundDomain::Int(_)));
994        if let GroundDomain::Int(ranges) = res {
995            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
996        }
997    }
998
999    #[test]
1000    fn test_negative_div() {
1001        let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
1002        let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
1003        let res = d1
1004            .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
1005            .unwrap();
1006
1007        assert!(matches!(res, GroundDomain::Int(_)));
1008        if let GroundDomain::Int(ranges) = res {
1009            assert!(!ranges.contains(&Range::Bounded(-4, 4)));
1010        }
1011    }
1012
1013    #[test]
1014    fn test_length_basic() {
1015        assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
1016        assert_eq!(Domain::bool().length(), Ok(2));
1017        assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
1018        assert_eq!(
1019            domain_int!(1..2, 5..).length(),
1020            Err(DomainOpError::Unbounded)
1021        );
1022    }
1023    #[test]
1024    fn test_length_set_basic() {
1025        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
1026        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
1027        assert_eq!(s.length(), Ok(8));
1028
1029        // {{1,2}, {1,3}, {2,3}}
1030        let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
1031        assert_eq!(s.length(), Ok(3));
1032
1033        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
1034        let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
1035        assert_eq!(s.length(), Ok(6));
1036
1037        // {{1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}}
1038        let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
1039        assert_eq!(s.length(), Ok(7));
1040
1041        // {∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}}
1042        let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
1043        assert_eq!(s.length(), Ok(7));
1044    }
1045
1046    #[test]
1047    fn test_length_set_nested() {
1048        // {
1049        // ∅,                                          -- all size 0
1050        // {∅}, {{1}}, {{2}}, {{1, 2}},                -- all size 1
1051        // {∅, {1}}, {∅, {2}}, {∅, {1, 2}},            -- all size 2
1052        // {{1}, {2}}, {{1}, {1, 2}}, {{2}, {1, 2}}
1053        // }
1054        let s2 = Domain::set(
1055            SetAttr::new_max_size(2),
1056            // {∅, {1}, {2}, {1,2}}
1057            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1058        );
1059        assert_eq!(s2.length(), Ok(11));
1060    }
1061
1062    #[test]
1063    fn test_length_set_unbounded_inner() {
1064        // leaf domain is unbounded
1065        let s2_bad = Domain::set(
1066            SetAttr::new_max_size(2),
1067            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
1068        );
1069        assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
1070    }
1071
1072    #[test]
1073    fn test_length_set_overflow() {
1074        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
1075        assert!(s.length().is_ok());
1076
1077        // current way of calculating the formula overflows for anything larger than this
1078        let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
1079        assert_eq!(s.length(), Err(DomainOpError::TooLarge));
1080    }
1081
1082    #[test]
1083    fn test_length_tuple() {
1084        // 3 ways to pick first element, 2 ways to pick second element
1085        let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
1086        assert_eq!(t.length(), Ok(6));
1087    }
1088
1089    #[test]
1090    fn test_length_record() {
1091        // 3 ways to pick rec.a, 2 ways to pick rec.b
1092        let t = Domain::record(vec![
1093            FieldEntry {
1094                name: Name::user("a"),
1095                domain: domain_int!(1..3),
1096            },
1097            FieldEntry {
1098                name: Name::user("b"),
1099                domain: Domain::bool(),
1100            },
1101        ]);
1102        assert_eq!(t.length(), Ok(6));
1103    }
1104
1105    #[test]
1106    fn test_length_matrix_basic() {
1107        // 3 booleans -> [T, T, T], [T, T, F], ..., [F, F, F]
1108        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
1109        assert_eq!(m.length(), Ok(8));
1110
1111        // 2 numbers, each 1..3 -> 3*3 options
1112        let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
1113        assert_eq!(m.length(), Ok(9));
1114    }
1115
1116    #[test]
1117    fn test_length_matrix_2d() {
1118        // 2x3 matrix of booleans -> (2**2)**3 = 64 options
1119        let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
1120        assert_eq!(m.length(), Ok(64));
1121    }
1122
1123    #[test]
1124    fn test_length_matrix_of_sets() {
1125        // 3 sets drawn from 1..2; 4**3 = 64 total options
1126        let m = Domain::matrix(
1127            Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
1128            vec![domain_int!(1..3)],
1129        );
1130        assert_eq!(m.length(), Ok(64));
1131    }
1132}