From 807ff5e58955ea70c73758715a4d0d4d6bd98764 Mon Sep 17 00:00:00 2001
From: timofey <tim@ongoteam.yaconnect.com>
Date: Sun, 15 Oct 2023 17:34:09 +0000
Subject: [PATCH] shared_follows_laws

---
 src/func/instances/composition.rs |  5 ++++
 src/func/instances/effect.rs      | 39 ++++++++++++++++++-------------
 src/func/instances/future.rs      |  5 ++++
 src/func/instances/option.rs      |  5 ++++
 src/func/instances/result.rs      |  5 ++++
 src/func/instances/solo.rs        |  5 ++++
 src/func/instances/tryfuture.rs   |  5 ++++
 src/func/test_suite.rs            | 10 ++++++++
 src/func/tests.rs                 | 15 ++++++++++++
 9 files changed, 78 insertions(+), 16 deletions(-)

diff --git a/src/func/instances/composition.rs b/src/func/instances/composition.rs
index 37b7cc5..b378a4a 100644
--- a/src/func/instances/composition.rs
+++ b/src/func/instances/composition.rs
@@ -214,4 +214,9 @@ mod composition_tests {
     fn monad_follows_laws() {
         test_suite::monad_follows_laws::<T>().unwrap();
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/instances/effect.rs b/src/func/instances/effect.rs
index 9fef2ea..27eac1e 100644
--- a/src/func/instances/effect.rs
+++ b/src/func/instances/effect.rs
@@ -166,12 +166,12 @@ mod effect_tests {
 
     use super::{test_suite, tests, Effect, EffectInstance, WithEffect};
 
-    #[derive(Debug, PartialEq)]
+    #[derive(Clone, Debug, PartialEq)]
     enum TestEffect {
         Pure,
         Sample,
-        Parallel(Box<Self>, Box<Self>),
-        Sequential(Box<Self>, Box<Self>),
+        Parallel(Arc<Self>, Arc<Self>),
+        Sequential(Arc<Self>, Arc<Self>),
     }
 
     impl TestEffect {
@@ -179,25 +179,27 @@ mod effect_tests {
             matches!(self, Self::Pure)
         }
 
-        fn simplify(self) -> Self {
+        fn simplify(&self) -> Arc<Self> {
             match self {
-                Self::Pure => Self::Pure,
-                Self::Sample => Self::Sample,
-                Self::Parallel(a, b) if a.is_pure() => *b,
-                Self::Parallel(a, b) if b.is_pure() => *a,
-                Self::Sequential(a, b) if a.is_pure() => *b,
-                Self::Sequential(a, b) if b.is_pure() => *a,
-                Self::Parallel(a, b) => match *a {
+                Self::Pure => Self::Pure.into(),
+                Self::Sample => Self::Sample.into(),
+                Self::Parallel(a, b) if a.is_pure() => b.clone(),
+                Self::Parallel(a, b) if b.is_pure() => a.clone(),
+                Self::Sequential(a, b) if a.is_pure() => b.clone(),
+                Self::Sequential(a, b) if b.is_pure() => a.clone(),
+                Self::Parallel(a, b) => match a.as_ref() {
                     Self::Parallel(aa, ab) => {
-                        Self::Parallel(aa, Self::Parallel(ab, b).into()).simplify()
+                        Self::Parallel(aa.clone(), Self::Parallel(ab.clone(), b.clone()).into())
+                            .simplify()
                     }
-                    a => Self::Parallel(a.simplify().into(), b.simplify().into()),
+                    a => Self::Parallel(a.simplify(), b.simplify()).into(),
                 },
-                Self::Sequential(a, b) => match *a {
+                Self::Sequential(a, b) => match a.as_ref() {
                     TestEffect::Sequential(aa, ab) => {
-                        Self::Sequential(aa, Self::Sequential(ab, b).into()).simplify()
+                        Self::Sequential(aa.clone(), Self::Sequential(ab.clone(), b.clone()).into())
+                            .simplify()
                     }
-                    a => Self::Sequential(a.simplify().into(), b.simplify().into()),
+                    a => Self::Sequential(a.simplify().clone(), b.simplify().clone()).into(),
                 },
             }
         }
@@ -248,4 +250,9 @@ mod effect_tests {
     fn monad_follows_laws() {
         test_suite::monad_follows_laws::<T>().unwrap();
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/instances/future.rs b/src/func/instances/future.rs
index 8c2208b..7358f05 100644
--- a/src/func/instances/future.rs
+++ b/src/func/instances/future.rs
@@ -184,4 +184,9 @@ mod future_tests {
             Selected::B(_, b) => assert_eq!(b, 2),
         }
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/instances/option.rs b/src/func/instances/option.rs
index b6e0578..fc2fc70 100644
--- a/src/func/instances/option.rs
+++ b/src/func/instances/option.rs
@@ -185,4 +185,9 @@ mod option_tests {
     fn monad_follows_laws() {
         test_suite::monad_follows_laws::<T>().unwrap();
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/instances/result.rs b/src/func/instances/result.rs
index 7f25683..f2515bb 100644
--- a/src/func/instances/result.rs
+++ b/src/func/instances/result.rs
@@ -280,4 +280,9 @@ mod result_tests {
     fn monad_follows_laws() {
         test_suite::monad_follows_laws::<T>().unwrap();
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/instances/solo.rs b/src/func/instances/solo.rs
index ac5f5a1..1eda3f3 100644
--- a/src/func/instances/solo.rs
+++ b/src/func/instances/solo.rs
@@ -147,4 +147,9 @@ mod solo_tests {
     fn monad_follows_laws() {
         test_suite::monad_follows_laws::<T>().unwrap();
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/instances/tryfuture.rs b/src/func/instances/tryfuture.rs
index 89b1783..09a0fac 100644
--- a/src/func/instances/tryfuture.rs
+++ b/src/func/instances/tryfuture.rs
@@ -256,4 +256,9 @@ mod tryfuture_tests {
             Selected::B(_, b) => assert_eq!(b, 2),
         }
     }
+
+    #[test]
+    fn shared_follows_laws() {
+        test_suite::shared_follows_laws::<T>().unwrap();
+    }
 }
diff --git a/src/func/test_suite.rs b/src/func/test_suite.rs
index fba8de6..49dfa5c 100644
--- a/src/func/test_suite.rs
+++ b/src/func/test_suite.rs
@@ -1,5 +1,7 @@
 use std::sync::Arc;
 
+use shared::SharedFunctor;
+
 use super::tests::*;
 use super::*;
 
@@ -119,3 +121,11 @@ pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R {
     });
     res
 }
+
+pub fn shared_follows_laws<'a, T: SharedFunctor<'a> + FunctorTestSuite<'a>>() -> R {
+    let mut res = R::default();
+    T::sample(|pa| {
+        res += shared_is_same_as_original::<T, _>(move || pa(2));
+    });
+    res
+}
diff --git a/src/func/tests.rs b/src/func/tests.rs
index 07ef32a..d110b3f 100644
--- a/src/func/tests.rs
+++ b/src/func/tests.rs
@@ -5,6 +5,7 @@ use std::{
 
 use applicative_select::Selected;
 use controlflow::IterativeWrapped;
+use shared::SharedFunctor;
 
 use super::*;
 
@@ -448,3 +449,17 @@ pub fn select_of_equal_is_same<
         fa0(),
     )
 }
+
+pub fn shared_is_same_as_original<
+    'a,
+    T: SharedFunctor<'a> + Eqr<'a>,
+    A: 'a + Send + Sync + Clone + Debug + PartialEq,
+>(
+    fa0: impl 'a + Fn() -> T::F<A>,
+) -> R {
+    T::eqr(
+        "shared same as original",
+        T::unshare(T::share(fa0())),
+        fa0(),
+    )
+}