Skip to content

Commit

Permalink
Cats Effect: STM & TRef #791 (#796)
Browse files Browse the repository at this point in the history
* Implement effect-polymorphic class atop STM #791

* Implement effect-polymorphic TRef #791

* remove unnecessary type parameters #791

* Add 'FunctionK' instance for converting TaskR to cats.IO #791

* Link to original documentation #791

* More efficient `collectAll` #791

* Make every method final #791

* Revert: Add 'FunctionK' instance for converting TaskR to cats.IO #791 (37d17db)

* Push implicits down to atomically #791

* Reorder methods alphabetically #791

* Fix formatting #791
  • Loading branch information
VladKopanev authored and jdegoes committed Apr 30, 2019
1 parent 99e699e commit fb7b0f1
Show file tree
Hide file tree
Showing 2 changed files with 298 additions and 0 deletions.
226 changes: 226 additions & 0 deletions interop-cats/jvm/src/main/scala/scalaz/zio/interop/stm/STM.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/*
* Copyright 2017-2019 John A. De Goes and the ZIO Contributors
*
* 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 scalaz.zio.interop.stm

import cats.effect.Async
import scalaz.zio.stm.{ STM => ZSTM }
import scalaz.zio.Runtime

import scala.util.Try

/**
* See [[scalaz.zio.stm.STM]]
*/
final class STM[F[+ _], +A] private[stm] (private[stm] val underlying: ZSTM[Throwable, A]) {
self =>

/**
* See `<*>` [[scalaz.zio.stm.STM]] `<*>`
*/
final def <*>[B](that: => STM[F, B]): STM[F, (A, B)] =
self zip that

/**
* See [[scalaz.zio.stm.STM]] `<*`
*/
final def <*[B](that: => STM[F, B]): STM[F, A] =
self zipLeft that

/**
* See [[scalaz.zio.stm.STM]] `*>`
*/
final def *>[B](that: => STM[F, B]): STM[F, B] =
self zipRight that

/**
* See [[scalaz.zio.stm.STM]] `>>=`
*/
final def >>=[B](f: A => STM[F, B]): STM[F, B] =
self flatMap f

/**
* See [[scalaz.zio.stm.STM#collect]]
*/
final def collect[B](pf: PartialFunction[A, B]): STM[F, B] = new STM(underlying.collect(pf))

/**
* See [[scalaz.zio.stm.STM#commit]]
*/
final def commit(implicit R: Runtime[Any], A: Async[F]): F[A] = STM.atomically(self)

/**
* See [[scalaz.zio.stm.STM#const]]
*/
final def const[B](b: => B): STM[F, B] = self map (_ => b)

/**
* See [[scalaz.zio.stm.STM#either]]
*/
final def either: STM[F, Either[Throwable, A]] = new STM(underlying.either)

/**
* See [[scalaz.zio.stm.STM#filter]]
*/
final def filter(f: A => Boolean): STM[F, A] =
collect {
case a if f(a) => a
}

/**
* See [[scalaz.zio.stm.STM#flatMap]]
*/
final def flatMap[B](f: A => STM[F, B]): STM[F, B] = new STM(underlying.flatMap(f.andThen(_.underlying)))

/**
* See [[scalaz.zio.stm.STM#flatten]]
*/
final def flatten[B](implicit ev: A <:< STM[F, B]): STM[F, B] =
self flatMap ev

/**
* See [[scalaz.zio.stm.STM#fold]]
*/
final def fold[B](f: Throwable => B, g: A => B): STM[F, B] = new STM(underlying.fold(f, g))

/**
* See [[scalaz.zio.stm.STM#foldM]]
*/
final def foldM[B](f: Throwable => STM[F, B], g: A => STM[F, B]): STM[F, B] =
new STM(underlying.foldM(f.andThen(_.underlying), g.andThen(_.underlying)))

/**
* See [[scalaz.zio.stm.STM#map]]
*/
final def map[B](f: A => B): STM[F, B] = new STM(underlying.map(f))

/**
* See [[scalaz.zio.stm.STM#mapError]]
*/
final def mapError[E1 <: Throwable](f: Throwable => E1): STM[F, A] = new STM(underlying.mapError(f))

/**
* Switch from effect F to effect G.
*/
final def mapK[G[+ _]]: STM[G, A] = new STM(underlying)

/**
* See [[scalaz.zio.stm.STM#option]]
*/
final def option: STM[F, Option[A]] =
fold[Option[A]](_ => None, Some(_))

/**
* See [[scalaz.zio.stm.STM#orElse]]
*/
final def orElse[A1 >: A](that: => STM[F, A1]): STM[F, A1] = new STM(underlying.orElse(that.underlying))

/**
* See [[scalaz.zio.stm.STM#orElseEither]]
*/
final def orElseEither[B](that: => STM[F, B]): STM[F, Either[A, B]] =
(self map (Left[A, B](_))) orElse (that map (Right[A, B](_)))

/**
* See scalaz.zio.stm.STM.unit
*/
final def unit: STM[F, Unit] = const(())

/**
* See scalaz.zio.stm.STM.unit
*/
final def void: STM[F, Unit] = unit

/**
* Same as [[filter]]
*/
final def withFilter(f: A => Boolean): STM[F, A] = filter(f)

/**
* See [[scalaz.zio.stm.STM#zip]]
*/
final def zip[B](that: => STM[F, B]): STM[F, (A, B)] =
(self zipWith that)((a, b) => a -> b)

/**
* See [[scalaz.zio.stm.STM#zipLeft]]
*/
final def zipLeft[B](that: => STM[F, B]): STM[F, A] =
(self zip that) map (_._1)

/**
* See [[scalaz.zio.stm.STM#zipRight]]
*/
final def zipRight[B](that: => STM[F, B]): STM[F, B] =
(self zip that) map (_._2)

/**
* See [[scalaz.zio.stm.STM#zipWith]]
*/
final def zipWith[B, C](that: => STM[F, B])(f: (A, B) => C): STM[F, C] =
self flatMap (a => that map (b => f(a, b)))

}

