-
Notifications
You must be signed in to change notification settings - Fork 509
/
ConcurrentEffectLaws.scala
66 lines (57 loc) · 2.21 KB
/
ConcurrentEffectLaws.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*
* Copyright (c) 2017-2018 The Typelevel Cats-effect Project Developers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cats
package effect
package laws
import cats.effect.concurrent.Deferred
import cats.implicits._
import cats.laws._
trait ConcurrentEffectLaws[F[_]] extends ConcurrentLaws[F] with EffectLaws[F] {
implicit def F: ConcurrentEffect[F]
def runAsyncRunCancelableCoherence[A](fa: F[A]) = {
val fa1 = IO.async[A] { cb => F.runAsync(fa)(r => IO(cb(r))).unsafeRunSync() }
val fa2 = IO.cancelable[A] { cb => F.runCancelable(fa)(r => IO(cb(r))).unsafeRunSync() }
fa1 <-> fa2
}
def runCancelableIsSynchronous[A](fa: F[A]) = {
// Creating never ending tasks
def never[T] = IO.async[T](_ => {})
val ff = F.cancelable[A](_ => F.runAsync(fa)(_ => never))
val lh = IO(F.runCancelable(ff)(_ => never).unsafeRunSync().unsafeRunSync())
lh <-> IO.unit
}
def runCancelableStartCancelCoherence[A](a: A) = {
// Cancellation via runCancelable
val f1 = Deferred[IO, A].flatMap { effect1 =>
val never = F.cancelable[A](_ => effect1.complete(a))
F.runCancelable(never)(_ => IO.unit).flatten *> effect1.get
}
// Cancellation via start.flatMap(_.cancel)
val f2 = Deferred[IO, A].flatMap { effect2 =>
val never = F.cancelable[A](_ => effect2.complete(a))
val task = F.start(never).flatMap(_.cancel)
F.runAsync(task)(_ => IO.unit) *> effect2.get
}
f1 <-> f2
}
def toIORunCancelableConsistency[A](fa: F[A]) =
ConcurrentEffect.toIOFromRunCancelable(fa) <-> F.toIO(fa)
}
object ConcurrentEffectLaws {
def apply[F[_]](implicit F0: ConcurrentEffect[F]): ConcurrentEffectLaws[F] = new ConcurrentEffectLaws[F] {
val F = F0
}
}