-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
GenericSharedLock.scala
141 lines (111 loc) · 4.54 KB
/
GenericSharedLock.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package japgolly.webapputil.locks
import japgolly.webapputil.general.Effect
import java.util.concurrent.TimeUnit
object GenericSharedLock {
trait Safe[F[_], L, T] {
protected def F: Effect[F]
protected def unlock(lock: L): F[Unit]
val lock: F[L]
val lockInterruptibly: F[L]
val tryLock: F[T]
def tryLock(time: Long, unit: TimeUnit): F[T]
def apply[A](fa: F[A]): F[A] =
F.bracket(lockInterruptibly)(use = _ => fa)(release = unlock)
}
object Safe { obj =>
type DefaultOnLock[F[_]] = Locked[F]
type DefaultOnTryLock[F[_]] = Option[Locked[F]]
final case class Locked[F[_]](unlock: F[Unit])
trait ReadWrite[F[_], L, T] {
val readLock: Safe[F, L, T]
val writeLock: Safe[F, L, T]
}
object ReadWrite {
type Default[F[_]] = ReadWrite[F, DefaultOnLock[F], DefaultOnTryLock[F]]
}
trait ExportObject {
type Generic[F[_], L, T] = Safe[F, L, T]
val Generic = Safe
type DefaultOnLock[F[_]] = obj.DefaultOnLock[F]
type DefaultOnTryLock[F[_]] = obj.DefaultOnTryLock[F]
type Locked[F[_]] = obj.Locked[F]
val Locked = obj.Locked
}
trait ExportObjectF[F[_]] {
type Generic[L, T] = Safe[F, L, T]
val Generic = Safe
type DefaultOnLock = obj.DefaultOnLock[F]
type DefaultOnTryLock = obj.DefaultOnTryLock[F]
type Locked = obj.Locked[F]
val Locked = obj.Locked
}
trait Default[F[_]] extends Safe[F, DefaultOnLock[F], DefaultOnTryLock[F]] {
override protected def unlock(lock: DefaultOnLock[F]): F[Unit] =
lock.unlock
}
}
// ===================================================================================================================
trait Unsafe[L, T] { self =>
protected def unlock(lock: L): Unit
def lock(): L
def lockInterruptibly(): L
def tryLock(): T
def tryLock(time: Long, unit: TimeUnit): T
def apply[A](a: => A): A = {
val l = lockInterruptibly()
try a finally unlock(l)
}
def applyF[F[_], A](fa: F[A])(implicit F: Effect[F]): F[A] =
F.bracket(F.delay(lockInterruptibly()))(use = _ => fa)(release = l => F.delay(unlock(l)))
def withEffectGeneric[F[_]](implicit E: Effect[F]): Safe[F, L, T] =
new Safe[F, L, T] {
override protected def F = E
override val lock = E.delay(self.lock())
override val lockInterruptibly = E.delay(self.lockInterruptibly())
override val tryLock = E.delay(self.tryLock())
override def tryLock(time: Long, unit: TimeUnit) = E.delay(self.tryLock(time, unit))
override protected def unlock(lock: L) = E.delay(self.unlock(lock))
}
}
object Unsafe { obj =>
type DefaultOnLock = Locked
type DefaultOnTryLock = Option[Locked]
final case class Locked(unlock: () => Unit) {
def unlockF[F[_]](implicit F: Effect[F]): F[Unit] =
F.delay(unlock())
def withEffect[F[_]](implicit F: Effect[F]): Safe.Locked[F] =
Safe.Locked[F](unlockF[F])
}
trait ReadWrite[L, T] {
val readLock: Unsafe[L, T]
val writeLock: Unsafe[L, T]
}
object ReadWrite {
type Default = ReadWrite[DefaultOnLock, DefaultOnTryLock]
}
trait ExportObject {
type Generic[L, T] = Unsafe[L, T]
val Generic = Unsafe
type DefaultOnLock = obj.DefaultOnLock
type DefaultOnTryLock = obj.DefaultOnTryLock
type Locked = obj.Locked
val Locked = obj.Locked
}
trait Default extends Unsafe[DefaultOnLock, DefaultOnTryLock] { self =>
import Unsafe.{DefaultOnLock => L}
override protected def unlock(lock: L): Unit =
lock.unlock()
def withEffect[F[_]](implicit E: Effect[F]): Safe.Default[F] = {
type L = Safe.DefaultOnLock[F]
new Safe.Default[F] {
override protected def F = E
override val lock = E.delay(self.lock().withEffect[F])
override val lockInterruptibly = E.delay(self.lockInterruptibly().withEffect[F])
override val tryLock = E.delay(self.tryLock().map(_.withEffect[F]))
override def tryLock(time: Long, unit: TimeUnit) = E.delay(self.tryLock(time , unit).map(_.withEffect[F]))
override protected def unlock(lock: L) = lock.unlock
}
}
}
}
}