object STM {

final def atomically[F[+ _], A](stm: STM[F, A])(implicit R: Runtime[Any], A: Async[F]): F[A] =
A.async { cb =>
R.unsafeRunAsync(ZSTM.atomically(stm.underlying)) { exit =>
cb(exit.toEither)
}
}

final def check[F[+ _]](p: Boolean): STM[F, Unit] =
if (p) STM.unit else retry

final def collectAll[F[+ _], A](
i: Iterable[STM[F, A]]
): STM[F, List[A]] =
new STM(ZSTM.collectAll(i.map(_.underlying)))

final def die[F[+ _]](t: Throwable): STM[F, Nothing] =
succeedLazy(throw t)

final def dieMessage[F[+ _]](m: String): STM[F, Nothing] =
die(new RuntimeException(m))

final def fail[F[+ _]](e: Throwable): STM[F, Nothing] =
new STM(ZSTM.fail(e))

final def foreach[F[+ _], A, B](
as: Iterable[A]
)(f: A => STM[F, B]): STM[F, List[B]] =
collectAll(as.map(f))

final def fromEither[F[+ _], A](e: Either[Throwable, A]): STM[F, A] =
new STM(ZSTM.fromEither(e))

final def fromTry[F[+ _], A](a: => Try[A]): STM[F, A] =
new STM(ZSTM.fromTry(a))

final def partial[F[+ _], A](a: => A): STM[F, A] =
fromTry(Try(a))

final def retry[F[+ _]]: STM[F, Nothing] = new STM(ZSTM.retry)

final def succeed[F[+ _], A](a: A): STM[F, A] = new STM(ZSTM.succeed(a))

final def succeedLazy[F[+ _], A](a: => A): STM[F, A] =
new STM(ZSTM.succeedLazy(a))

final def unit[F[+ _]]: STM[F, Unit] = succeed(())
}
72 changes: 72 additions & 0 deletions interop-cats/jvm/src/main/scala/scalaz/zio/interop/stm/TRef.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2017-2019 John A. De Goes and the ZIO Contributors
*
* 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 scalaz.zio.interop.stm

import cats.effect.Async
import scalaz.zio.Runtime
import scalaz.zio.stm.{ TRef => ZTRef }

class TRef[F[+ _], A] private (val underlying: ZTRef[A]) extends AnyVal {
self =>

/**
* See [[scalaz.zio.stm.TRef#get]]
*/
final def get: STM[F, A] = new STM(underlying.get)

/**
* Switch from effect F to effect G.
*/
def mapK[G[+ _]]: TRef[G, A] = new TRef(underlying)

/**
* See [[scalaz.zio.stm.TRef#modify]]
*/
final def modify[B](f: A => (B, A)): STM[F, B] = new STM(underlying.modify(f))

/**
* See [[scalaz.zio.stm.TRef#modifySome]]
*/
final def modifySome[B](default: B)(f: PartialFunction[A, (B, A)]): STM[F, B] =
new STM(underlying.modifySome(default)(f))

/**
* See [[scalaz.zio.stm.TRef#set]]
*/
final def set(newValue: A): STM[F, Unit] = new STM(underlying.set(newValue))

override final def toString = underlying.toString

/**
* See [[scalaz.zio.stm.TRef#update]]
*/
final def update(f: A => A): STM[F, A] = new STM(underlying.update(f))

/**
* See [[scalaz.zio.stm.TRef#updateSome]]
*/
final def updateSome(f: PartialFunction[A, A]): STM[F, A] = new STM(underlying.updateSome(f))
}

object TRef {

final def make[F[+ _], A](a: => A): STM[F, TRef[F, A]] =
new STM(ZTRef.make(a).map(new TRef(_)))

final def makeCommit[F[+ _], A](a: => A)(implicit R: Runtime[Any], A: Async[F]): F[TRef[F, A]] =
STM.atomically(make(a))
}

0 comments on commit fb7b0f1

Please sign in to comment.