1use std::collections::HashMap;
47use std::hash::Hash;
48
49use serde::Deserialize;
50use serde::Serialize;
51
52use super::BoundedJoinSemilattice;
53use super::JoinSemilattice;
54
55#[derive(
72 Clone,
73 Copy,
74 Debug,
75 PartialEq,
76 Eq,
77 PartialOrd,
78 Ord,
79 Hash,
80 Serialize,
81 Deserialize,
82 typeuri::Named
83)]
84pub struct Max<T>(pub T);
85
86impl<T: Ord + Clone> JoinSemilattice for Max<T> {
87 fn join(&self, other: &Self) -> Self {
88 if self.0 >= other.0 {
89 self.clone()
90 } else {
91 other.clone()
92 }
93 }
94}
95
96impl<T: Ord + Clone + num_traits::Bounded> BoundedJoinSemilattice for Max<T> {
97 fn bottom() -> Self {
98 Max(num_traits::Bounded::min_value())
99 }
100}
101
102impl<T> From<T> for Max<T> {
103 fn from(value: T) -> Self {
104 Max(value)
105 }
106}
107
108impl<T: Ord + Clone + num_traits::Bounded> Default for Max<T> {
109 fn default() -> Self {
110 Self::bottom()
111 }
112}
113
114impl<T> Max<T> {
115 pub fn get(&self) -> &T {
117 &self.0
118 }
119}
120
121#[derive(
138 Clone,
139 Copy,
140 Debug,
141 PartialEq,
142 Eq,
143 PartialOrd,
144 Ord,
145 Hash,
146 Serialize,
147 Deserialize,
148 typeuri::Named
149)]
150pub struct Min<T>(pub T);
151
152impl<T: Ord + Clone> JoinSemilattice for Min<T> {
153 fn join(&self, other: &Self) -> Self {
154 if self.0 <= other.0 {
155 self.clone()
156 } else {
157 other.clone()
158 }
159 }
160}
161
162impl<T: Ord + Clone + num_traits::Bounded> BoundedJoinSemilattice for Min<T> {
163 fn bottom() -> Self {
164 Min(num_traits::Bounded::max_value())
165 }
166}
167
168impl<T> From<T> for Min<T> {
169 fn from(value: T) -> Self {
170 Min(value)
171 }
172}
173
174impl<T: Ord + Clone + num_traits::Bounded> Default for Min<T> {
175 fn default() -> Self {
176 Self::bottom()
177 }
178}
179
180impl<T> Min<T> {
181 pub fn get(&self) -> &T {
183 &self.0
184 }
185}
186
187#[derive(
204 Clone,
205 Copy,
206 Debug,
207 PartialEq,
208 Eq,
209 PartialOrd,
210 Ord,
211 Hash,
212 Serialize,
213 Deserialize,
214 typeuri::Named
215)]
216pub struct Any(pub bool);
217
218impl JoinSemilattice for Any {
219 fn join(&self, other: &Self) -> Self {
220 Any(self.0 || other.0)
221 }
222}
223
224impl BoundedJoinSemilattice for Any {
225 fn bottom() -> Self {
226 Any(false)
227 }
228}
229
230impl From<bool> for Any {
231 fn from(value: bool) -> Self {
232 Any(value)
233 }
234}
235
236#[derive(
264 Clone,
265 Copy,
266 Debug,
267 PartialEq,
268 Eq,
269 Hash,
270 Serialize,
271 Deserialize,
272 typeuri::Named
273)]
274pub struct All(pub bool);
275
276impl JoinSemilattice for All {
277 fn join(&self, other: &Self) -> Self {
278 All(self.0 && other.0)
279 }
280}
281
282impl BoundedJoinSemilattice for All {
283 fn bottom() -> Self {
284 All(true)
285 }
286}
287
288impl From<bool> for All {
289 fn from(value: bool) -> Self {
290 All(value)
291 }
292}
293
294#[derive(Clone, Debug, Serialize, Deserialize)]
389#[serde(bound(
390 serialize = "K: Eq + Hash + Serialize, V: Serialize",
391 deserialize = "K: Eq + Hash + Deserialize<'de>, V: Deserialize<'de>"
392))]
393pub struct LatticeMap<K, V> {
394 inner: HashMap<K, V>,
395}
396
397impl<K, V> PartialEq for LatticeMap<K, V>
401where
402 K: Eq + Hash,
403 V: PartialEq,
404{
405 fn eq(&self, other: &Self) -> bool {
406 self.inner == other.inner
407 }
408}
409
410impl<K, V> Eq for LatticeMap<K, V>
411where
412 K: Eq + Hash,
413 V: Eq,
414{
415}
416
417impl<K, V> LatticeMap<K, V>
418where
419 K: Eq + Hash,
420{
421 pub fn new() -> Self {
423 Self {
424 inner: HashMap::new(),
425 }
426 }
427
428 pub fn insert(&mut self, k: K, v: V) {
430 self.inner.insert(k, v);
431 }
432
433 pub fn get(&self, k: &K) -> Option<&V> {
435 self.inner.get(k)
436 }
437
438 pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
440 self.inner.iter()
441 }
442
443 pub fn as_inner(&self) -> &HashMap<K, V> {
445 &self.inner
446 }
447
448 pub fn into_inner(self) -> HashMap<K, V> {
450 self.inner
451 }
452
453 pub fn len(&self) -> usize {
455 self.inner.len()
456 }
457
458 pub fn is_empty(&self) -> bool {
460 self.inner.is_empty()
461 }
462}
463
464impl<K, V> Default for LatticeMap<K, V>
465where
466 K: Eq + Hash,
467{
468 fn default() -> Self {
469 Self::new()
470 }
471}
472
473impl<K, V> JoinSemilattice for LatticeMap<K, V>
474where
475 K: Eq + Hash + Clone,
476 V: JoinSemilattice + Clone,
477{
478 fn join(&self, other: &Self) -> Self {
479 let mut out = self.inner.clone();
480
481 for (k, v_other) in &other.inner {
482 out.entry(k.clone())
483 .and_modify(|v_here| {
484 *v_here = v_here.join(v_other);
485 })
486 .or_insert_with(|| v_other.clone());
487 }
488
489 LatticeMap { inner: out }
490 }
491}
492
493impl<K, V> BoundedJoinSemilattice for LatticeMap<K, V>
494where
495 K: Eq + Hash + Clone,
496 V: BoundedJoinSemilattice + Clone,
497{
498 fn bottom() -> Self {
499 LatticeMap {
500 inner: HashMap::new(),
501 }
502 }
503}
504
505use std::collections::HashSet;
506
507impl<T: Eq + Hash + Clone> JoinSemilattice for HashSet<T> {
517 fn join(&self, other: &Self) -> Self {
518 self.union(other).cloned().collect()
519 }
520}
521
522impl<T: Eq + Hash + Clone> BoundedJoinSemilattice for HashSet<T> {
523 fn bottom() -> Self {
524 HashSet::new()
525 }
526}
527
528use std::collections::BTreeSet;
529
530impl<T: Ord + Clone> JoinSemilattice for BTreeSet<T> {
534 fn join(&self, other: &Self) -> Self {
535 self.union(other).cloned().collect()
536 }
537}
538
539impl<T: Ord + Clone> BoundedJoinSemilattice for BTreeSet<T> {
540 fn bottom() -> Self {
541 BTreeSet::new()
542 }
543}
544
545impl<L: JoinSemilattice + Clone> JoinSemilattice for Option<L> {
555 fn join(&self, other: &Self) -> Self {
556 match (self, other) {
557 (None, x) | (x, None) => x.clone(),
558 (Some(a), Some(b)) => Some(a.join(b)),
559 }
560 }
561}
562
563impl<L: JoinSemilattice + Clone> BoundedJoinSemilattice for Option<L> {
564 fn bottom() -> Self {
565 None
566 }
567}
568
569impl JoinSemilattice for () {
573 fn join(&self, _other: &Self) -> Self {}
574}
575
576impl BoundedJoinSemilattice for () {
577 fn bottom() -> Self {}
578}
579
580#[cfg(test)]
583mod tests {
584 use super::*;
585
586 #[test]
589 fn max_join_is_maximum() {
590 let a = Max(5);
591 let b = Max(10);
592 assert_eq!(a.join(&b), Max(10));
593 assert_eq!(b.join(&a), Max(10));
594 }
595
596 #[test]
597 fn max_bottom_is_min_value() {
598 assert_eq!(Max::<i32>::bottom(), Max(i32::MIN));
599 assert_eq!(Max::<u64>::bottom(), Max(u64::MIN));
600 }
601
602 #[test]
603 fn max_is_idempotent() {
604 let x = Max(42);
605 assert_eq!(x.join(&x), x);
606 }
607
608 #[test]
609 fn max_is_commutative() {
610 let a = Max(3);
611 let b = Max(7);
612 assert_eq!(a.join(&b), b.join(&a));
613 }
614
615 #[test]
616 fn max_is_associative() {
617 let a = Max(1);
618 let b = Max(5);
619 let c = Max(3);
620 assert_eq!(a.join(&b).join(&c), a.join(&b.join(&c)));
621 }
622
623 #[test]
624 fn max_bottom_is_identity() {
625 let x = Max(100);
626 assert_eq!(Max::bottom().join(&x), x);
627 assert_eq!(x.join(&Max::bottom()), x);
628 }
629
630 #[test]
633 fn min_join_is_minimum() {
634 let a = Min(5);
635 let b = Min(10);
636 assert_eq!(a.join(&b), Min(5));
637 assert_eq!(b.join(&a), Min(5));
638 }
639
640 #[test]
641 fn min_bottom_is_max_value() {
642 assert_eq!(Min::<i32>::bottom(), Min(i32::MAX));
643 assert_eq!(Min::<u64>::bottom(), Min(u64::MAX));
644 }
645
646 #[test]
647 fn min_is_idempotent() {
648 let x = Min(42);
649 assert_eq!(x.join(&x), x);
650 }
651
652 #[test]
653 fn min_is_commutative() {
654 let a = Min(3);
655 let b = Min(7);
656 assert_eq!(a.join(&b), b.join(&a));
657 }
658
659 #[test]
660 fn min_is_associative() {
661 let a = Min(1);
662 let b = Min(5);
663 let c = Min(3);
664 assert_eq!(a.join(&b).join(&c), a.join(&b.join(&c)));
665 }
666
667 #[test]
668 fn min_bottom_is_identity() {
669 let x = Min(100);
670 assert_eq!(Min::bottom().join(&x), x);
671 assert_eq!(x.join(&Min::bottom()), x);
672 }
673
674 #[test]
677 fn any_join_is_or() {
678 assert_eq!(Any(false).join(&Any(false)), Any(false));
679 assert_eq!(Any(false).join(&Any(true)), Any(true));
680 assert_eq!(Any(true).join(&Any(false)), Any(true));
681 assert_eq!(Any(true).join(&Any(true)), Any(true));
682 }
683
684 #[test]
685 fn any_bottom_is_false() {
686 assert_eq!(Any::bottom(), Any(false));
687 assert_eq!(Any(false).join(&Any(true)), Any(true));
688 assert_eq!(Any(true).join(&Any(false)), Any(true));
689 }
690
691 #[test]
692 fn any_is_idempotent() {
693 assert_eq!(Any(false).join(&Any(false)), Any(false));
694 assert_eq!(Any(true).join(&Any(true)), Any(true));
695 }
696
697 #[test]
700 fn all_join_is_and() {
701 assert_eq!(All(false).join(&All(false)), All(false));
702 assert_eq!(All(false).join(&All(true)), All(false));
703 assert_eq!(All(true).join(&All(false)), All(false));
704 assert_eq!(All(true).join(&All(true)), All(true));
705 }
706
707 #[test]
708 fn all_bottom_is_true() {
709 assert_eq!(All::bottom(), All(true));
710 assert_eq!(All(true).join(&All(false)), All(false));
711 assert_eq!(All(false).join(&All(true)), All(false));
712 }
713
714 #[test]
715 fn all_is_idempotent() {
716 assert_eq!(All(false).join(&All(false)), All(false));
717 assert_eq!(All(true).join(&All(true)), All(true));
718 }
719
720 #[test]
723 fn max_from_value() {
724 let x: Max<i32> = 42.into();
725 assert_eq!(x, Max(42));
726 assert_eq!(Max::from(100u64), Max(100u64));
727 }
728
729 #[test]
730 fn min_from_value() {
731 let x: Min<i32> = 42.into();
732 assert_eq!(x, Min(42));
733 assert_eq!(Min::from(100u64), Min(100u64));
734 }
735
736 #[test]
737 fn any_from_bool() {
738 let t: Any = true.into();
739 let f: Any = false.into();
740 assert_eq!(t, Any(true));
741 assert_eq!(f, Any(false));
742 }
743
744 #[test]
745 fn all_from_bool() {
746 let t: All = true.into();
747 let f: All = false.into();
748 assert_eq!(t, All(true));
749 assert_eq!(f, All(false));
750 }
751
752 #[test]
755 fn max_default_is_bottom() {
756 assert_eq!(Max::<i32>::default(), Max::<i32>::bottom());
757 assert_eq!(Max::<u64>::default(), Max(u64::MIN));
758 }
759
760 #[test]
761 fn min_default_is_bottom() {
762 assert_eq!(Min::<i32>::default(), Min::<i32>::bottom());
763 assert_eq!(Min::<u64>::default(), Min(u64::MAX));
764 }
765
766 #[test]
769 fn max_serde_roundtrip() {
770 let original = Max(42i64);
771 let encoded = bincode::serde::encode_to_vec(original, bincode::config::legacy()).unwrap();
772 let decoded: Max<i64> =
773 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
774 .map(|(v, _)| v)
775 .unwrap();
776 assert_eq!(original, decoded);
777
778 let bottom = Max::<i64>::bottom();
780 let encoded = bincode::serde::encode_to_vec(bottom, bincode::config::legacy()).unwrap();
781 let decoded: Max<i64> =
782 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
783 .map(|(v, _)| v)
784 .unwrap();
785 assert_eq!(bottom, decoded);
786 }
787
788 #[test]
789 fn min_serde_roundtrip() {
790 let original = Min(42i64);
791 let encoded = bincode::serde::encode_to_vec(original, bincode::config::legacy()).unwrap();
792 let decoded: Min<i64> =
793 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
794 .map(|(v, _)| v)
795 .unwrap();
796 assert_eq!(original, decoded);
797
798 let bottom = Min::<i64>::bottom();
800 let encoded = bincode::serde::encode_to_vec(bottom, bincode::config::legacy()).unwrap();
801 let decoded: Min<i64> =
802 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
803 .map(|(v, _)| v)
804 .unwrap();
805 assert_eq!(bottom, decoded);
806 }
807
808 #[test]
809 fn any_serde_roundtrip() {
810 for value in [true, false] {
811 let original = Any(value);
812 let encoded =
813 bincode::serde::encode_to_vec(original, bincode::config::legacy()).unwrap();
814 let decoded: Any =
815 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
816 .map(|(v, _)| v)
817 .unwrap();
818 assert_eq!(original, decoded);
819 }
820
821 let bottom = Any::bottom();
823 let encoded = bincode::serde::encode_to_vec(bottom, bincode::config::legacy()).unwrap();
824 let decoded: Any = bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
825 .map(|(v, _)| v)
826 .unwrap();
827 assert_eq!(bottom, decoded);
828 }
829
830 #[test]
831 fn all_serde_roundtrip() {
832 for value in [true, false] {
833 let original = All(value);
834 let encoded =
835 bincode::serde::encode_to_vec(original, bincode::config::legacy()).unwrap();
836 let decoded: All =
837 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
838 .map(|(v, _)| v)
839 .unwrap();
840 assert_eq!(original, decoded);
841 }
842
843 let bottom = All::bottom();
845 let encoded = bincode::serde::encode_to_vec(bottom, bincode::config::legacy()).unwrap();
846 let decoded: All = bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
847 .map(|(v, _)| v)
848 .unwrap();
849 assert_eq!(bottom, decoded);
850 }
851
852 #[test]
855 fn lattice_map_new_is_empty() {
856 let m: LatticeMap<i32, Max<i32>> = LatticeMap::new();
857 assert!(m.is_empty());
858 assert_eq!(m.len(), 0);
859 }
860
861 #[test]
862 fn lattice_map_bottom_is_empty() {
863 let m: LatticeMap<i32, Max<i32>> = BoundedJoinSemilattice::bottom();
864 assert!(m.is_empty());
865 assert_eq!(m.len(), 0);
866 }
867
868 #[test]
869 fn lattice_map_insert_and_get() {
870 let mut m: LatticeMap<&str, Max<i32>> = LatticeMap::new();
871 m.insert("foo", Max(42));
872 assert_eq!(m.get(&"foo"), Some(&Max(42)));
873 assert_eq!(m.get(&"bar"), None);
874 assert_eq!(m.len(), 1);
875 assert!(!m.is_empty());
876 }
877
878 #[test]
879 fn lattice_map_join_is_pointwise() {
880 let mut m1: LatticeMap<&str, Max<i32>> = LatticeMap::new();
882 m1.insert("a", Max(1));
883 m1.insert("b", Max(10));
884
885 let mut m2: LatticeMap<&str, Max<i32>> = LatticeMap::new();
886 m2.insert("b", Max(7));
887 m2.insert("c", Max(3));
888
889 let j = m1.join(&m2);
890
891 assert_eq!(j.get(&"a"), Some(&Max(1)));
893 assert_eq!(j.get(&"b"), Some(&Max(10))); assert_eq!(j.get(&"c"), Some(&Max(3)));
895 }
896
897 #[test]
898 fn lattice_map_join_is_commutative() {
899 let mut m1: LatticeMap<u32, Min<i64>> = LatticeMap::new();
900 m1.insert(0, Min(10));
901
902 let mut m2: LatticeMap<u32, Min<i64>> = LatticeMap::new();
903 m2.insert(0, Min(20));
904
905 assert_eq!(m1.join(&m2), m2.join(&m1));
906 }
907
908 #[test]
909 fn lattice_map_join_is_idempotent() {
910 let mut m: LatticeMap<u32, Max<i64>> = LatticeMap::new();
911 m.insert(1, Max(100));
912 m.insert(2, Max(200));
913
914 assert_eq!(m.join(&m), m);
915 }
916
917 #[test]
918 fn lattice_map_watermark_example() {
919 let mut state1: LatticeMap<u32, Min<u64>> = LatticeMap::new();
921 state1.insert(0, Min(100)); state1.insert(1, Min(200)); let mut state2: LatticeMap<u32, Min<u64>> = LatticeMap::new();
925 state2.insert(0, Min(150)); state2.insert(2, Min(50)); let merged = state1.join(&state2);
930
931 assert_eq!(merged.get(&0), Some(&Min(100))); assert_eq!(merged.get(&1), Some(&Min(200))); assert_eq!(merged.get(&2), Some(&Min(50))); let watermark = merged.iter().map(|(_, v)| v.0).min().unwrap();
938 assert_eq!(watermark, 50);
939 }
940
941 #[test]
942 fn lattice_map_iter_works() {
943 let mut m: LatticeMap<&str, Max<i32>> = LatticeMap::new();
944 m.insert("a", Max(1));
945 m.insert("b", Max(2));
946
947 let items: HashMap<_, _> = m.iter().map(|(k, v)| (*k, v.0)).collect();
948 assert_eq!(items.get(&"a"), Some(&1));
949 assert_eq!(items.get(&"b"), Some(&2));
950 assert_eq!(items.len(), 2);
951 }
952
953 #[test]
954 fn lattice_map_serde_roundtrip() {
955 let mut original: LatticeMap<u32, Min<i64>> = LatticeMap::new();
956 original.insert(1, Min(10));
957 original.insert(2, Min(20));
958
959 let encoded = bincode::serde::encode_to_vec(&original, bincode::config::legacy()).unwrap();
960 let decoded: LatticeMap<u32, Min<i64>> =
961 bincode::serde::decode_from_slice(&encoded, bincode::config::legacy())
962 .map(|(v, _)| v)
963 .unwrap();
964
965 assert_eq!(original, decoded);
966 }
967
968 #[test]
971 fn hashset_join_is_union() {
972 let mut a = HashSet::new();
973 a.insert(1);
974 a.insert(2);
975
976 let mut b = HashSet::new();
977 b.insert(2);
978 b.insert(3);
979
980 let c = a.join(&b);
981 assert_eq!(c.len(), 3);
982 assert!(c.contains(&1));
983 assert!(c.contains(&2));
984 assert!(c.contains(&3));
985 }
986
987 #[test]
988 fn hashset_bottom_is_empty() {
989 let bottom: HashSet<i32> = HashSet::bottom();
990 assert!(bottom.is_empty());
991
992 let mut a = HashSet::new();
993 a.insert(42);
994
995 assert_eq!(bottom.join(&a), a);
996 assert_eq!(a.join(&bottom), a);
997 }
998
999 #[test]
1000 fn hashset_is_idempotent() {
1001 let mut a = HashSet::new();
1002 a.insert(1);
1003 a.insert(2);
1004
1005 assert_eq!(a.join(&a), a);
1006 }
1007
1008 #[test]
1009 fn hashset_is_commutative() {
1010 let mut a = HashSet::new();
1011 a.insert(1);
1012 a.insert(2);
1013
1014 let mut b = HashSet::new();
1015 b.insert(2);
1016 b.insert(3);
1017
1018 assert_eq!(a.join(&b), b.join(&a));
1019 }
1020
1021 #[test]
1022 fn hashset_is_associative() {
1023 let mut a = HashSet::new();
1024 a.insert(1);
1025
1026 let mut b = HashSet::new();
1027 b.insert(2);
1028
1029 let mut c = HashSet::new();
1030 c.insert(3);
1031
1032 assert_eq!(a.join(&b).join(&c), a.join(&b.join(&c)));
1033 }
1034
1035 #[test]
1036 fn hashset_semigroup_blanket_impl() {
1037 let mut a: HashSet<&str> = HashSet::new();
1040 a.insert("foo");
1041
1042 let mut b: HashSet<&str> = HashSet::new();
1043 b.insert("bar");
1044
1045 let c = a.join(&b);
1047 assert_eq!(c.len(), 2);
1048 assert!(c.contains(&"foo"));
1049 assert!(c.contains(&"bar"));
1050 }
1051
1052 #[test]
1053 fn hashset_monoid_blanket_impl() {
1054 let empty: HashSet<i32> = HashSet::bottom();
1057 assert!(empty.is_empty());
1058
1059 let mut a = HashSet::new();
1060 a.insert(42);
1061
1062 assert_eq!(empty.join(&a), a);
1064 assert_eq!(a.join(&empty), a);
1065 }
1066
1067 #[test]
1070 fn btreeset_join_is_union() {
1071 let a: BTreeSet<i32> = [1, 2].into_iter().collect();
1072 let b: BTreeSet<i32> = [2, 3].into_iter().collect();
1073
1074 let c = a.join(&b);
1075 assert_eq!(c.len(), 3);
1076 assert!(c.contains(&1));
1077 assert!(c.contains(&2));
1078 assert!(c.contains(&3));
1079 }
1080
1081 #[test]
1082 fn btreeset_bottom_is_empty() {
1083 let bottom: BTreeSet<i32> = BTreeSet::bottom();
1084 assert!(bottom.is_empty());
1085
1086 let a: BTreeSet<i32> = [42].into_iter().collect();
1087 assert_eq!(bottom.join(&a), a);
1088 assert_eq!(a.join(&bottom), a);
1089 }
1090
1091 #[test]
1092 fn btreeset_is_idempotent() {
1093 let a: BTreeSet<i32> = [1, 2].into_iter().collect();
1094 assert_eq!(a.join(&a), a);
1095 }
1096
1097 #[test]
1098 fn btreeset_is_commutative() {
1099 let a: BTreeSet<i32> = [1, 2].into_iter().collect();
1100 let b: BTreeSet<i32> = [2, 3].into_iter().collect();
1101 assert_eq!(a.join(&b), b.join(&a));
1102 }
1103
1104 #[test]
1107 fn option_join_lifts_inner() {
1108 let a: Option<Max<i32>> = Some(Max(5));
1109 let b: Option<Max<i32>> = Some(Max(10));
1110
1111 assert_eq!(a.join(&b), Some(Max(10)));
1112 }
1113
1114 #[test]
1115 fn option_join_with_none() {
1116 let a: Option<Max<i32>> = Some(Max(5));
1117 let none: Option<Max<i32>> = None;
1118
1119 assert_eq!(a.join(&none), a);
1121 assert_eq!(none.join(&a), a);
1122 assert_eq!(none.join(&none), None);
1123 }
1124
1125 #[test]
1126 fn option_bottom_is_none() {
1127 let bottom: Option<Max<i32>> = Option::bottom();
1128 assert_eq!(bottom, None);
1129 }
1130
1131 #[test]
1132 fn option_with_hashset() {
1133 let a: Option<HashSet<i32>> = Some([1, 2].into_iter().collect());
1134 let b: Option<HashSet<i32>> = Some([2, 3].into_iter().collect());
1135
1136 let c = a.join(&b);
1137 let expected: HashSet<i32> = [1, 2, 3].into_iter().collect();
1138 assert_eq!(c, Some(expected));
1139 }
1140
1141 #[test]
1142 fn option_is_idempotent() {
1143 let a: Option<Max<i32>> = Some(Max(5));
1144 assert_eq!(a.join(&a), a);
1145
1146 let none: Option<Max<i32>> = None;
1147 assert_eq!(none.join(&none), none);
1148 }
1149
1150 #[test]
1151 fn option_is_commutative() {
1152 let a: Option<Max<i32>> = Some(Max(5));
1153 let b: Option<Max<i32>> = Some(Max(10));
1154 assert_eq!(a.join(&b), b.join(&a));
1155 }
1156
1157 #[test]
1160 fn unit_join_is_trivial() {
1161 assert_eq!(().join(&()), ());
1162 }
1163
1164 #[test]
1165 fn unit_bottom_is_unit() {
1166 assert_eq!(<()>::bottom(), ());
1167 }
1168
1169 #[test]
1170 fn unit_is_idempotent() {
1171 assert_eq!(().join(&()), ());
1172 }
1173}