forked from jsuereth/scala-arm
/
package.scala
90 lines (80 loc) · 3.67 KB
/
package.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
import resource._
/**
* Package related methods for managed resources.
*/
package object resource {
/** The type used to hold errors and results in the same return value. */
type ErrorHolder[A] = Either[List[Throwable],A]
/**
* Creates a ManagedResource for any type with a Resource type class implementation. This includes all
* java.io.Closeable subclasses, and any types that have a close or dispose method. You can also provide your own
* resource type class implementations in your own scope.
*/
def managed[A : Resource : Manifest](opener : => A) : ManagedResource[A] = new DefaultManagedResource(opener)
/**
* Constructs a managed resource using function objects for each abstract method.
*
* @param opener The by-name parameter that will open the resource.
* @param closer A closure that will close the resource.
* @param exceptions A list of exception classes that cannot be ignored to close a resource.
*/
def makeManagedResource[R : Manifest](opener : => R)(closer : R => Unit)(exceptions : List[Class[_<:Throwable]]) = {
implicit val typeTrait = new Resource[R] {
override def close(r : R) = closer(r)
override val fatalExceptions = exceptions
}
new DefaultManagedResource(opener)
}
import scala.util.continuations._
/**
* Starts block that will use continuation-based resource handling. This is where you can nest resources directly
* without having to worry about closing the block. Example:
*
*/
def withResources[C](f : => C @cps[Either[List[Throwable],C]]) = reset { Right(f) }
/**
* Combined two resources such that they are both opened/closed together. The first resource is opened before
* the second resource and closed after the second resource, however the resulting ManagedResource acts like
* both are opened/closed together.
* @return A ManagedResource of a tuple containing the initial two resources.
*/
def and[A,B](r1 : ManagedResource[A], r2 : ManagedResource[B]) = new ManagedResource[(A,B)] with ManagedResourceOperations[(A,B)] {
override def acquireFor[C](f : ((A,B)) => C) = withResources { f(Tuple2(r1.reflect[C], r2.reflect[C])) }
}
/*def joinResources[A](resources : Seq[ManagedResource[A]]) : ManagedResource[Seq[A]] = new ManagedResource[Seq[A]] with ManagedResourceOperations[Seq[A]] {
def acquireFor[C](f : Seq[A] => C) = withResources {
val rs = resources.map(_.reflect[C])
f(rs)
}
} */
/**
* Takes a sequence of ManagedResource objects and traits them as a ManagedResource of a Sequence of Objects.
*
* This is useful for dealing with many resources within the same scope.
*
* @param resource A collection of ManageResources of the same type
* @return A ManagedResoruce of a collection of types
*/
def join[A, MR, CC ](resources: CC)(implicit ev0: CC <:< Seq[ MR ], ev1: MR <:< ManagedResource[A]) : ManagedResource[Seq[A]] = {
//TODO - Use foldLeft
//TODO - Don't use such a sucky algorithm...
//We currently assume 1 resource
//TODO - See if we can provide Hlist implementation as well...
val itr = (resources.reverseIterator : Iterator[MR])
val first : ManagedResource[A] = itr.next
var toReturn : ManagedResource[Seq[A]] = first.map( x => Seq(x))
while(itr.hasNext) {
val r1 = toReturn
val r2 : ManagedResource[A] = itr.next
toReturn = new ManagedResource[Seq[A]] with ManagedResourceOperations[Seq[A]] {
override def acquireFor[B](f : Seq[A] => B) : Either[List[Throwable], B] = r1.acquireFor {
r1seq =>
r2.acquireAndGet { r2item =>
f( r2item :: r1seq.toList)
}
}
}
}
toReturn
}
}