Skip to content

Commit

Permalink
Merge pull request #552 from Atry/await-promise
Browse files Browse the repository at this point in the history
Let Await accept js.Promise
  • Loading branch information
Atry committed Dec 20, 2021
2 parents 019ad1d + feb6ab9 commit c86a4ba
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.thoughtworks.dsl
package keywords
import com.thoughtworks.dsl.domains.Continuation.!!
import scalajs.js
import scala.util.Success
import scala.util.Failure
import scala.util.control.NonFatal

private trait AwaitJS { this: Await.type =>
given [PromiseResult]
: Dsl.IsKeyword[Await[js.Promise[PromiseResult]], PromiseResult] with {}

given [Value, That]: Dsl[Await[js.Promise[Value]], js.Promise[That], Value] =
Await.apply.liftCo[[X] =>> Dsl[X, js.Promise[That], Value]](_ `then` _)

extension [FA, A](inline fa: FA)(using
inline notKeyword: util.NotGiven[
FA <:< Dsl.Keyword
],
inline asFA: FA <:< js.Promise[A]
)
transparent inline def unary_! : A =
Dsl.shift(Await(asFA(fa))): A
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.thoughtworks.dsl.keywords

private trait AwaitJS { this: Await.type =>

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import scala.concurrent.duration.Duration
import scala.concurrent.{ExecutionContext, Future}
import scala.language.implicitConversions

/** [[Await]] is a [[Dsl.Keyword Keyword]] to extract value from a [[scala.concurrent.Future]].
/** [[Await]] is a [[Dsl.Keyword Keyword]] to extract value from a
* [[scala.concurrent.Future]].
*
* This keyword is available in functions whose return types are [[scala.concurrent.Future Future]],
* [[domains.task.Task]], or any exception aware continuations as `(_ !! Throwable !! _)`.
* This keyword is available in functions whose return types are
* [[scala.concurrent.Future Future]], [[domains.task.Task]], or any exception
* aware continuations as `(_ !! Throwable !! _)`.
*
* @example
* Given a [[scala.concurrent.Future Future]]:
Expand All @@ -23,15 +25,17 @@ import scala.language.implicitConversions
* }
* }}}
*
* You can [[Await]] the [[scala.concurrent.Future Future]] in another [[scala.concurrent.Future Future]]
* You can [[Await]] the [[scala.concurrent.Future Future]] in another
* [[scala.concurrent.Future Future]]
*
* {{{
* def myFuture42 = *[Future] {
* !Await(myFuture40) + 2
* }
* }}}
*
* A [[scala.concurrent.Future Future]] can be converted to a [[domains.task.Task]] with the help of [[Await]].
* A [[scala.concurrent.Future Future]] can be converted to a
* [[domains.task.Task]] with the help of [[Await]].
*
* {{{
* import com.thoughtworks.dsl.domains.Task
Expand All @@ -41,8 +45,8 @@ import scala.language.implicitConversions
* }
* }}}
*
* Then a [[domains.task.Task]] can be converted back to a [[scala.concurrent.Future]] via
* [[domains.task.Task.toFuture]].
* Then a [[domains.task.Task]] can be converted back to a
* [[scala.concurrent.Future]] via [[domains.task.Task.toFuture]].
*
* {{{
* val myAssertionTask = Task {
Expand Down Expand Up @@ -77,7 +81,8 @@ import scala.language.implicitConversions
* myFuture.map(_.toString should be("Oh No!"))
* }}}
* @example
* Other keywords, including [[Return]] or [[Get]], can be used together with [[Await]]
* Other keywords, including [[Return]] or [[Get]], can be used together with
* [[Await]]
* {{{
* import scala.concurrent.Future
* import com.thoughtworks.dsl.keywords.{Get, Return}
Expand Down Expand Up @@ -106,32 +111,29 @@ import scala.language.implicitConversions
* @author
* 杨博 (Yang Bo)
*/
opaque type Await[Result] <: Dsl.Keyword.Opaque = Dsl.Keyword.Opaque.Of[concurrent.Future[Result]]
object Await {
@inline def apply[Result]: concurrent.Future[Result] =:= Await[Result] = Dsl.Keyword.Opaque.Of.apply
given [Result]: IsKeyword[Await[Result], Result] with {}
opaque type Await[AwaitableValue] <: Dsl.Keyword.Opaque =
Dsl.Keyword.Opaque.Of[AwaitableValue]
object Await extends AwaitJS {
@inline def apply[AwaitableValue]: AwaitableValue =:= Await[AwaitableValue] =
Dsl.Keyword.Opaque.Of.apply
given [FutureResult]: IsKeyword[Await[Future[FutureResult]], FutureResult] with {}

implicit def awaitDsl[Value, That](implicit
executionContext: ExecutionContext
): Dsl[Await[Value], Future[That], Value] =
new Dsl[Await[Value], Future[That], Value] {
def cpsApply(keyword: Await[Value], handler: Value => Future[That]): Future[That] = {
keyword.flatMap(handler)
}
}
given [Value, That](using
ExecutionContext
): Dsl[Await[Future[Value]], Future[That], Value] =
_ flatMap _

// // TODO:
// // TODO:
// implicit def tailRecContinuationAwaitDsl[Value](implicit
// executionContext: ExecutionContext
// ): Dsl[Await[Value], TailRec[Unit] !! Throwable, Value]

implicit def continuationAwaitDsl[Value](implicit
executionContext: ExecutionContext
): Dsl[Await[Value], Unit !! Throwable, Value] =
new Dsl[Await[Value], Unit !! Throwable, Value] {
def cpsApply(keyword: Await[Value], handler: Value => Unit !! Throwable): Unit !! Throwable =
!!.fromTryContinuation[Unit, Value](keyword.onComplete)(handler)
}
given [Value](using
ExecutionContext
): Dsl[Await[Future[Value]], Unit !! Throwable, Value] = {
(keyword: Await[Future[Value]], handler: Value => Unit !! Throwable) =>
!!.fromTryContinuation[Unit, Value](keyword.onComplete)(handler)
}
extension [FA, A](inline fa: FA)(using
inline notKeyword: util.NotGiven[
FA <:< Dsl.Keyword
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
ast1.type
<:<
Dsl.For.Yield.FlatMap[
Await[Int],
Await[Future[Int]],
Int,
Dsl.For.Yield.Map[
Each[Int],
Expand Down Expand Up @@ -76,7 +76,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
ast2.type
<:<
Dsl.For.Yield.FlatMap[
Await[Int],
Await[Future[Int]],
Int,
Dsl.For.Yield.Map[
Each[Int],
Expand All @@ -99,7 +99,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
ast3.type
<:<
FlatMap[
Await[Int],
Await[Future[Int]],
Int,
FlatMap[
Each[Int],
Expand Down Expand Up @@ -134,8 +134,8 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
val reified = reify {
!Await(Future(1L))
}
summon[reified.type <:< Typed[Await[Long], Long]]
summon[Run[Typed[Await[Long], Long], Future[Long], Long]](reified)
summon[reified.type <:< Typed[Await[Future[Long]], Long]]
summon[Run[Typed[Await[Future[Long]], Long], Future[Long], Long]](reified)

*[Future] {
!Await(reified.to[Future]) should be(1L)
Expand All @@ -146,10 +146,12 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
val reified = reify {
!Await(Future(!Await(Future(1L))))
}
summon[reified.type <:< Typed[FlatMap[Await[Long], Long, Await[Long]], Long]]
summon[reified.type <:< Typed[FlatMap[Await[Future[Long]], Long, Await[
Future[Long]
]], Long]]
summon[
Run[
FlatMap[Await[Long], Long, Await[Long]],
FlatMap[Await[Future[Long]], Long, Await[Future[Long]]],
Future[Long],
Long
]
Expand All @@ -165,12 +167,12 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
!Await(Future(i))
}
summon[reified.type <:< Typed[
FlatMap[Await[String], String, Await[String]],
FlatMap[Await[Future[String]], String, Await[Future[String]]],
String
]]
summon[
Run[
FlatMap[Await[String], String, Await[String]],
FlatMap[Await[Future[String]], String, Await[Future[String]]],
Future[String],
String
]
Expand All @@ -193,10 +195,12 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
}
!Await(Future(A.j))
}
summon[reified.type <:< Typed[FlatMap[Await[Long], Long, Await[Long]], Long]]
summon[reified.type <:< Typed[FlatMap[Await[Future[Long]], Long, Await[
Future[Long]
]], Long]]
summon[
Run[
FlatMap[Await[Long], Long, Await[Long]],
FlatMap[Await[Future[Long]], Long, Await[Future[Long]]],
Future[Long],
Long
]
Expand All @@ -214,7 +218,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[FlatMap[
Await[Unit],
Await[Future[Unit]],
Unit,
FlatMap[Return[Unit], Nothing, Pure[Unit]]
], Unit]
Expand All @@ -232,7 +236,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
// summon[reified.type <:<
// Typed[
// FlatMap[
// Await[Unit]
// Await[Future[Unit]]
// , Unit,Pure[Nothing]]
// , Nothing]
// ]
Expand Down Expand Up @@ -329,12 +333,12 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
reified.type <:<
Typed[
keywords.TryCatchFinally[Suspend[
Await[String]
Await[Future[String]]
], Match.WithIndex[0, FlatMap[
Await[Int],
Await[Future[Int]],
Int,
FlatMap[Await[
Int
Future[Int]
], Int, Pure[String]]
]]
+: Nothing, Suspend[Pure[Unit]]],
Expand All @@ -358,7 +362,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[keywords.TryFinally[Suspend[
Await[Int]
Await[Future[Int]]
], Suspend[Pure[Unit]]], Int]
]

Expand All @@ -383,17 +387,17 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
reified.type <:<
Typed[keywords.TryCatch[Suspend[
FlatMap[
Await[Int],
Await[Future[Int]],
Int,
FlatMap[Await[
Int
Future[Int]
], Int, Pure[String]]
]
], Match.WithIndex[0, FlatMap[
Await[Int],
Await[Future[Int]],
Int,
FlatMap[Await[
Int
Future[Int]
], Int, Pure[String]]
]]
+: Nothing], String]
Expand All @@ -415,11 +419,11 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
reified.type <:<
Typed[FlatMap[While[
Suspend[
Await[Boolean]
Await[Future[Boolean]]
],
Suspend[
FlatMap[Await[
Int
Future[Int]
], Int, Pure[Unit]]
]
], Unit, Pure[Long]], Long]
Expand All @@ -441,10 +445,10 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[FlatMap[
Await[A.type],
Await[Future[A.type]],
A.type,
FlatMap[
Await[String],
Await[Future[String]],
String,
Pure[String]
]
Expand All @@ -462,10 +466,10 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[FlatMap[
Await[CharSequence],
Await[Future[CharSequence]],
CharSequence,
FlatMap[Await[
CharSequence
Future[CharSequence]
], CharSequence, Pure[Object]]
], Object]
]
Expand Down Expand Up @@ -502,9 +506,9 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[FlatMap[
Await[Int => Int],
Await[Future[Int => Int]],
Int => Int,
Await[Any => Boolean]
Await[Future[Any => Boolean]]
], Any => Boolean]
]
reified.to[Future].map {
Expand All @@ -520,9 +524,9 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[FlatMap[
FlatMap[Await[Int => Int], Int => Int, Pure[Any => Boolean]],
FlatMap[Await[Future[Int => Int]], Int => Int, Pure[Any => Boolean]],
Any => Boolean,
Await[Any => Boolean]
Await[Future[Any => Boolean]]
], Any => Boolean]
]
reified.to[Future].map {
Expand All @@ -538,9 +542,9 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
summon[
reified.type <:<
Typed[FlatMap[
FlatMap[Await[Int => Int], Int => Int, Pure[Any => Boolean]],
FlatMap[Await[Future[Int => Int]], Int => Int, Pure[Any => Boolean]],
Any => Boolean,
Await[Any => Boolean]
Await[Future[Any => Boolean]]
], Any => Boolean]
]
reified.to[Future].map {
Expand Down

0 comments on commit c86a4ba

Please sign in to comment.