Skip to content

Instantly share code, notes, and snippets.

@djspiewak
Created December 12, 2020 23:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djspiewak/19729390a1ce0828476212e0ec25b6fe to your computer and use it in GitHub Desktop.
Save djspiewak/19729390a1ce0828476212e0ec25b6fe to your computer and use it in GitHub Desktop.
/*
* Copyright 2020 Typelevel
*
* 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.effect
package laws
import cats.effect.kernel.{Deferred, GenConcurrent, Ref}
import cats.syntax.all._
trait GenConcurrentLaws[F[_], E] extends GenSpawnLaws[F, E] {
implicit val F: GenConcurrent[F, E]
def refGetReturnsValue[A] =
assume[Ref[F, A]] in { (ref, a) => ref.get <-> a.pure[F] }
def refSetModifiesValue[A](a: A) =
assume[Ref[F, A]] in { (ref, _) => ref.set(a) <-> mutate(F.unit, ref -> a) }
def deferredGetReturnsValueOrNever[A] =
assume[Deferred[F, A]] in { (d, opt) => d.get <-> opt.fold(F.never[A])(_.pure[F]) }
def deferredTryGetReturnsOptionalValue[A] =
assume[Deferred[F, A]] in { (d, opt) => d.tryGet <-> opt.pure[F] }
def deferredCompleteModifiesValueWhenUnset[A](a: A) =
assume[Deferred[F, A]] in { (d, old) =>
old match {
case Some(_) => d.complete(a) <-> false.pure[F]
case None =>
d.complete(a) <-> mutate(true.pure[F], d -> a.some)
}
}
private[this] def assume[T](implicit env: Env[F, T]): AssumePartial[T, env.A] =
new AssumePartial[T, env.A](env)
private[this] def mutate[T, A, B](value: A, mut: (T, B)): WithContext[A, T, B] =
WithContext(value, Some(mut))
private[this] class AssumePartial[T, B](env: Env.Aux[F, T, B]) {
def in[A](
body: (T, B) => IsEqWithContext[F, A, T, B]): B => F[IsEqWithContext[F, A, T, B]] =
b => env(b).map(t => body(t, b))
}
}
object GenConcurrentLaws {
def apply[F[_], E](implicit F0: GenConcurrent[F, E]): GenConcurrentLaws[F, E] =
new GenConcurrentLaws[F, E] { val F = F0 }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment