-
Notifications
You must be signed in to change notification settings - Fork 29
/
Using.scala
94 lines (82 loc) · 3.17 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
package com.thoughtworks.dsl.keywords
import com.thoughtworks.dsl.Dsl
import com.thoughtworks.dsl.Dsl.{!!, Keyword}
import com.thoughtworks.dsl.keywords.Catch.{CatchDsl, DslCatch}
import scala.concurrent.{ExecutionContext, Future}
import scala.language.implicitConversions
import scala.util.{Failure, Success, Try}
import scala.util.control.NonFatal
/** This [[Using]] keyword automatically manage resources in [[scala.concurrent.Future]], [[domains.task.Task]],
* and other asynchrounous domains derived from `Future` or `Task`.
*
* @author 杨博 (Yang Bo)
* @see [[dsl]] for usage of this [[Using]] keyword in continuations
*/
final case class Using[R <: AutoCloseable](open: () => R) extends AnyVal with Keyword[Using[R], R]
object Using {
implicit def implicitUsing[R <: AutoCloseable](r: => R): Using[R] = Using[R](r _)
def apply[R <: AutoCloseable](r: => R)(
implicit dummyImplicit: DummyImplicit = DummyImplicit.dummyImplicit): Using[R] = new Using(r _)
implicit def throwableContinuationUsingDsl[Domain, Value, R <: AutoCloseable](
implicit catchDsl: DslCatch[Domain, Domain, Value],
shiftDsl: Dsl[Shift[Domain, Value], Domain, Value]
): Dsl[Using[R], Domain !! Value, R] =
new Dsl[Using[R], Domain !! Value, R] {
def cpsApply(keyword: Using[R], handler: R => Domain !! Value): Domain !! Value = _ {
val r = keyword.open()
try {
!Shift(handler(r))
} finally {
r.close()
}
}
}
@deprecated("Use Dsl[Catch[...], ...] as implicit parameters instead of CatchDsl[...]", "Dsl.scala 1.2.0")
private[Using] def throwableContinuationUsingDsl[Domain, Value, R <: AutoCloseable](
implicit catchDsl: CatchDsl[Domain, Domain, Value],
shiftDsl: Dsl[Shift[Domain, Value], Domain, Value]
): Dsl[Using[R], Domain !! Value, R] = {
throwableContinuationUsingDsl(catchDsl: DslCatch[Domain, Domain, Value],
shiftDsl: Dsl[Shift[Domain, Value], Domain, Value])
}
implicit def scalaFutureUsingDsl[R <: AutoCloseable, A](
implicit executionContext: ExecutionContext): Dsl[Using[R], Future[A], R] =
new Dsl[Using[R], Future[A], R] {
def cpsApply(keyword: Using[R], handler: R => Future[A]): Future[A] = {
Future(keyword.open()).flatMap { r: R =>
def onFailure(e: Throwable): Future[Nothing] = {
try {
r.close()
Future.failed(e)
} catch {
case NonFatal(e2) =>
Future.failed(e2)
}
}
def onSuccess(a: A): Future[A] = {
try {
r.close()
Future.successful(a)
} catch {
case NonFatal(e2) =>
Future.failed(e2)
}
}
def returnableBlock(): Future[A] = {
val fa: Future[A] = try {
handler(r)
} catch {
case NonFatal(e) =>
return onFailure(e)
}
fa.recoverWith {
case NonFatal(e) =>
onFailure(e)
}
.flatMap(onSuccess)
}
returnableBlock()
}
}
}
}