Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions core-tests/shared/src/test/scala/zio/CancelableFutureSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package zio

import zio.test.Assertion._
import zio.test._

object CancelableFutureSpec
extends ZIOBaseSpec(
suite("CancelableFutureSpec")(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the new ZIO Test!

testM("interrupts the underlying task on cancel") {
for {
p <- Promise.make[Nothing, Unit]
p2 <- Promise.make[Nothing, Int]
f <- (p.succeed(()) *> IO.never).onInterrupt(p2.succeed(42)).toFuture
_ <- p.await
_ <- UIO(f.cancel)
test <- p2.await
} yield assert(test, equalTo(42))
},
testM("cancel returns the exit reason") {
for {
t <- UIO(new Exception("test"))
p1 <- Promise.make[Nothing, Unit]
p2 <- Promise.make[Nothing, Unit]
f1 <- (ZIO.succeed(42) <* p1.succeed(())).toFuture
f2 <- ZIO.fail(t).onError(_ => p2.succeed(())).toFuture
_ <- p1.await
_ <- p2.await
e1 <- ZIO.fromFuture(_ => f1.cancel)
e2 <- ZIO.fromFuture(_ => f2.cancel)
} yield assert(e1.succeeded, isTrue) && assert(e2.succeeded, isFalse)
},
testM("is a scala.concurrent.Future") {
for {
f <- ZIO(42).toFuture
v <- ZIO.fromFuture(_ => f)
} yield {
assert(v, equalTo(42))
}
}
)
)
20 changes: 20 additions & 0 deletions core/shared/src/main/scala-2.11/zio/FutureTransformCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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 zio

private[zio] trait FutureTransformCompat[+A] { this: CancelableFuture[Any, A] =>
}
28 changes: 28 additions & 0 deletions core/shared/src/main/scala-2.12+/zio/FutureTransformCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 zio

import scala.concurrent.{ ExecutionContext, Future }
import scala.util.Try

private[zio] trait FutureTransformCompat[+A] { this: CancelableFuture[Any, A] =>
def transform[S](f: Try[A] => Try[S])(implicit executor: ExecutionContext): Future[S] =
future.transform(f)(executor)

def transformWith[S](f: Try[A] => Future[S])(implicit executor: ExecutionContext): Future[S] =
future.transformWith(f)(executor)
}
46 changes: 46 additions & 0 deletions core/shared/src/main/scala/zio/CancelableFuture.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 zio

import scala.concurrent.{ CanAwait, ExecutionContext, Future }
import scala.concurrent.duration.Duration
import scala.util.Try

abstract class CancelableFuture[+E, +A](val future: Future[A]) extends Future[A] with FutureTransformCompat[A] {

/**
* Immediately cancels the operation and returns a [[scala.concurrent.Future]] containing the result
*/
def cancel: Future[Exit[E, A]]

def onComplete[U](f: Try[A] => U)(implicit executor: ExecutionContext): Unit =
future.onComplete(f)(executor)

def isCompleted: Boolean =
future.isCompleted

def value: Option[Try[A]] =
future.value

def ready(atMost: Duration)(implicit permit: CanAwait): this.type = {
future.ready(atMost)(permit)
this
}

def result(atMost: Duration)(implicit permit: CanAwait): A =
future.result(atMost)
}
11 changes: 7 additions & 4 deletions core/shared/src/main/scala/zio/Fiber.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ trait Fiber[+E, +A] { self =>
* @param ev implicit witness that E is a subtype of Throwable
* @return `UIO[Future[A]]`
*/
final def toFuture(implicit ev: E <:< Throwable): UIO[Future[A]] =
final def toFuture(implicit ev: E <:< Throwable): UIO[CancelableFuture[E, A]] =
toFutureWith(ev)

/**
Expand All @@ -267,17 +267,20 @@ trait Fiber[+E, +A] { self =>
* @param f function to the error into a Throwable
* @return `UIO[Future[A]]`
*/
final def toFutureWith(f: E => Throwable): UIO[Future[A]] =
final def toFutureWith(f: E => Throwable): UIO[CancelableFuture[E, A]] =
UIO.effectTotal {
val p: concurrent.Promise[A] = scala.concurrent.Promise[A]()

def failure(cause: Cause[E]): UIO[p.type] = UIO(p.failure(cause.squashWith(f)))
def success(value: A): UIO[p.type] = UIO(p.success(value))

UIO.effectTotal(p.future) <* self.await
ZIO.runtime[Any].map { runtime =>
new CancelableFuture[E, A](p.future) {
def cancel: Future[Exit[E, A]] = runtime.unsafeRunToFuture(interrupt)
}
} <* self.await
.flatMap[Any, Nothing, p.type](_.foldM[Any, Nothing, p.type](failure, success))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if type annotations could be avoided if concurrent.Promise[A] is used in success/failure returns instead of p.type

.fork

}.flatten

/**
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/zio/Runtime.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ trait Runtime[+R] {
*
* This method is effectful and should only be used at the edges of your program.
*/
final def unsafeRunToFuture[E <: Throwable, A](io: ZIO[R, E, A]): scala.concurrent.Future[A] =
final def unsafeRunToFuture[E <: Throwable, A](io: ZIO[R, E, A]): CancelableFuture[E, A] =
unsafeRun(io.toFuture)

/**
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/zio/ZIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1314,13 +1314,13 @@ sealed trait ZIO[-R, +E, +A] extends Serializable { self =>
/**
* Converts the effect into a [[scala.concurrent.Future]].
*/
final def toFuture(implicit ev2: E <:< Throwable): ZIO[R, Nothing, scala.concurrent.Future[A]] =
final def toFuture(implicit ev2: E <:< Throwable): ZIO[R, Nothing, CancelableFuture[E, A]] =
self toFutureWith ev2

/**
* Converts the effect into a [[scala.concurrent.Future]].
*/
final def toFutureWith(f: E => Throwable): ZIO[R, Nothing, scala.concurrent.Future[A]] =
final def toFutureWith(f: E => Throwable): ZIO[R, Nothing, CancelableFuture[E, A]] =
self.fork >>= (_.toFutureWith(f))

/**
Expand Down