-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cats Effect: STM & TRef #791 #796
Changes from all commits
a510755
3c8b37f
4d58e73
1a49bef
37d17db
652c70d
b14bd6e
52dad8b
768aa79
3fed4f5
aad5019
b951023
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No Scaladoc link? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did this because in this case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries! |
||
*/ | ||
final def unit: STM[F, Unit] = const(()) | ||
|
||
/** | ||
* See scalaz.zio.stm.STM.unit | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No Scaladoc link? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same problem here. |
||
*/ | ||
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] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Beautiful! Just this single method needs the implicit. |
||
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]( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't need an implicit. |
||
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(()) | ||
} |
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]] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This all looks good to me! I'd just sort the methods alphabetically, then it looks good to merge! 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
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)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks super clean. I think you can
extend AnyVal
here, too, now.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to, but scala compiler has issue with nested AnyVal classes, actually it does not support this feature yet. I didn't find any workarounds at this point. Anyways I think AnyVal has a bunch of restrictions that could make all workarounds meaningless (e.g. passing underlying ZSTM as a trait or other type leads to allocation).