1use super::attrs::SetAttr;
2use super::ground::GroundDomain;
3use super::range::Range;
4use super::unresolved::{IntVal, UnresolvedDomain};
5use crate::ast::{
6 DeclarationPtr, DomainOpError, Expression, FuncAttr, Literal, Moo, RecordEntry,
7 RecordEntryGround, Reference, ReturnType, Typeable,
8};
9use itertools::Itertools;
10use polyquine::Quine;
11use serde::{Deserialize, Serialize};
12use std::fmt::{Display, Formatter};
13use std::thread_local;
14use uniplate::Uniplate;
15
16pub type Int = i32;
18
19pub type DomainPtr = Moo<Domain>;
20
21impl DomainPtr {
22 pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
23 self.as_ref().resolve()
24 }
25
26 pub fn union(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
29 self.as_ref().union(other.as_ref()).map(DomainPtr::new)
30 }
31
32 pub fn intersect(&self, other: &DomainPtr) -> Result<DomainPtr, DomainOpError> {
35 self.as_ref().intersect(other.as_ref()).map(DomainPtr::new)
36 }
37}
38
39impl From<Moo<GroundDomain>> for DomainPtr {
40 fn from(value: Moo<GroundDomain>) -> Self {
41 Moo::new(Domain::Ground(value))
42 }
43}
44
45impl From<Moo<UnresolvedDomain>> for DomainPtr {
46 fn from(value: Moo<UnresolvedDomain>) -> Self {
47 Moo::new(Domain::Unresolved(value))
48 }
49}
50
51impl From<GroundDomain> for DomainPtr {
52 fn from(value: GroundDomain) -> Self {
53 Moo::new(Domain::Ground(Moo::new(value)))
54 }
55}
56
57impl From<UnresolvedDomain> for DomainPtr {
58 fn from(value: UnresolvedDomain) -> Self {
59 Moo::new(Domain::Unresolved(Moo::new(value)))
60 }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
64#[biplate(to=DomainPtr)]
65#[biplate(to=GroundDomain)]
66#[biplate(to=UnresolvedDomain)]
67#[biplate(to=Expression)]
68#[biplate(to=Reference)]
69#[biplate(to=RecordEntry)]
70#[biplate(to=IntVal)]
71#[path_prefix(conjure_cp::ast)]
72pub enum Domain {
73 Ground(Moo<GroundDomain>),
75 Unresolved(Moo<UnresolvedDomain>),
77}
78
79pub trait HasDomain {
81 fn domain_of(&self) -> DomainPtr;
83}
84
85impl<T: HasDomain> Typeable for T {
86 fn return_type(&self) -> ReturnType {
87 self.domain_of().return_type()
88 }
89}
90
91thread_local! {
94 static BOOL_DOMAIN: DomainPtr =
95 Moo::new(Domain::Ground(Moo::new(GroundDomain::Bool)));
96}
97
98impl Domain {
99 pub fn bool() -> DomainPtr {
102 BOOL_DOMAIN.with(Clone::clone)
103 }
104
105 pub fn empty(ty: ReturnType) -> DomainPtr {
108 Moo::new(Domain::Ground(Moo::new(GroundDomain::Empty(ty))))
109 }
110
111 pub fn int<T>(ranges: Vec<T>) -> DomainPtr
115 where
116 T: Into<Range<IntVal>> + TryInto<Range<Int>> + Clone,
117 {
118 if let Ok(int_rngs) = ranges
119 .iter()
120 .cloned()
121 .map(TryInto::try_into)
122 .collect::<Result<Vec<_>, _>>()
123 {
124 return Domain::int_ground(int_rngs);
125 }
126 let unresolved_rngs: Vec<Range<IntVal>> = ranges.into_iter().map(Into::into).collect();
127 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Int(
128 unresolved_rngs,
129 ))))
130 }
131
132 pub fn int_ground(ranges: Vec<Range<Int>>) -> DomainPtr {
134 let rngs = Range::squeeze(&ranges);
135 Moo::new(Domain::Ground(Moo::new(GroundDomain::Int(rngs))))
136 }
137
138 pub fn set<T>(attr: T, inner_dom: DomainPtr) -> DomainPtr
142 where
143 T: Into<SetAttr<IntVal>> + TryInto<SetAttr<Int>> + Clone,
144 {
145 if let Domain::Ground(gd) = inner_dom.as_ref()
146 && let Ok(int_attr) = attr.clone().try_into()
147 {
148 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Set(
149 int_attr,
150 gd.clone(),
151 ))));
152 }
153 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Set(
154 attr.into(),
155 inner_dom,
156 ))))
157 }
158
159 pub fn matrix(inner_dom: DomainPtr, idx_doms: Vec<DomainPtr>) -> DomainPtr {
163 if let Domain::Ground(gd) = inner_dom.as_ref()
164 && let Some(idx_gds) = as_grounds(&idx_doms)
165 {
166 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Matrix(
167 gd.clone(),
168 idx_gds,
169 ))));
170 }
171 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(
172 inner_dom, idx_doms,
173 ))))
174 }
175
176 pub fn tuple(inner_doms: Vec<DomainPtr>) -> DomainPtr {
180 if let Some(inner_gds) = as_grounds(&inner_doms) {
181 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Tuple(inner_gds))));
182 }
183 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(
184 inner_doms,
185 ))))
186 }
187
188 pub fn record(entries: Vec<RecordEntry>) -> DomainPtr {
192 if let Ok(entries_gds) = entries.iter().cloned().map(TryInto::try_into).try_collect() {
193 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Record(entries_gds))));
194 }
195 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Record(
196 entries,
197 ))))
198 }
199
200 pub fn reference(ptr: DeclarationPtr) -> Option<DomainPtr> {
202 ptr.as_domain_letting()?;
203 Some(Moo::new(Domain::Unresolved(Moo::new(
204 UnresolvedDomain::Reference(Reference::new(ptr)),
205 ))))
206 }
207
208 pub fn function<T>(attrs: T, dom: DomainPtr, cdom: DomainPtr) -> DomainPtr
210 where
211 T: Into<FuncAttr<IntVal>> + TryInto<FuncAttr<Int>> + Clone,
212 {
213 if let Ok(attrs_gd) = attrs.clone().try_into()
214 && let Some(dom_gd) = dom.as_ground()
215 && let Some(cdom_gd) = cdom.as_ground()
216 {
217 return Moo::new(Domain::Ground(Moo::new(GroundDomain::Function(
218 attrs_gd,
219 Moo::new(dom_gd.clone()),
220 Moo::new(cdom_gd.clone()),
221 ))));
222 }
223
224 Moo::new(Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
225 attrs.into(),
226 dom,
227 cdom,
228 ))))
229 }
230
231 pub fn resolve(&self) -> Option<Moo<GroundDomain>> {
236 match self {
237 Domain::Ground(gd) => Some(gd.clone()),
238 Domain::Unresolved(ud) => ud.resolve().map(Moo::new),
239 }
240 }
241
242 pub fn as_ground(&self) -> Option<&GroundDomain> {
246 match self {
247 Domain::Ground(gd) => Some(gd.as_ref()),
248 _ => None,
249 }
250 }
251
252 pub fn as_ground_mut(&mut self) -> Option<&mut GroundDomain> {
255 match self {
256 Domain::Ground(gd) => Some(Moo::<GroundDomain>::make_mut(gd)),
257 _ => None,
258 }
259 }
260
261 pub fn as_unresolved(&self) -> Option<&UnresolvedDomain> {
263 match self {
264 Domain::Unresolved(ud) => Some(ud.as_ref()),
265 _ => None,
266 }
267 }
268
269 pub fn as_unresolved_mut(&mut self) -> Option<&mut UnresolvedDomain> {
271 match self {
272 Domain::Unresolved(ud) => Some(Moo::<UnresolvedDomain>::make_mut(ud)),
273 _ => None,
274 }
275 }
276
277 pub fn as_dom_empty(&self) -> Option<&ReturnType> {
279 if let Some(GroundDomain::Empty(ty)) = self.as_ground() {
280 return Some(ty);
281 }
282 None
283 }
284
285 pub fn as_dom_empty_mut(&mut self) -> Option<&mut ReturnType> {
287 if let Some(GroundDomain::Empty(ty)) = self.as_ground_mut() {
288 return Some(ty);
289 }
290 None
291 }
292
293 pub fn is_bool(&self) -> bool {
295 self.return_type() == ReturnType::Bool
296 }
297
298 pub fn is_int(&self) -> bool {
300 self.return_type() == ReturnType::Int
301 }
302
303 pub fn as_int(&self) -> Option<Vec<Range<IntVal>>> {
306 if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
307 return Some(rngs.iter().cloned().map(|r| r.into()).collect());
308 }
309 if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved() {
310 return Some(rngs.clone());
311 }
312 None
313 }
314
315 pub fn as_int_mut(&mut self) -> Option<&mut Vec<Range<IntVal>>> {
318 if let Some(GroundDomain::Int(rngs_gds)) = self.as_ground() {
324 let rngs: Vec<Range<IntVal>> = rngs_gds.iter().cloned().map(|r| r.into()).collect();
325 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Int(rngs)))
326 }
327
328 if let Some(UnresolvedDomain::Int(rngs)) = self.as_unresolved_mut() {
329 return Some(rngs);
330 }
331 None
332 }
333
334 pub fn as_int_ground(&self) -> Option<&Vec<Range<Int>>> {
336 if let Some(GroundDomain::Int(rngs)) = self.as_ground() {
337 return Some(rngs);
338 }
339 None
340 }
341
342 pub fn as_int_ground_mut(&mut self) -> Option<&mut Vec<Range<Int>>> {
344 if let Some(GroundDomain::Int(rngs)) = self.as_ground_mut() {
345 return Some(rngs);
346 }
347 None
348 }
349
350 pub fn as_matrix(&self) -> Option<(DomainPtr, Vec<DomainPtr>)> {
353 if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
354 let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
355 let inner_dom: DomainPtr = inner_dom_gd.clone().into();
356 return Some((inner_dom, idx_doms));
357 }
358 if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved() {
359 return Some((inner_dom.clone(), idx_doms.clone()));
360 }
361 None
362 }
363
364 pub fn as_matrix_mut(&mut self) -> Option<(&mut DomainPtr, &mut Vec<DomainPtr>)> {
368 if let Some(GroundDomain::Matrix(inner_dom_gd, idx_doms_gds)) = self.as_ground() {
371 let inner_dom: DomainPtr = inner_dom_gd.clone().into();
372 let idx_doms: Vec<DomainPtr> = idx_doms_gds.iter().cloned().map(|d| d.into()).collect();
373 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Matrix(inner_dom, idx_doms)));
374 }
375
376 if let Some(UnresolvedDomain::Matrix(inner_dom, idx_doms)) = self.as_unresolved_mut() {
377 return Some((inner_dom, idx_doms));
378 }
379 None
380 }
381
382 pub fn as_matrix_ground(&self) -> Option<(&Moo<GroundDomain>, &Vec<Moo<GroundDomain>>)> {
384 if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground() {
385 return Some((inner_dom, idx_doms));
386 }
387 None
388 }
389
390 pub fn as_matrix_ground_mut(
392 &mut self,
393 ) -> Option<(&mut Moo<GroundDomain>, &mut Vec<Moo<GroundDomain>>)> {
394 if let Some(GroundDomain::Matrix(inner_dom, idx_doms)) = self.as_ground_mut() {
395 return Some((inner_dom, idx_doms));
396 }
397 None
398 }
399
400 pub fn as_set(&self) -> Option<(SetAttr<IntVal>, DomainPtr)> {
402 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
403 return Some((attr.clone().into(), inner_dom.clone().into()));
404 }
405 if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved() {
406 return Some((attr.clone(), inner_dom.clone()));
407 }
408 None
409 }
410
411 pub fn as_set_mut(&mut self) -> Option<(&mut SetAttr<IntVal>, &mut DomainPtr)> {
414 if let Some(GroundDomain::Set(attr_gd, inner_dom_gd)) = self.as_ground() {
415 let attr: SetAttr<IntVal> = attr_gd.clone().into();
416 let inner_dom = inner_dom_gd.clone().into();
417 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Set(attr, inner_dom)));
418 }
419
420 if let Some(UnresolvedDomain::Set(attr, inner_dom)) = self.as_unresolved_mut() {
421 return Some((attr, inner_dom));
422 }
423 None
424 }
425
426 pub fn as_set_ground(&self) -> Option<(&SetAttr<Int>, &Moo<GroundDomain>)> {
428 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground() {
429 return Some((attr, inner_dom));
430 }
431 None
432 }
433
434 pub fn as_set_ground_mut(&mut self) -> Option<(&mut SetAttr<Int>, &mut Moo<GroundDomain>)> {
436 if let Some(GroundDomain::Set(attr, inner_dom)) = self.as_ground_mut() {
437 return Some((attr, inner_dom));
438 }
439 None
440 }
441
442 pub fn as_tuple(&self) -> Option<Vec<DomainPtr>> {
444 if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
445 return Some(inner_doms.iter().cloned().map(|d| d.into()).collect());
446 }
447 if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved() {
448 return Some(inner_doms.clone());
449 }
450 None
451 }
452
453 pub fn as_tuple_mut(&mut self) -> Option<&mut Vec<DomainPtr>> {
456 if let Some(GroundDomain::Tuple(inner_doms_gds)) = self.as_ground() {
457 let inner_doms: Vec<DomainPtr> =
458 inner_doms_gds.iter().cloned().map(|d| d.into()).collect();
459 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Tuple(inner_doms)));
460 }
461
462 if let Some(UnresolvedDomain::Tuple(inner_doms)) = self.as_unresolved_mut() {
463 return Some(inner_doms);
464 }
465 None
466 }
467
468 pub fn as_tuple_ground(&self) -> Option<&Vec<Moo<GroundDomain>>> {
470 if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground() {
471 return Some(inner_doms);
472 }
473 None
474 }
475
476 pub fn as_tuple_ground_mut(&mut self) -> Option<&mut Vec<Moo<GroundDomain>>> {
478 if let Some(GroundDomain::Tuple(inner_doms)) = self.as_ground_mut() {
479 return Some(inner_doms);
480 }
481 None
482 }
483
484 pub fn as_record(&self) -> Option<Vec<RecordEntry>> {
486 if let Some(GroundDomain::Record(record_entries)) = self.as_ground() {
487 return Some(record_entries.iter().cloned().map(|r| r.into()).collect());
488 }
489 if let Some(UnresolvedDomain::Record(record_entries)) = self.as_unresolved() {
490 return Some(record_entries.clone());
491 }
492 None
493 }
494
495 pub fn as_record_ground(&self) -> Option<&Vec<RecordEntryGround>> {
497 if let Some(GroundDomain::Record(entries)) = self.as_ground() {
498 return Some(entries);
499 }
500 None
501 }
502
503 pub fn as_record_mut(&mut self) -> Option<&mut Vec<RecordEntry>> {
506 if let Some(GroundDomain::Record(entries_gds)) = self.as_ground() {
507 let entries: Vec<RecordEntry> = entries_gds.iter().cloned().map(|r| r.into()).collect();
508 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Record(entries)));
509 }
510
511 if let Some(UnresolvedDomain::Record(entries_gds)) = self.as_unresolved_mut() {
512 return Some(entries_gds);
513 }
514 None
515 }
516
517 pub fn as_record_ground_mut(&mut self) -> Option<&mut Vec<RecordEntryGround>> {
519 if let Some(GroundDomain::Record(entries)) = self.as_ground_mut() {
520 return Some(entries);
521 }
522 None
523 }
524
525 pub fn as_function(&self) -> Option<(FuncAttr<IntVal>, Moo<Domain>, Moo<Domain>)> {
527 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
528 return Some((
529 attrs.clone().into(),
530 dom.clone().into(),
531 codom.clone().into(),
532 ));
533 }
534 if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved() {
535 return Some((attrs.clone(), dom.clone(), codom.clone()));
536 }
537 None
538 }
539
540 pub fn as_function_mut(
544 &mut self,
545 ) -> Option<(&mut FuncAttr<IntVal>, &mut Moo<Domain>, &mut Moo<Domain>)> {
546 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
547 *self = Domain::Unresolved(Moo::new(UnresolvedDomain::Function(
548 attrs.clone().into(),
549 dom.clone().into(),
550 codom.clone().into(),
551 )));
552 }
553
554 if let Some(UnresolvedDomain::Function(attrs, dom, codom)) = self.as_unresolved_mut() {
555 return Some((attrs, dom, codom));
556 }
557 None
558 }
559
560 pub fn as_function_ground(
562 &self,
563 ) -> Option<(&FuncAttr, &Moo<GroundDomain>, &Moo<GroundDomain>)> {
564 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground() {
565 return Some((attrs, dom, codom));
566 }
567 None
568 }
569
570 pub fn as_function_ground_mut(
572 &mut self,
573 ) -> Option<(
574 &mut FuncAttr,
575 &mut Moo<GroundDomain>,
576 &mut Moo<GroundDomain>,
577 )> {
578 if let Some(GroundDomain::Function(attrs, dom, codom)) = self.as_ground_mut() {
579 return Some((attrs, dom, codom));
580 }
581 None
582 }
583
584 pub fn union(&self, other: &Domain) -> Result<Domain, DomainOpError> {
586 match (self, other) {
587 (Domain::Ground(a), Domain::Ground(b)) => Ok(Domain::Ground(Moo::new(a.union(b)?))),
588 (Domain::Unresolved(a), Domain::Unresolved(b)) => {
589 Ok(Domain::Unresolved(Moo::new(a.union_unresolved(b)?)))
590 }
591 (Domain::Unresolved(u), Domain::Ground(g))
592 | (Domain::Ground(g), Domain::Unresolved(u)) => {
593 todo!("Union of unresolved domain {u} and ground domain {g} is not yet implemented")
594 }
595 }
596 }
597
598 pub fn intersect(&self, other: &Domain) -> Result<Domain, DomainOpError> {
600 match (self, other) {
601 (Domain::Ground(a), Domain::Ground(b)) => {
602 a.intersect(b).map(|res| Domain::Ground(Moo::new(res)))
603 }
604 _ => Err(DomainOpError::NotGround),
605 }
606 }
607
608 pub fn values(&self) -> Result<impl Iterator<Item = Literal>, DomainOpError> {
610 if let Some(gd) = self.as_ground() {
611 return gd.values();
612 }
613 Err(DomainOpError::NotGround)
614 }
615
616 pub fn length(&self) -> Result<u64, DomainOpError> {
618 if let Some(gd) = self.as_ground() {
619 return gd.length();
620 }
621 Err(DomainOpError::NotGround)
622 }
623
624 pub fn from_literal_vec(vals: &[Literal]) -> Result<DomainPtr, DomainOpError> {
626 GroundDomain::from_literal_vec(vals).map(DomainPtr::from)
627 }
628
629 pub fn contains(&self, lit: &Literal) -> Result<bool, DomainOpError> {
631 if let Some(gd) = self.as_ground() {
632 return gd.contains(lit);
633 }
634 Err(DomainOpError::NotGround)
635 }
636
637 pub fn element_domain(&self) -> Option<DomainPtr> {
638 match self {
639 Domain::Ground(gd) => gd.element_domain().map(DomainPtr::from),
640 Domain::Unresolved(ud) => ud.element_domain(),
641 }
642 }
643}
644
645impl Typeable for Domain {
646 fn return_type(&self) -> ReturnType {
647 match self {
648 Domain::Ground(dom) => dom.return_type(),
649 Domain::Unresolved(dom) => dom.return_type(),
650 }
651 }
652}
653
654impl Display for Domain {
655 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
656 match &self {
657 Domain::Ground(gd) => gd.fmt(f),
658 Domain::Unresolved(ud) => ud.fmt(f),
659 }
660 }
661}
662
663fn as_grounds(doms: &[DomainPtr]) -> Option<Vec<Moo<GroundDomain>>> {
664 doms.iter()
665 .map(|idx| match idx.as_ref() {
666 Domain::Ground(idx_gd) => Some(idx_gd.clone()),
667 _ => None,
668 })
669 .collect()
670}
671
672#[cfg(test)]
673mod tests {
674 use super::*;
675 use crate::ast::Name;
676 use crate::{domain_int, range};
677
678 #[test]
679 fn test_negative_product() {
680 let d1 = Domain::int(vec![Range::Bounded(-2, 1)]);
681 let d2 = Domain::int(vec![Range::Bounded(-2, 1)]);
682 let res = d1
683 .as_ground()
684 .unwrap()
685 .apply_i32(|a, b| Some(a * b), d2.as_ground().unwrap())
686 .unwrap();
687
688 assert!(matches!(res, GroundDomain::Int(_)));
689 if let GroundDomain::Int(ranges) = res {
690 assert!(!ranges.contains(&Range::Bounded(-4, 4)));
691 }
692 }
693
694 #[test]
695 fn test_negative_div() {
696 let d1 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
697 let d2 = GroundDomain::Int(vec![Range::Bounded(-2, 1)]);
698 let res = d1
699 .apply_i32(|a, b| if b != 0 { Some(a / b) } else { None }, &d2)
700 .unwrap();
701
702 assert!(matches!(res, GroundDomain::Int(_)));
703 if let GroundDomain::Int(ranges) = res {
704 assert!(!ranges.contains(&Range::Bounded(-4, 4)));
705 }
706 }
707
708 #[test]
709 fn test_length_basic() {
710 assert_eq!(Domain::empty(ReturnType::Int).length(), Ok(0));
711 assert_eq!(Domain::bool().length(), Ok(2));
712 assert_eq!(domain_int!(1..3, 5, 7..9).length(), Ok(7));
713 assert_eq!(
714 domain_int!(1..2, 5..).length(),
715 Err(DomainOpError::Unbounded)
716 );
717 }
718 #[test]
719 fn test_length_set_basic() {
720 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..3));
722 assert_eq!(s.length(), Ok(8));
723
724 let s = Domain::set(SetAttr::new_size(2), domain_int!(1..3));
726 assert_eq!(s.length(), Ok(3));
727
728 let s = Domain::set(SetAttr::new_min_max_size(1, 2), domain_int!(1..3));
730 assert_eq!(s.length(), Ok(6));
731
732 let s = Domain::set(SetAttr::new_min_size(1), domain_int!(1..3));
734 assert_eq!(s.length(), Ok(7));
735
736 let s = Domain::set(SetAttr::new_max_size(2), domain_int!(1..3));
738 assert_eq!(s.length(), Ok(7));
739 }
740
741 #[test]
742 fn test_length_set_nested() {
743 let s2 = Domain::set(
750 SetAttr::new_max_size(2),
751 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
753 );
754 assert_eq!(s2.length(), Ok(11));
755 }
756
757 #[test]
758 fn test_length_set_unbounded_inner() {
759 let s2_bad = Domain::set(
761 SetAttr::new_max_size(2),
762 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..)),
763 );
764 assert_eq!(s2_bad.length(), Err(DomainOpError::Unbounded));
765 }
766
767 #[test]
768 fn test_length_set_overflow() {
769 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..20));
770 assert!(s.length().is_ok());
771
772 let s = Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..63));
774 assert_eq!(s.length(), Err(DomainOpError::TooLarge));
775 }
776
777 #[test]
778 fn test_length_tuple() {
779 let t = Domain::tuple(vec![domain_int!(1..3), Domain::bool()]);
781 assert_eq!(t.length(), Ok(6));
782 }
783
784 #[test]
785 fn test_length_record() {
786 let t = Domain::record(vec![
788 RecordEntry {
789 name: Name::user("a"),
790 domain: domain_int!(1..3),
791 },
792 RecordEntry {
793 name: Name::user("b"),
794 domain: Domain::bool(),
795 },
796 ]);
797 assert_eq!(t.length(), Ok(6));
798 }
799
800 #[test]
801 fn test_length_matrix_basic() {
802 let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..3)]);
804 assert_eq!(m.length(), Ok(8));
805
806 let m = Domain::matrix(domain_int!(1..3), vec![domain_int!(1..2)]);
808 assert_eq!(m.length(), Ok(9));
809 }
810
811 #[test]
812 fn test_length_matrix_2d() {
813 let m = Domain::matrix(Domain::bool(), vec![domain_int!(1..2), domain_int!(1..3)]);
815 assert_eq!(m.length(), Ok(64));
816 }
817
818 #[test]
819 fn test_length_matrix_of_sets() {
820 let m = Domain::matrix(
822 Domain::set(SetAttr::<IntVal>::default(), domain_int!(1..2)),
823 vec![domain_int!(1..3)],
824 );
825 assert_eq!(m.length(), Ok(64));
826 }
827}