-
Notifications
You must be signed in to change notification settings - Fork 29
/
Using.scala
102 lines (92 loc) · 3.16 KB
/
Using.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package com.thoughtworks.dsl
package keywords
import com.thoughtworks.dsl.macros.Reset.Default.*
import com.thoughtworks.dsl.Dsl
import com.thoughtworks.dsl.Dsl.IsKeyword
import com.thoughtworks.dsl.keywords.TryFinally
import scala.concurrent.{ExecutionContext, Future}
import scala.language.implicitConversions
import scala.util.control.NonFatal
/** This [[Using]] keyword automatically manage resources in
* [[scala.concurrent.Future]], [[domains.task.Task]], and other asynchronous
* domains derived from `Future` or `Task`.
*
* @author
* 杨博 (Yang Bo)
* @see
* [[dsl]] for usage of this [[Using]] keyword in continuations
*/
opaque type Using[+R] <: Dsl.Keyword.Opaque = Dsl.Keyword.Opaque.Of[R]
def Using[R](using
dummyImplicit: DummyImplicit = DummyImplicit.dummyImplicit
): R =:= Using[R] = Dsl.Keyword.Opaque.Of
object Using {
given [R]: IsKeyword[Using[R], R] with {}
extension [R](inline r: R)(using
inline notKeyword: util.NotGiven[
R <:< Dsl.Keyword
]
)
transparent inline def unary_! : R =
!Using[R](r)
trait ScopeExitHandler extends AutoCloseable
/** Returns a [[Using]] keyword to execute a [[ScopeExitHandler]] when exiting
* the nearest enclosing scope that is annotated as [[Dsl.reset @reset]], (or
* the nearest enclosing function if [[compilerplugins.ResetEverywhere]] is
* enabled).
*
* @note
* This method is similar to [[apply]], except the parameter type is
* changed from a generic `R` to the SAM type [[ScopeExitHandler]], which
* allows for function literal expressions in Scala 2.12+ or Scala 2.11
* with `-Xexperimental` compiler option.
*
* @example
* The following function will perform `n *= 2` after `n += 20`:
*
* {{{
* import scala.concurrent.Future
* import com.thoughtworks.dsl.keywords.Using.scopeExit
* import com.thoughtworks.dsl.keywords.Using.unary_!
* import com.thoughtworks.dsl.macros.Reset.Default.*
* var n = 1
* def multiplicationAfterAddition = *[Future] {
* !scopeExit { () =>
* n *= 2
* }
* n += 20
* }
* }}}
*
* Therefore, the final value of `n` should be `(1 + 20) * 2 = 42`.
*
* {{{
* multiplicationAfterAddition.map { _ =>
* n should be(42)
* }
* }}}
*/
def scopeExit(r: ScopeExitHandler): Using[ScopeExitHandler] = Using(r)
given [
R <: AutoCloseable,
Mapped <: Dsl.Keyword.Opaque | Dsl.Keyword.Trait,
MappedValue,
OuterDomain,
BlockDomain,
FinalizerDomain
](using
IsKeyword[Mapped, MappedValue],
TryFinally.DslComposer[OuterDomain, MappedValue, BlockDomain],
Dsl.Searching[Mapped, BlockDomain, MappedValue]
): Dsl.Composed[FlatMap[Using[R], Mapped], OuterDomain, MappedValue] =
Dsl.Composed {
case (FlatMap(r, flatMapper: (Using[R] @unchecked => Mapped)), handler) =>
reset[OuterDomain] {
handler(try {
!flatMapper(r)
} finally {
r.close()
})
}
}
}