|
1 | 1 | package com.thoughtworks.dsl |
2 | 2 | package keywords |
3 | 3 |
|
4 | | -import com.thoughtworks.dsl.bangnotation.{ `*`, reify, reset, unary_!} |
| 4 | +import com.thoughtworks.dsl.bangnotation.{`*`, reify, reset, unary_!} |
5 | 5 | import com.thoughtworks.dsl.Dsl |
6 | 6 | import com.thoughtworks.dsl.Dsl.!! |
7 | 7 | import com.thoughtworks.dsl.Dsl.AsKeyword |
8 | | -// import com.thoughtworks.dsl.keywords.Catch.{CatchDsl, DslCatch} |
9 | 8 | import com.thoughtworks.dsl.keywords.TryFinally |
10 | 9 | import com.thoughtworks.dsl.Dsl.cpsApply |
11 | 10 |
|
12 | 11 | import scala.concurrent.{ExecutionContext, Future} |
13 | 12 | import scala.language.implicitConversions |
14 | 13 | import scala.util.control.NonFatal |
15 | 14 |
|
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`. |
18 | 18 | * |
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 |
21 | 23 | */ |
22 | | -final case class Using[R <: AutoCloseable](open: () => R) extends AnyVal |
| 24 | +opaque type Using[R <: AutoCloseable] = R |
23 | 25 |
|
24 | 26 | object Using { |
25 | 27 | given [R <: AutoCloseable]: AsKeyword.FromKeyword[Using[R], R] with {} |
26 | 28 |
|
27 | | - given [R <: AutoCloseable]: AsKeyword[R, Using[R], R] = r => Using(() => r) |
| 29 | + given [R <: AutoCloseable]: AsKeyword[R, Using[R], R] = Using(_) |
28 | 30 |
|
29 | 31 | trait ScopeExitHandler extends AutoCloseable |
30 | 32 |
|
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). |
34 | 37 | * |
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. |
39 | 43 | * |
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`: |
41 | 46 | * |
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 | + * }}} |
54 | 59 | * |
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`. |
56 | 61 | * |
57 | | - * {{{ |
58 | | - * multiplicationAfterAddition.map { _ => |
59 | | - * n should be(42) |
60 | | - * } |
61 | | - * }}} |
| 62 | + * {{{ |
| 63 | + * multiplicationAfterAddition.map { _ => |
| 64 | + * n should be(42) |
| 65 | + * } |
| 66 | + * }}} |
62 | 67 | */ |
63 | | - def scopeExit(r: => ScopeExitHandler) = new Using(() => r) |
| 68 | + def scopeExit(r: ScopeExitHandler) = r |
64 | 69 |
|
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 |
68 | 71 |
|
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 { |
88 | 89 | r.close() |
89 | | - Future.failed(e) |
90 | | - } catch { |
91 | | - case NonFatal(e2) => |
92 | | - Future.failed(e2) |
93 | | - } |
| 90 | + }) |
94 | 91 | } |
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 | 92 | } |
| 93 | + |
122 | 94 | } |
0 commit comments