1use super::attrs::SetAttr;
2use super::ground::GroundDomain;
3use super::range::Range;
4use super::unresolved::{IntVal, UnresolvedDomain};
5use crate::ast::domains::attrs::MSetAttr;
6use crate::ast::{
7 DeclarationPtr, DomainOpError, Expression, FuncAttr, Literal, Moo, RecordEntry,
8 RecordEntryGround, Reference, ReturnType, 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
17pub 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 pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
30 self.as_ref().union(other.as_ref()).map(DomainPtr::new)
31 }
32
33 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=RecordEntry)]
71#[biplate(to=IntVal)]
72#[path_prefix(conjure_cp::ast)]
73pub enum Domain {
74 Ground(Moo<GroundDomain>),
76 Unresolved(Moo<UnresolvedDomain>),
78}
79
80pub trait HasDomain {
82 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
92thread_local! {
95 static BOOL_DOMAIN: DomainPtr =
96 Moo::new(Domain::Ground(Moo::new(GroundDomain::Bool)));
97}
98
99impl Domain {
100 pub fn bool() -> DomainPtr {
103 BOOL_DOMAIN.with(Clone::clone)
104 }
105
106 pub fn empty(ty: ReturnType) -> DomainPtr {
109 Moo::new(Domain::Ground(Moo::new(GroundDomain::Empty(ty))))
110 }
111
112 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 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 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 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 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 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 pub fn record(entries: Vec<RecordEntry>) -> 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 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 pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
230 where
231 T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
232 {
233 if let Ok(attrs_gd) = attrs.clone().try_into()
234 && let Some(dom_gd) = dom.as_ground()
235 && let Some(cdom_gd) = cdom.as_ground()
236 {
237 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
238 attrs_gd,
239 Moo::new(dom_gd.clone()),
240 Moo::new(cdom_gd.clone()),
241 ))));
242 }
243
244 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
245 attrs.into(),
246 dom,
247 cdom,
248 ))))
249 }
250
251 pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
256 match self {
257 Domain::Ground(gd) => Some(gd.clone()),
258 Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
259 }
260 }
261
262 pub fn as_ground(&self) -> Option<&GroundDomain> {
266 match self {
267 Domain::Ground(gd) => Some(gd.as_ref()),
268 _ => None,
269 }
270 }
271
272 pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
275 match self {
276 Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
277 _ => None,
278 }
279 }
280
281 pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
283 match self {
284 Domain::Unresolved(ud) => Some(ud.as_ref()),
285 _ => None,
286 }
287 }
288
289 pub fn as_unresolved_mut(&mut self) -> Option<&mut UnresolvedDomain> {
291 match self {
292 Domain::Unresolved(ud) => Some(Moo::<UnresolvedDomain>::make_mut(ud)),
293 _ => None,
294 }
295 }
296
297 pub fn as_dom_empty(&self) -> Option<&ReturnType> {
299 if let Some(GroundDomain::Empty(ty)) = self.as_ground() {
300 return Some(ty);
301 }
302 None
303 }
304
305 pub fn as_dom_empty_mut(&mut self) -> Option<&mut ReturnType> {
307 if let Some(GroundDomain::Empty(ty)) = self.as_ground_mut() {
308 return Some(ty);
309 }
310 None
311 }
312
313 pub fn is_bool(&self) -> bool {
315 self.return_type() == ReturnType::Bool
316 }
317
318 pub fn is_int(&self) -> bool {
320 self.return_type() == ReturnType::Int
321 }
322
323 pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
326 if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
327 return Some(rngs.iter().cloned().map(|r| r.into()).collect());
328 }
329 if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved() {
330 return Some(rngs.clone());
331 }
332 None
333 }
334
335 pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
338 if let Some(GroundDomain::Int(rngs_gds)) = self.as_ground() {
344 let rngs: Vec<Range<IntVal>> = rngs_gds.iter().cloned().map(|r| r.into()).collect();
345 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Int(rngs)))
346 }
347
348 if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved_mut() {
349 return Some(rngs);
350 }
351 None
352 }
353
354 pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
356 if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
357 return Some(rngs);
358 }
359 None
360 }
361
362 pub fn as_int_ground_mut(&mut self) -> Option<&mut Vec<Range<Int>>> {
364 if let Some(GroundDomain::Int(rngs)) = self.as_ground_mut() {
365 return Some(rngs);
366 }
367 None
368 }
369
370 pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
373 if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
374 let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
375 let inner_dom: DomainPtr = inner_dom_gd.clone().into();
376 return Some((inner_dom, idx_doms));
377 }
378 if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved() {
379 return Some((inner_dom.clone(), idx_doms.clone()));
380 }
381 None
382 }
383
384 pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
388 if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
391 let inner_dom: DomainPtr = inner_dom_gd.clone().into();
392 let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
393 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(inner_dom, idx_doms)));
394 }
395
396 if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved_mut() {
397 return Some((inner_dom, idx_doms));
398 }
399 None
400 }
401
402 pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
404 if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground() {
405 return Some((inner_dom, idx_doms));
406 }
407 None
408 }
409
410 pub fn as_matrix_ground_mut(
412 &mut self,
413 ) -> Option<(&mut Moo<GroundDomain>, &mut Vec<Moo<GroundDomain>>)> {
414 if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground_mut() {
415 return Some((inner_dom, idx_doms));
416 }
417 None
418 }
419
420 pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
422 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
423 return Some((attr.clone().into(), inner_dom.clone().into()));
424 }
425 if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
426 return Some((attr.clone(), inner_dom.clone()));
427 }
428 None
429 }
430
431 pub fn as_set_mut(&mut self) -> Option<(&mut SetAttr<IntVal>, &mut DomainPtr)> {
434 if let Some(GroundDomain::Set(attr_gd, inner_dom_gd)) = self.as_ground() {
435 let attr: SetAttr<IntVal> = attr_gd.clone().into();
436 let inner_dom = inner_dom_gd.clone().into();
437 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Set(attr, inner_dom)));
438 }
439
440 if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved_mut() {
441 return Some((attr, inner_dom));
442 }
443 None
444 }
445
446 pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
448 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
449 return Some((attr, inner_dom));
450 }
451 None
452 }
453
454 pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
456 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
457 return Some((attr, inner_dom));
458 }
459 None
460 }
461
462 pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
464 if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
465 return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
466 }
467 if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved() {
468 return Some(inner_doms.clone());
469 }
470 None
471 }
472
473 pub fn as_tuple_mut(&mut self) -> Option<&mut Vec<DomainPtr>> {
476 if let Some(GroundDomain::Tuple(inner_doms_gds)) = self.as_ground() {
477 let inner_doms: Vec<DomainPtr> =
478 inner_doms_gds.iter().cloned().map(|d| d.into()).collect();
479 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(inner_doms)));
480 }
481
482 if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved_mut() {
483 return Some(inner_doms);
484 }
485 None
486 }
487
488 pub fn as_tuple_ground(&self) -> Option<&Vec<Moo<GroundDomain>>> {
490 if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
491 return Some(inner_doms);
492 }
493 None
494 }
495
496 pub fn as_tuple_ground_mut(&mut self) -> Option<&mut Vec<Moo<GroundDomain>>> {
498 if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground_mut() {
499 return Some(inner_doms);
500 }
501 None
502 }
503
504 pub fn as_record(&self) -> Option<Vec<RecordEntry>> {
506 if let Some(GroundDomain::Record(record_entries)) = self.as_ground() {
507 return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
508 }
509 if let Some(UnresolvedDomain::Record(record_entries)) = self.as_unresolved() {
510 return Some(record_entries.clone());
511 }
512 None
513 }
514
515 pub fn as_record_ground(&self) -> Option<&Vec<RecordEntryGround>> {
517 if let Some(GroundDomain::Record(entries)) = self.as_ground() {
518 return Some(entries);
519 }
520 None
521 }
522
523 pub fn as_record_mut(&mut self) -> Option<&mut Vec<RecordEntry>> {
526 if let Some(GroundDomain::Record(entries_gds)) = self.as_ground() {
527 let entries: Vec<RecordEntry> = entries_gds.iter().cloned().map(|r| r.into()).collect();
528 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Record(entries)));
529 }
530
531 if let Some(UnresolvedDomain::Record(entries_gds)) = self.as_unresolved_mut() {
532 return Some(entries_gds);
533 }
534 None
535 }
536
537 pub fn as_record_ground_mut(&mut self) -> Option<&mut Vec<RecordEntryGround>> {
539 if let Some(GroundDomain::Record(entries)) = self.as_ground_mut() {
540 return Some(entries);
541 }
542 None
543 }
544
545 pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
547 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
548 return Some((
549 attrs.clone().into(),
550 dom.clone().into(),
551 codom.clone().into(),
552 ));
553 }
554 if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
555 return Some((attrs.clone(), dom.clone(), codom.clone()));
556 }
557 None
558 }
559
560 pub fn as_function_mut(
564 &mut self,
565 ) -> Option<(&mut FuncAttr<IntVal>, &mut Moo<Domain>, &mut Moo<Domain>)> {
566 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
567 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
568 attrs.clone().into(),
569 dom.clone().into(),
570 codom.clone().into(),
571 )));
572 }
573
574 if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved_mut() {
575 return Some((attrs, dom, codom));
576 }
577 None
578 }
579
580 pub fn as_function_ground(
582 &self,
583 ) -> Option<(&FuncAttr, &Moo<GroundDomain>, &Moo<GroundDomain>)> {
584 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
585 return Some((attrs, dom, codom));
586 }
587 None
588 }
589
590 pub fn as_function_ground_mut(
592 &mut self,
593 ) -> Option<(
594 &mut FuncAttr,
595 &mut Moo<GroundDomain>,
596 &mut Moo<GroundDomain>,
597 )> {
598 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground_mut() {
599 return Some((attrs, dom, codom));
600 }
601 None
602 }
603
604 pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
606 match (self, other) {
607 (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
608 (Domain::Unresolved(a), Domain::Unresolved(b)) => {
609 Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
610 }
611 (Domain::Unresolved(u), Domain::Ground(g))
612 | (Domain::Ground(g), Domain::Unresolved(u)) => {
613 todo!("Union of unresolved domain {u} and ground domain {g} is not yet implemented")
614 }
615 }
616 }
617
618 pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
620 match (self, other) {
621 (Domain::Ground(a), Domain::Ground(b)) => {
622 a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
623 }
624 _ => Err(DomainOpError::NotGround),
625 }
626 }
627
628 pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
630 if let Some(gd) = self.as_ground() {
631 return gd.values();
632 }
633 Err(DomainOpError::NotGround)
634 }
635
636 pub fn length(&self) -> Result<u64, DomainOpError> {
638 if let Some(gd) = self.as_ground() {
639 return gd.length();
640 }
641 Err(DomainOpError::NotGround)
642 }
643
644 pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
646 GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
647 }
648
649 pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
651 if let Some(gd) = self.as_ground() {
652 return gd.contains(lit);
653 }
654 Err(DomainOpError::NotGround)
655 }
656
657 pub fn element_domain(&self) -> Option<DomainPtr> {
658 match self {
659 Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
660 Domain::Unresolved(ud) => ud.element_domain(),
661 }
662 }
663}
664
665impl Typeable for Domain {
666 fn return_type(&self) -> ReturnType {
667 match self {
668 Domain::Ground(dom) => dom.return_type(),
669 Domain::Unresolved(dom) => dom.return_type(),
670 }
671 }
672}
673
674impl Display for Domain {
675 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
676 match &self {
677 Domain::Ground(gd) => gd.fmt(f),
678 Domain::Unresolved(ud) => ud.fmt(f),
679 }
680 }
681}
682
683fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
684 doms.iter()
685 .map(|idx| match idx.as_ref() {
686 Domain::Ground(idx_gd) => Some(idx_gd.clone()),
687 _ => None,
688 })
689 .collect()
690}
691
692#[cfg(test)]
693mod tests {
694 use super::*;
695 use crate::ast::Name;
696 use crate::{domain_int, range};
697
698 #[test]
699 fn test_negative_product() {
700 let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
701 let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
702 let res = d1
703 .as_ground()
704 .unwrap()
705 .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
706 .unwrap();
707
708 assert!(matches!(res, GroundDomain::Int(_)));
709 if let GroundDomain::Int(ranges) = res {
710 assert!(!ranges.contains(&Range::Bounded(-4, 4)));
711 }
712 }
713
714 #[test]
715 fn test_negative_div() {
716 let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
717 let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
718 let res = d1
719 .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
720 .unwrap();
721
722 assert!(matches!(res, GroundDomain::Int(_)));
723 if let GroundDomain::Int(ranges) = res {
724 assert!(!ranges.contains(&Range::Bounded(-4, 4)));
725 }
726 }
727
728 #[test]
729 fn test_length_basic() {
730 assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
731 assert_eq!(Domain::bool().length(), Ok(2));
732 assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
733 assert_eq!(
734 domain_int!(1..2, 5..).length(),
735 Err(DomainOpError::Unbounded)
736 );
737 }
738 #[test]
739 fn test_length_set_basic() {
740 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
742 assert_eq!(s.length(), Ok(8));
743
744 let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
746 assert_eq!(s.length(), Ok(3));
747
748 let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
750 assert_eq!(s.length(), Ok(6));
751
752 let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
754 assert_eq!(s.length(), Ok(7));
755
756 let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
758 assert_eq!(s.length(), Ok(7));
759 }
760
761 #[test]
762 fn test_length_set_nested() {
763 let s2 = Domain::set(
770 SetAttr::new_max_size(2),
771 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
773 );
774 assert_eq!(s2.length(), Ok(11));
775 }
776
777 #[test]
778 fn test_length_set_unbounded_inner() {
779 let s2_bad = Domain::set(
781 SetAttr::new_max_size(2),
782 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
783 );
784 assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
785 }
786
787 #[test]
788 fn test_length_set_overflow() {
789 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
790 assert!(s.length().is_ok());
791
792 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
794 assert_eq!(s.length(), Err(DomainOpError::TooLarge));
795 }
796
797 #[test]
798 fn test_length_tuple() {
799 let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
801 assert_eq!(t.length(), Ok(6));
802 }
803
804 #[test]
805 fn test_length_record() {
806 let t = Domain::record(vec![
808 RecordEntry {
809 name: Name::user("a"),
810 domain: domain_int!(1..3),
811 },
812 RecordEntry {
813 name: Name::user("b"),
814 domain: Domain::bool(),
815 },
816 ]);
817 assert_eq!(t.length(), Ok(6));
818 }
819
820 #[test]
821 fn test_length_matrix_basic() {
822 let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
824 assert_eq!(m.length(), Ok(8));
825
826 let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
828 assert_eq!(m.length(), Ok(9));
829 }
830
831 #[test]
832 fn test_length_matrix_2d() {
833 let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
835 assert_eq!(m.length(), Ok(64));
836 }
837
838 #[test]
839 fn test_length_matrix_of_sets() {
840 let m = Domain::matrix(
842 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
843 vec![domain_int!(1..3)],
844 );
845 assert_eq!(m.length(), Ok(64));
846 }
847}