1pub trait Semigroup: Sized {
67 fn combine(self, other: Self) -> Self;
80}
81
82impl<T> Semigroup for Vec<T> {
84 #[inline]
85 fn combine(mut self, other: Self) -> Self {
86 self.extend(other);
87 self
88 }
89}
90
91impl Semigroup for String {
93 #[inline]
94 fn combine(mut self, other: Self) -> Self {
95 self.push_str(&other);
96 self
97 }
98}
99
100macro_rules! impl_semigroup_tuple {
102 ($($idx:tt $T:ident),+) => {
103 impl<$($T: Semigroup),+> Semigroup for ($($T,)+) {
104 #[inline]
105 fn combine(self, other: Self) -> Self {
106 (
107 $(self.$idx.combine(other.$idx)),+
108 )
109 }
110 }
111 };
112}
113
114impl_semigroup_tuple!(0 T1, 1 T2);
116impl_semigroup_tuple!(0 T1, 1 T2, 2 T3);
117impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4);
118impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5);
119impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6);
120impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7);
121impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8);
122impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9);
123impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10);
124impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10, 10 T11);
125impl_semigroup_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10, 10 T11, 11 T12);
126
127use std::collections::HashMap;
129use std::hash::Hash;
130
131impl<K, V> Semigroup for HashMap<K, V>
158where
159 K: Eq + Hash + Clone,
160 V: Semigroup + Clone,
161{
162 fn combine(mut self, other: Self) -> Self {
163 for (key, value) in other {
164 self.entry(key.clone())
165 .and_modify(|existing| {
166 *existing = existing.clone().combine(value.clone());
167 })
168 .or_insert(value);
169 }
170 self
171 }
172}
173
174use std::collections::HashSet;
176
177impl<T> Semigroup for HashSet<T>
192where
193 T: Eq + Hash,
194{
195 fn combine(mut self, other: Self) -> Self {
196 self.extend(other);
197 self
198 }
199}
200
201use std::collections::BTreeMap;
203
204impl<K, V> Semigroup for BTreeMap<K, V>
226where
227 K: Ord + Clone,
228 V: Semigroup + Clone,
229{
230 fn combine(mut self, other: Self) -> Self {
231 for (key, value) in other {
232 self.entry(key.clone())
233 .and_modify(|existing| {
234 *existing = existing.clone().combine(value.clone());
235 })
236 .or_insert(value);
237 }
238 self
239 }
240}
241
242use std::collections::BTreeSet;
244
245impl<T> Semigroup for BTreeSet<T>
262where
263 T: Ord,
264{
265 fn combine(mut self, other: Self) -> Self {
266 self.extend(other);
267 self
268 }
269}
270
271impl<T> Semigroup for Option<T>
294where
295 T: Semigroup,
296{
297 fn combine(self, other: Self) -> Self {
298 match (self, other) {
299 (Some(a), Some(b)) => Some(a.combine(b)),
300 (Some(a), None) => Some(a),
301 (None, Some(b)) => Some(b),
302 (None, None) => None,
303 }
304 }
305}
306
307#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
320pub struct First<T>(pub T);
321
322impl<T> Semigroup for First<T> {
323 fn combine(self, _other: Self) -> Self {
324 self }
326}
327
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
339pub struct Last<T>(pub T);
340
341impl<T> Semigroup for Last<T> {
342 fn combine(self, other: Self) -> Self {
343 other }
345}
346
347#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct Intersection<S>(pub S);
367
368impl<T> Semigroup for Intersection<HashSet<T>>
369where
370 T: Eq + Hash + Clone,
371{
372 fn combine(self, other: Self) -> Self {
373 Intersection(self.0.intersection(&other.0).cloned().collect())
374 }
375}
376
377impl<T> Semigroup for Intersection<BTreeSet<T>>
378where
379 T: Ord + Clone,
380{
381 fn combine(self, other: Self) -> Self {
382 Intersection(self.0.intersection(&other.0).cloned().collect())
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389
390 #[test]
392 fn test_vec_semigroup() {
393 let v1 = vec![1, 2, 3];
394 let v2 = vec![4, 5, 6];
395 assert_eq!(v1.combine(v2), vec![1, 2, 3, 4, 5, 6]);
396 }
397
398 #[test]
399 fn test_vec_semigroup_empty() {
400 let v1: Vec<i32> = vec![];
401 let v2 = vec![1, 2, 3];
402 assert_eq!(v1.combine(v2), vec![1, 2, 3]);
403 }
404
405 #[test]
406 fn test_string_semigroup() {
407 let s1 = "Hello, ".to_string();
408 let s2 = "World!".to_string();
409 assert_eq!(s1.combine(s2), "Hello, World!");
410 }
411
412 #[test]
413 fn test_string_semigroup_empty() {
414 let s1 = "".to_string();
415 let s2 = "Hello".to_string();
416 assert_eq!(s1.combine(s2), "Hello");
417 }
418
419 #[test]
420 fn test_tuple_2_semigroup() {
421 let t1 = (vec![1], "a".to_string());
422 let t2 = (vec![2], "b".to_string());
423 assert_eq!(t1.combine(t2), (vec![1, 2], "ab".to_string()));
424 }
425
426 #[test]
427 fn test_tuple_3_semigroup() {
428 let t1 = (vec![1], "a".to_string(), vec!["x".to_string()]);
429 let t2 = (vec![2], "b".to_string(), vec!["y".to_string()]);
430 assert_eq!(
431 t1.combine(t2),
432 (
433 vec![1, 2],
434 "ab".to_string(),
435 vec!["x".to_string(), "y".to_string()]
436 )
437 );
438 }
439
440 #[test]
442 fn test_vec_associativity() {
443 let a = vec![1, 2];
444 let b = vec![3, 4];
445 let c = vec![5, 6];
446
447 let left = a.clone().combine(b.clone()).combine(c.clone());
448 let right = a.combine(b.combine(c));
449
450 assert_eq!(left, right);
451 }
452
453 #[test]
454 fn test_string_associativity() {
455 let a = "hello".to_string();
456 let b = " ".to_string();
457 let c = "world".to_string();
458
459 let left = a.clone().combine(b.clone()).combine(c.clone());
460 let right = a.combine(b.combine(c));
461
462 assert_eq!(left, right);
463 }
464
465 #[test]
466 fn test_tuple_associativity() {
467 let a = (vec![1], "a".to_string());
468 let b = (vec![2], "b".to_string());
469 let c = (vec![3], "c".to_string());
470
471 let left = a.clone().combine(b.clone()).combine(c.clone());
472 let right = a.combine(b.combine(c));
473
474 assert_eq!(left, right);
475 }
476
477 #[test]
481 fn test_vec_multiple_combines() {
482 let result = vec![1].combine(vec![2]).combine(vec![3]).combine(vec![4]);
483 assert_eq!(result, vec![1, 2, 3, 4]);
484 }
485
486 #[test]
487 fn test_string_multiple_combines() {
488 let result = "a"
489 .to_string()
490 .combine("b".to_string())
491 .combine("c".to_string())
492 .combine("d".to_string());
493 assert_eq!(result, "abcd");
494 }
495
496 #[test]
498 fn test_large_tuple() {
499 let t1 = (vec![1], "a".to_string(), vec![2], "b".to_string(), vec![3]);
500 let t2 = (vec![4], "c".to_string(), vec![5], "d".to_string(), vec![6]);
501 assert_eq!(
502 t1.combine(t2),
503 (
504 vec![1, 4],
505 "ac".to_string(),
506 vec![2, 5],
507 "bd".to_string(),
508 vec![3, 6],
509 )
510 );
511 }
512
513 #[test]
515 fn test_hashmap_combine() {
516 let mut map1 = HashMap::new();
517 map1.insert("a", vec![1, 2]);
518
519 let mut map2 = HashMap::new();
520 map2.insert("a", vec![3, 4]);
521 map2.insert("b", vec![5]);
522
523 let result = map1.combine(map2);
524 assert_eq!(result.get("a"), Some(&vec![1, 2, 3, 4]));
525 assert_eq!(result.get("b"), Some(&vec![5]));
526 }
527
528 #[test]
529 fn test_hashmap_no_overlap() {
530 let mut map1 = HashMap::new();
531 map1.insert("a", vec![1, 2]);
532
533 let mut map2 = HashMap::new();
534 map2.insert("b", vec![3, 4]);
535
536 let result = map1.combine(map2);
537 assert_eq!(result.get("a"), Some(&vec![1, 2]));
538 assert_eq!(result.get("b"), Some(&vec![3, 4]));
539 }
540
541 #[test]
542 fn test_hashmap_associativity() {
543 let mut a = HashMap::new();
544 a.insert("x", vec![1]);
545
546 let mut b = HashMap::new();
547 b.insert("x", vec![2]);
548
549 let mut c = HashMap::new();
550 c.insert("x", vec![3]);
551
552 let left = a.clone().combine(b.clone()).combine(c.clone());
553 let right = a.combine(b.combine(c));
554
555 assert_eq!(left, right);
556 }
557
558 #[test]
560 fn test_hashset_union() {
561 let set1: HashSet<_> = [1, 2, 3].iter().cloned().collect();
562 let set2: HashSet<_> = [3, 4, 5].iter().cloned().collect();
563
564 let result = set1.combine(set2);
565 assert_eq!(result.len(), 5);
566 assert!(result.contains(&1));
567 assert!(result.contains(&2));
568 assert!(result.contains(&3));
569 assert!(result.contains(&4));
570 assert!(result.contains(&5));
571 }
572
573 #[test]
574 fn test_hashset_associativity() {
575 let a: HashSet<_> = [1, 2].iter().cloned().collect();
576 let b: HashSet<_> = [2, 3].iter().cloned().collect();
577 let c: HashSet<_> = [3, 4].iter().cloned().collect();
578
579 let left = a.clone().combine(b.clone()).combine(c.clone());
580 let right = a.combine(b.combine(c));
581
582 assert_eq!(left, right);
583 }
584
585 #[test]
587 fn test_btreemap_combine() {
588 let mut map1 = BTreeMap::new();
589 map1.insert("a", vec![1, 2]);
590
591 let mut map2 = BTreeMap::new();
592 map2.insert("a", vec![3, 4]);
593 map2.insert("b", vec![5]);
594
595 let result = map1.combine(map2);
596 assert_eq!(result.get("a"), Some(&vec![1, 2, 3, 4]));
597 assert_eq!(result.get("b"), Some(&vec![5]));
598 }
599
600 #[test]
601 fn test_btreemap_associativity() {
602 let mut a = BTreeMap::new();
603 a.insert("x", vec![1]);
604
605 let mut b = BTreeMap::new();
606 b.insert("x", vec![2]);
607
608 let mut c = BTreeMap::new();
609 c.insert("x", vec![3]);
610
611 let left = a.clone().combine(b.clone()).combine(c.clone());
612 let right = a.combine(b.combine(c));
613
614 assert_eq!(left, right);
615 }
616
617 #[test]
619 fn test_btreeset_union() {
620 let set1: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
621 let set2: BTreeSet<_> = [3, 4, 5].iter().cloned().collect();
622
623 let result = set1.combine(set2);
624 assert_eq!(result.len(), 5);
625 assert!(result.contains(&1));
626 assert!(result.contains(&5));
627 }
628
629 #[test]
630 fn test_btreeset_associativity() {
631 let a: BTreeSet<_> = [1, 2].iter().cloned().collect();
632 let b: BTreeSet<_> = [2, 3].iter().cloned().collect();
633 let c: BTreeSet<_> = [3, 4].iter().cloned().collect();
634
635 let left = a.clone().combine(b.clone()).combine(c.clone());
636 let right = a.combine(b.combine(c));
637
638 assert_eq!(left, right);
639 }
640
641 #[test]
643 fn test_option_semigroup() {
644 let opt1 = Some(vec![1, 2]);
645 let opt2 = Some(vec![3, 4]);
646 assert_eq!(opt1.combine(opt2), Some(vec![1, 2, 3, 4]));
647
648 let none: Option<Vec<i32>> = None;
649 let some = Some(vec![1]);
650 assert_eq!(none.clone().combine(some.clone()), some);
651 assert_eq!(some.clone().combine(none), some);
652 }
653
654 #[test]
655 fn test_option_both_none() {
656 let none1: Option<Vec<i32>> = None;
657 let none2: Option<Vec<i32>> = None;
658 assert_eq!(none1.combine(none2), None);
659 }
660
661 #[test]
662 fn test_option_associativity() {
663 let a = Some(vec![1]);
664 let b = Some(vec![2]);
665 let c = Some(vec![3]);
666
667 let left = a.clone().combine(b.clone()).combine(c.clone());
668 let right = a.combine(b.combine(c));
669
670 assert_eq!(left, right);
671 }
672
673 #[test]
675 fn test_first_last() {
676 assert_eq!(First(1).combine(First(2)), First(1));
677 assert_eq!(Last(1).combine(Last(2)), Last(2));
678 }
679
680 #[test]
681 fn test_first_associativity() {
682 let a = First(1);
683 let b = First(2);
684 let c = First(3);
685
686 let left = a.combine(b).combine(c);
687 let right = a.combine(b.combine(c));
688
689 assert_eq!(left, right);
690 }
691
692 #[test]
693 fn test_last_associativity() {
694 let a = Last(1);
695 let b = Last(2);
696 let c = Last(3);
697
698 let left = a.combine(b).combine(c);
699 let right = a.combine(b.combine(c));
700
701 assert_eq!(left, right);
702 }
703
704 #[test]
706 fn test_intersection_hashset() {
707 let set1: HashSet<_> = [1, 2, 3].iter().cloned().collect();
708 let set2: HashSet<_> = [2, 3, 4].iter().cloned().collect();
709
710 let i1 = Intersection(set1);
711 let i2 = Intersection(set2);
712 let result = i1.combine(i2);
713
714 let expected: HashSet<_> = [2, 3].iter().cloned().collect();
715 assert_eq!(result.0, expected);
716 }
717
718 #[test]
719 fn test_intersection_btreeset() {
720 let set1: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
721 let set2: BTreeSet<_> = [2, 3, 4].iter().cloned().collect();
722
723 let i1 = Intersection(set1);
724 let i2 = Intersection(set2);
725 let result = i1.combine(i2);
726
727 let expected: BTreeSet<_> = [2, 3].iter().cloned().collect();
728 assert_eq!(result.0, expected);
729 }
730
731 #[test]
732 fn test_intersection_associativity() {
733 let a: HashSet<_> = [1, 2, 3, 4].iter().cloned().collect();
734 let b: HashSet<_> = [2, 3, 4, 5].iter().cloned().collect();
735 let c: HashSet<_> = [3, 4, 5, 6].iter().cloned().collect();
736
737 let left = Intersection(a.clone())
738 .combine(Intersection(b.clone()))
739 .combine(Intersection(c.clone()));
740 let right = Intersection(a).combine(Intersection(b).combine(Intersection(c)));
741
742 assert_eq!(left.0, right.0);
743 }
744
745 #[cfg(test)]
747 mod proptests {
748 use super::*;
749 use proptest::prelude::*;
750
751 proptest! {
752 #[test]
753 fn prop_hashmap_associative(
754 a: HashMap<String, Vec<i32>>,
755 b: HashMap<String, Vec<i32>>,
756 c: HashMap<String, Vec<i32>>,
757 ) {
758 let left = a.clone().combine(b.clone()).combine(c.clone());
759 let right = a.combine(b.combine(c));
760 prop_assert_eq!(left, right);
761 }
762
763 #[test]
764 fn prop_hashset_associative(
765 a: HashSet<i32>,
766 b: HashSet<i32>,
767 c: HashSet<i32>,
768 ) {
769 let left = a.clone().combine(b.clone()).combine(c.clone());
770 let right = a.combine(b.combine(c));
771 prop_assert_eq!(left, right);
772 }
773
774 #[test]
775 fn prop_btreemap_associative(
776 a: BTreeMap<String, Vec<i32>>,
777 b: BTreeMap<String, Vec<i32>>,
778 c: BTreeMap<String, Vec<i32>>,
779 ) {
780 let left = a.clone().combine(b.clone()).combine(c.clone());
781 let right = a.combine(b.combine(c));
782 prop_assert_eq!(left, right);
783 }
784
785 #[test]
786 fn prop_btreeset_associative(
787 a: BTreeSet<i32>,
788 b: BTreeSet<i32>,
789 c: BTreeSet<i32>,
790 ) {
791 let left = a.clone().combine(b.clone()).combine(c.clone());
792 let right = a.combine(b.combine(c));
793 prop_assert_eq!(left, right);
794 }
795
796 #[test]
797 fn prop_option_associative(
798 a: Option<Vec<i32>>,
799 b: Option<Vec<i32>>,
800 c: Option<Vec<i32>>,
801 ) {
802 let left = a.clone().combine(b.clone()).combine(c.clone());
803 let right = a.combine(b.combine(c));
804 prop_assert_eq!(left, right);
805 }
806
807 #[test]
808 fn prop_first_associative(a: i32, b: i32, c: i32) {
809 let fa = First(a);
810 let fb = First(b);
811 let fc = First(c);
812 let left = fa.combine(fb).combine(fc);
813 let right = fa.combine(fb.combine(fc));
814 prop_assert_eq!(left, right);
815 }
816
817 #[test]
818 fn prop_last_associative(a: i32, b: i32, c: i32) {
819 let la = Last(a);
820 let lb = Last(b);
821 let lc = Last(c);
822 let left = la.combine(lb).combine(lc);
823 let right = la.combine(lb.combine(lc));
824 prop_assert_eq!(left, right);
825 }
826
827 #[test]
828 fn prop_intersection_associative(
829 a: HashSet<i32>,
830 b: HashSet<i32>,
831 c: HashSet<i32>,
832 ) {
833 let left = Intersection(a.clone())
834 .combine(Intersection(b.clone()))
835 .combine(Intersection(c.clone()));
836 let right = Intersection(a).combine(
837 Intersection(b).combine(Intersection(c))
838 );
839 prop_assert_eq!(left.0, right.0);
840 }
841 }
842 }
843}