Skip to content

Commit eeb0567

Browse files
committed
Simplify Using Dsl with the help of FlatMap
1 parent 486edd6 commit eeb0567

File tree

1 file changed

+60
-88
lines changed
  • keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords

1 file changed

+60
-88
lines changed
Lines changed: 60 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,94 @@
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}
98
import com.thoughtworks.dsl.keywords.TryFinally
109
import com.thoughtworks.dsl.Dsl.cpsApply
1110

1211
import scala.concurrent.{ExecutionContext, Future}
1312
import scala.language.implicitConversions
1413
import scala.util.control.NonFatal
1514

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

2426
object Using {
2527
given [R <: AutoCloseable]: AsKeyword.FromKeyword[Using[R], R] with {}
2628

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

2931
trait ScopeExitHandler extends AutoCloseable
3032

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).
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).
3437
*
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.
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.
3943
*
40-
* @example The following function will perform `n *= 2` after `n += 20`:
44+
* @example
45+
* The following function will perform `n *= 2` after `n += 20`:
4146
*
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-
* }}}
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+
* }}}
5459
*
55-
* Therefore, the final value of `n` should be `(1 + 20) * 2 = 42`.
60+
* Therefore, the final value of `n` should be `(1 + 20) * 2 = 42`.
5661
*
57-
* {{{
58-
* multiplicationAfterAddition.map { _ =>
59-
* n should be(42)
60-
* }
61-
* }}}
62+
* {{{
63+
* multiplicationAfterAddition.map { _ =>
64+
* n should be(42)
65+
* }
66+
* }}}
6267
*/
63-
def scopeExit(r: => ScopeExitHandler) = new Using(() => r)
68+
def scopeExit(r: ScopeExitHandler) = r
6469

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

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()
79-
}
80-
}
81-
}
82-
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 {
72+
given [
73+
R <: AutoCloseable,
74+
Mapped,
75+
MappedValue,
76+
OuterDomain,
77+
BlockDomain,
78+
FinalizerDomain
79+
](using
80+
AsKeyword.FromKeyword[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 {
8889
r.close()
89-
Future.failed(e)
90-
} catch {
91-
case NonFatal(e2) =>
92-
Future.failed(e2)
93-
}
90+
})
9491
}
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-
}
12192
}
93+
12294
}

0 commit comments

Comments
 (0)