Skip to content

Commit 7e148bd

Browse files
authored
Merge pull request #505 from Atry/test-asio
Revert FlatMap based Using Dsl and backport #504 to 2.x to fix a test against Using
2 parents 0351be8 + 5e506c2 commit 7e148bd

File tree

3 files changed

+94
-67
lines changed

3 files changed

+94
-67
lines changed
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
enablePlugins(Example)
22

33
import meta._
4-
exampleSuperTypes := exampleSuperTypes.value.map {
5-
case init"_root_.org.scalatest.FreeSpec" =>
6-
init"_root_.org.scalatest.AsyncFreeSpec"
7-
case otherTrait =>
8-
otherTrait
4+
exampleSuperTypes := {
5+
val (init"_root_.org.scalatest.freespec.AnyFreeSpec" +: traits) = exampleSuperTypes.value
6+
init"_root_.org.scalatest.freespec.AsyncFreeSpec" +: traits
97
}
108

119
libraryDependencies += "org.scalatest" %%% "scalatest" % "3.2.10" % Test

keywords-AsynchronousIo/src/main/scala/com/thoughtworks/dsl/keywords/AsynchronousIo.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ import scala.util.control.NonFatal
6868
* Then the `cat` function is used to concatenate files from this project, as shown below:
6969
*
7070
* {{{
71-
* Task.toFuture(*[Task] {
71+
* Task.toFuture(Task {
7272
* (!Shift(cat(Paths.get(".sbtopts"), Paths.get(".scalafmt.conf")))).mkString should be(
73-
* "-J-XX:MaxMetaspaceSize=512M\n-J-Xmx5G\n-J-Xss6M\nversion = \"1.5.1\"\nmaxColumn = 120"
73+
* new String(Files.readAllBytes(Paths.get(".sbtopts")), io.Codec.UTF8.charSet) +
74+
* new String(Files.readAllBytes(Paths.get(".scalafmt.conf")), io.Codec.UTF8.charSet)
7475
* )
7576
* })
7677
* }}}
Lines changed: 88 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,122 @@
11
package com.thoughtworks.dsl
22
package keywords
33

4-
import com.thoughtworks.dsl.bangnotation.{`*`, reify, reset, unary_!}
4+
import com.thoughtworks.dsl.bangnotation.{ `*`, reify, reset, unary_!}
55
import com.thoughtworks.dsl.Dsl
66
import com.thoughtworks.dsl.Dsl.!!
77
import com.thoughtworks.dsl.Dsl.AsKeyword
8+
// import com.thoughtworks.dsl.keywords.Catch.{CatchDsl, DslCatch}
89
import com.thoughtworks.dsl.keywords.TryFinally
910
import com.thoughtworks.dsl.Dsl.cpsApply
1011

1112
import scala.concurrent.{ExecutionContext, Future}
1213
import scala.language.implicitConversions
1314
import scala.util.control.NonFatal
1415

15-
/** This [[Using]] keyword automatically manage resources in
16-
* [[scala.concurrent.Future]], [[domains.task.Task]], and other asynchronous
17-
* domains derived from `Future` or `Task`.
16+
/** This [[Using]] keyword automatically manage resources in [[scala.concurrent.Future]], [[domains.task.Task]],
17+
* and other asynchronous domains derived from `Future` or `Task`.
1818
*
19-
* @author
20-
* 杨博 (Yang Bo)
21-
* @see
22-
* [[dsl]] for usage of this [[Using]] keyword in continuations
19+
* @author 杨博 (Yang Bo)
20+
* @see [[dsl]] for usage of this [[Using]] keyword in continuations
2321
*/
24-
opaque type Using[R <: AutoCloseable] = R
22+
final case class Using[R <: AutoCloseable](open: () => R) extends AnyVal
2523

2624
object Using {
2725
given [R <: AutoCloseable]: AsKeyword.IsKeyword[Using[R], R] with {}
2826

29-
given [R <: AutoCloseable]: AsKeyword[R, Using[R], R] = Using(_)
27+
given [R <: AutoCloseable]: AsKeyword[R, Using[R], R] = r => Using(() => r)
3028

3129
trait ScopeExitHandler extends AutoCloseable
3230

33-
/** Returns a [[Using]] keyword to execute a [[ScopeExitHandler]] when exiting
34-
* the nearest enclosing scope that is annotated as [[Dsl.reset @reset]], (or
35-
* the nearest enclosing function if [[compilerplugins.ResetEverywhere]] is
36-
* enabled).
31+
/** Returns a [[Using]] keyword to execute a [[ScopeExitHandler]] when exiting the nearest enclosing scope
32+
* that is annotated as [[Dsl.reset @reset]],
33+
* (or the nearest enclosing function if [[compilerplugins.ResetEverywhere]] is enabled).
3734
*
38-
* @note
39-
* This method is similar to [[apply]], except the parameter type is
40-
* changed from a generic `R` to the SAM type [[ScopeExitHandler]], which
41-
* allows for function literal expressions in Scala 2.12+ or Scala 2.11
42-
* with `-Xexperimental` compiler option.
35+
* @note This method is similar to [[apply]],
36+
* except the parameter type is changed from a generic `R` to the SAM type [[ScopeExitHandler]],
37+
* which allows for function literal expressions
38+
* in Scala 2.12+ or Scala 2.11 with `-Xexperimental` compiler option.
4339
*
44-
* @example
45-
* The following function will perform `n *= 2` after `n += 20`:
40+
* @example The following function will perform `n *= 2` after `n += 20`:
4641
*
47-
* {{{
48-
* import scala.concurrent.Future
49-
* import com.thoughtworks.dsl.keywords.Using.scopeExit
50-
* import com.thoughtworks.dsl.bangnotation._
51-
* var n = 1
52-
* def multiplicationAfterAddition = *[Future] {
53-
* !scopeExit { () =>
54-
* n *= 2
55-
* }
56-
* n += 20
57-
* }
58-
* }}}
42+
* {{{
43+
* import scala.concurrent.Future
44+
* import com.thoughtworks.dsl.keywords.Using.scopeExit
45+
* import com.thoughtworks.dsl.bangnotation._
46+
* var n = 1
47+
* def multiplicationAfterAddition = *[Future] {
48+
* !scopeExit { () =>
49+
* n *= 2
50+
* }
51+
* n += 20
52+
* }
53+
* }}}
5954
*
60-
* Therefore, the final value of `n` should be `(1 + 20) * 2 = 42`.
55+
* Therefore, the final value of `n` should be `(1 + 20) * 2 = 42`.
6156
*
62-
* {{{
63-
* multiplicationAfterAddition.map { _ =>
64-
* n should be(42)
65-
* }
66-
* }}}
57+
* {{{
58+
* multiplicationAfterAddition.map { _ =>
59+
* n should be(42)
60+
* }
61+
* }}}
6762
*/
68-
def scopeExit(r: ScopeExitHandler) = r
63+
def scopeExit(r: => ScopeExitHandler) = new Using(() => r)
6964

70-
def apply[R <: AutoCloseable]: R =:= Using[R] = summon
65+
def apply[R <: AutoCloseable](r: => R)(implicit
66+
dummyImplicit: DummyImplicit = DummyImplicit.dummyImplicit
67+
): Using[R] = new Using(() => r)
7168

72-
given [
73-
R <: AutoCloseable,
74-
Mapped,
75-
MappedValue,
76-
OuterDomain,
77-
BlockDomain,
78-
FinalizerDomain
79-
](using
80-
AsKeyword.IsKeyword[Mapped, MappedValue],
81-
Dsl.TryFinally[MappedValue, OuterDomain, BlockDomain, FinalizerDomain],
82-
Dsl.PolyCont[Mapped, BlockDomain, MappedValue]
83-
): Dsl.PolyCont[FlatMap[Using[R], R, Mapped], OuterDomain, MappedValue] = {
84-
case (FlatMap(r, flatMapper), handler) =>
85-
reset {
86-
handler(try {
87-
!flatMapper(r)
88-
} finally {
89-
r.close()
90-
})
69+
implicit def continuationUsingDsl[Domain, Value, R <: AutoCloseable](implicit
70+
tryFinally: Dsl.TryFinally[Value, Domain, Domain, Domain],
71+
// shiftDsl: Dsl[Shift[Domain, Value], Domain, Value]
72+
): Dsl[Using[R], Domain !! Value, R] = { (keyword: Using[R], handler: R => Domain !! Value) =>
73+
*[[X] =>> Domain !! X] {
74+
val r = keyword.open()
75+
try {
76+
!Shift[Domain, Value](handler(r))
77+
} finally {
78+
r.close()
9179
}
80+
}
9281
}
9382

83+
implicit def scalaFutureUsingDsl[R <: AutoCloseable, A](implicit executionContext: ExecutionContext)
84+
: Dsl[Using[R], Future[A], R] = { (keyword: Using[R], handler: R => Future[A]) =>
85+
Future(keyword.open()).flatMap { (r: R) =>
86+
def onFailure(e: Throwable): Future[Nothing] = {
87+
try {
88+
r.close()
89+
Future.failed(e)
90+
} catch {
91+
case NonFatal(e2) =>
92+
Future.failed(e2)
93+
}
94+
}
95+
96+
def onSuccess(a: A): Future[A] = {
97+
try {
98+
r.close()
99+
Future.successful(a)
100+
} catch {
101+
case NonFatal(e2) =>
102+
Future.failed(e2)
103+
}
104+
}
105+
106+
def returnableBlock(): Future[A] = {
107+
val fa: Future[A] = try {
108+
handler(r)
109+
} catch {
110+
case NonFatal(e) =>
111+
return onFailure(e)
112+
}
113+
fa.recoverWith {
114+
case NonFatal(e) =>
115+
onFailure(e)
116+
}
117+
.flatMap(onSuccess)
118+
}
119+
returnableBlock()
120+
}
121+
}
94122
}

0 commit comments

Comments
 (0)