effect 4.0.0-beta.17 → 4.0.0-beta.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/Array.d.ts +127 -299
  2. package/dist/Array.d.ts.map +1 -1
  3. package/dist/Array.js +102 -62
  4. package/dist/Array.js.map +1 -1
  5. package/dist/Cache.d.ts.map +1 -1
  6. package/dist/Cache.js +5 -4
  7. package/dist/Cache.js.map +1 -1
  8. package/dist/Channel.d.ts +97 -11
  9. package/dist/Channel.d.ts.map +1 -1
  10. package/dist/Channel.js +72 -29
  11. package/dist/Channel.js.map +1 -1
  12. package/dist/Chunk.d.ts +54 -247
  13. package/dist/Chunk.d.ts.map +1 -1
  14. package/dist/Chunk.js +36 -67
  15. package/dist/Chunk.js.map +1 -1
  16. package/dist/Effect.d.ts +337 -437
  17. package/dist/Effect.d.ts.map +1 -1
  18. package/dist/Effect.js +118 -134
  19. package/dist/Effect.js.map +1 -1
  20. package/dist/Filter.d.ts +0 -33
  21. package/dist/Filter.d.ts.map +1 -1
  22. package/dist/Filter.js +0 -13
  23. package/dist/Filter.js.map +1 -1
  24. package/dist/HashMap.d.ts +15 -14
  25. package/dist/HashMap.d.ts.map +1 -1
  26. package/dist/HashMap.js +4 -4
  27. package/dist/HashMap.js.map +1 -1
  28. package/dist/Iterable.d.ts +40 -39
  29. package/dist/Iterable.d.ts.map +1 -1
  30. package/dist/Iterable.js +94 -22
  31. package/dist/Iterable.js.map +1 -1
  32. package/dist/Option.d.ts +22 -15
  33. package/dist/Option.d.ts.map +1 -1
  34. package/dist/Option.js +14 -7
  35. package/dist/Option.js.map +1 -1
  36. package/dist/Pull.d.ts.map +1 -1
  37. package/dist/Pull.js +1 -1
  38. package/dist/Pull.js.map +1 -1
  39. package/dist/Record.d.ts +24 -120
  40. package/dist/Record.d.ts.map +1 -1
  41. package/dist/Record.js +21 -41
  42. package/dist/Record.js.map +1 -1
  43. package/dist/Sink.d.ts +11 -11
  44. package/dist/Sink.d.ts.map +1 -1
  45. package/dist/Sink.js +53 -6
  46. package/dist/Sink.js.map +1 -1
  47. package/dist/Stream.d.ts +198 -386
  48. package/dist/Stream.d.ts.map +1 -1
  49. package/dist/Stream.js +103 -59
  50. package/dist/Stream.js.map +1 -1
  51. package/dist/Trie.d.ts +18 -17
  52. package/dist/Trie.d.ts.map +1 -1
  53. package/dist/Trie.js +5 -5
  54. package/dist/Trie.js.map +1 -1
  55. package/dist/TxChunk.d.ts +37 -37
  56. package/dist/TxChunk.d.ts.map +1 -1
  57. package/dist/TxChunk.js +3 -3
  58. package/dist/TxChunk.js.map +1 -1
  59. package/dist/TxDeferred.d.ts +328 -0
  60. package/dist/TxDeferred.d.ts.map +1 -0
  61. package/dist/TxDeferred.js +196 -0
  62. package/dist/TxDeferred.js.map +1 -0
  63. package/dist/TxHashMap.d.ts +84 -83
  64. package/dist/TxHashMap.d.ts.map +1 -1
  65. package/dist/TxHashMap.js +24 -24
  66. package/dist/TxHashMap.js.map +1 -1
  67. package/dist/TxHashSet.d.ts +35 -35
  68. package/dist/TxHashSet.d.ts.map +1 -1
  69. package/dist/TxHashSet.js +14 -14
  70. package/dist/TxHashSet.js.map +1 -1
  71. package/dist/TxPriorityQueue.d.ts +609 -0
  72. package/dist/TxPriorityQueue.d.ts.map +1 -0
  73. package/dist/TxPriorityQueue.js +415 -0
  74. package/dist/TxPriorityQueue.js.map +1 -0
  75. package/dist/TxPubSub.d.ts +585 -0
  76. package/dist/TxPubSub.d.ts.map +1 -0
  77. package/dist/TxPubSub.js +521 -0
  78. package/dist/TxPubSub.js.map +1 -0
  79. package/dist/TxQueue.d.ts +32 -32
  80. package/dist/TxQueue.d.ts.map +1 -1
  81. package/dist/TxQueue.js +26 -26
  82. package/dist/TxQueue.js.map +1 -1
  83. package/dist/TxReentrantLock.d.ts +523 -0
  84. package/dist/TxReentrantLock.d.ts.map +1 -0
  85. package/dist/TxReentrantLock.js +504 -0
  86. package/dist/TxReentrantLock.js.map +1 -0
  87. package/dist/TxRef.d.ts +34 -34
  88. package/dist/TxRef.d.ts.map +1 -1
  89. package/dist/TxRef.js +21 -14
  90. package/dist/TxRef.js.map +1 -1
  91. package/dist/TxSemaphore.d.ts +8 -8
  92. package/dist/TxSemaphore.d.ts.map +1 -1
  93. package/dist/TxSemaphore.js +7 -7
  94. package/dist/TxSemaphore.js.map +1 -1
  95. package/dist/TxSubscriptionRef.d.ts +508 -0
  96. package/dist/TxSubscriptionRef.d.ts.map +1 -0
  97. package/dist/TxSubscriptionRef.js +293 -0
  98. package/dist/TxSubscriptionRef.js.map +1 -0
  99. package/dist/index.d.ts +40 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +40 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/internal/effect.js +99 -42
  104. package/dist/internal/effect.js.map +1 -1
  105. package/dist/internal/hashMap.js +3 -2
  106. package/dist/internal/hashMap.js.map +1 -1
  107. package/dist/internal/trie.js +5 -4
  108. package/dist/internal/trie.js.map +1 -1
  109. package/dist/unstable/ai/Tool.d.ts.map +1 -1
  110. package/dist/unstable/ai/Tool.js +0 -9
  111. package/dist/unstable/ai/Tool.js.map +1 -1
  112. package/dist/unstable/cli/Command.d.ts +1 -1
  113. package/dist/unstable/cli/Command.d.ts.map +1 -1
  114. package/dist/unstable/cli/Command.js +1 -1
  115. package/dist/unstable/cli/Command.js.map +1 -1
  116. package/dist/unstable/cluster/K8sHttpClient.js +4 -4
  117. package/dist/unstable/cluster/K8sHttpClient.js.map +1 -1
  118. package/dist/unstable/cluster/Sharding.js +1 -1
  119. package/dist/unstable/cluster/Sharding.js.map +1 -1
  120. package/dist/unstable/encoding/Sse.js +1 -1
  121. package/dist/unstable/encoding/Sse.js.map +1 -1
  122. package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
  123. package/dist/unstable/rpc/RpcServer.js +1 -2
  124. package/dist/unstable/rpc/RpcServer.js.map +1 -1
  125. package/dist/unstable/socket/Socket.d.ts.map +1 -1
  126. package/dist/unstable/socket/Socket.js +3 -3
  127. package/dist/unstable/socket/Socket.js.map +1 -1
  128. package/package.json +1 -1
  129. package/src/Array.ts +190 -342
  130. package/src/Cache.ts +6 -5
  131. package/src/Channel.ts +506 -102
  132. package/src/Chunk.ts +81 -268
  133. package/src/Effect.ts +437 -518
  134. package/src/Filter.ts +0 -57
  135. package/src/HashMap.ts +15 -14
  136. package/src/Iterable.ts +105 -50
  137. package/src/Option.ts +30 -20
  138. package/src/Pull.ts +1 -1
  139. package/src/Record.ts +43 -152
  140. package/src/Sink.ts +75 -23
  141. package/src/Stream.ts +442 -502
  142. package/src/Trie.ts +18 -17
  143. package/src/TxChunk.ts +72 -53
  144. package/src/TxDeferred.ts +394 -0
  145. package/src/TxHashMap.ts +332 -285
  146. package/src/TxHashSet.ts +111 -116
  147. package/src/TxPriorityQueue.ts +767 -0
  148. package/src/TxPubSub.ts +789 -0
  149. package/src/TxQueue.ts +241 -251
  150. package/src/TxReentrantLock.ts +753 -0
  151. package/src/TxRef.ts +50 -38
  152. package/src/TxSemaphore.ts +29 -32
  153. package/src/TxSubscriptionRef.ts +639 -0
  154. package/src/index.ts +45 -0
  155. package/src/internal/effect.ts +368 -163
  156. package/src/internal/hashMap.ts +7 -5
  157. package/src/internal/trie.ts +16 -9
  158. package/src/unstable/ai/Tool.ts +0 -9
  159. package/src/unstable/cli/Command.ts +6 -4
  160. package/src/unstable/cluster/K8sHttpClient.ts +4 -4
  161. package/src/unstable/cluster/Sharding.ts +1 -1
  162. package/src/unstable/encoding/Sse.ts +1 -1
  163. package/src/unstable/rpc/RpcServer.ts +1 -7
  164. package/src/unstable/socket/Socket.ts +9 -11
@@ -0,0 +1,753 @@
1
+ /**
2
+ * TxReentrantLock is a transactional read/write lock with reentrant semantics using Software
3
+ * Transactional Memory (STM). Multiple readers can hold the lock concurrently, OR a single
4
+ * writer can hold exclusive access. A fiber holding a write lock may acquire additional
5
+ * read or write locks (reentrancy).
6
+ *
7
+ * @since 4.0.0
8
+ */
9
+ import * as Effect from "./Effect.ts"
10
+ import * as HashMap from "./HashMap.ts"
11
+ import type { Inspectable } from "./Inspectable.ts"
12
+ import { NodeInspectSymbol, toJson } from "./Inspectable.ts"
13
+ import * as Option from "./Option.ts"
14
+ import type { Pipeable } from "./Pipeable.ts"
15
+ import { pipeArguments } from "./Pipeable.ts"
16
+ import { hasProperty } from "./Predicate.ts"
17
+ import type * as Scope from "./Scope.ts"
18
+ import * as TxRef from "./TxRef.ts"
19
+
20
+ const TypeId = "~effect/transactions/TxReentrantLock"
21
+
22
+ /**
23
+ * @since 4.0.0
24
+ * @category models
25
+ */
26
+ interface LockState {
27
+ readonly readers: HashMap.HashMap<number, number>
28
+ readonly writer: Option.Option<readonly [fiberId: number, count: number]>
29
+ }
30
+
31
+ const emptyState: LockState = {
32
+ readers: HashMap.empty<number, number>(),
33
+ writer: Option.none()
34
+ }
35
+
36
+ /**
37
+ * A TxReentrantLock provides a transactional read/write lock with reentrant semantics.
38
+ * Multiple readers can hold the lock concurrently, or a single writer can hold exclusive
39
+ * access. A fiber holding the write lock may acquire additional read/write locks (reentrancy).
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { Effect, TxReentrantLock } from "effect"
44
+ *
45
+ * const program = Effect.gen(function*() {
46
+ * const lock = yield* TxReentrantLock.make()
47
+ *
48
+ * // Multiple readers can proceed concurrently
49
+ * yield* TxReentrantLock.withReadLock(lock, Effect.succeed("reading"))
50
+ *
51
+ * // Writer gets exclusive access
52
+ * yield* TxReentrantLock.withWriteLock(lock, Effect.succeed("writing"))
53
+ * })
54
+ * ```
55
+ *
56
+ * @since 4.0.0
57
+ * @category models
58
+ */
59
+ export interface TxReentrantLock extends Inspectable, Pipeable {
60
+ readonly [TypeId]: typeof TypeId
61
+ /** @internal */
62
+ readonly stateRef: TxRef.TxRef<LockState>
63
+ }
64
+
65
+ const TxReentrantLockProto: Omit<TxReentrantLock, typeof TypeId | "stateRef"> = {
66
+ [NodeInspectSymbol](this: TxReentrantLock) {
67
+ return toJson(this)
68
+ },
69
+ toJSON(this: TxReentrantLock) {
70
+ return { _id: "TxReentrantLock" }
71
+ },
72
+ toString() {
73
+ return "TxReentrantLock"
74
+ },
75
+ pipe() {
76
+ return pipeArguments(this, arguments)
77
+ }
78
+ }
79
+
80
+ // =============================================================================
81
+ // Constructors
82
+ // =============================================================================
83
+
84
+ /**
85
+ * Creates a new TxReentrantLock.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * import { Effect, TxReentrantLock } from "effect"
90
+ *
91
+ * const program = Effect.gen(function*() {
92
+ * const lock = yield* TxReentrantLock.make()
93
+ * const isLocked = yield* TxReentrantLock.locked(lock)
94
+ * console.log(isLocked) // false
95
+ * })
96
+ * ```
97
+ *
98
+ * @since 4.0.0
99
+ * @category constructors
100
+ */
101
+ export const make = (): Effect.Effect<TxReentrantLock, never, Effect.Transaction> =>
102
+ Effect.gen(function*() {
103
+ const stateRef = yield* TxRef.make<LockState>(emptyState)
104
+ const self = Object.create(TxReentrantLockProto)
105
+ self[TypeId] = TypeId
106
+ self.stateRef = stateRef
107
+ return self
108
+ })
109
+
110
+ // =============================================================================
111
+ // Mutations
112
+ // =============================================================================
113
+
114
+ /**
115
+ * Acquires a read lock. Blocks if another fiber holds the write lock.
116
+ * If the current fiber already holds the write lock, the read lock is granted (reentrancy).
117
+ * Returns the current number of read locks held by this fiber.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { Effect, TxReentrantLock } from "effect"
122
+ *
123
+ * const program = Effect.gen(function*() {
124
+ * const lock = yield* TxReentrantLock.make()
125
+ * const count = yield* TxReentrantLock.acquireRead(lock)
126
+ * console.log(count) // 1
127
+ * yield* TxReentrantLock.releaseRead(lock)
128
+ * })
129
+ * ```
130
+ *
131
+ * @since 4.0.0
132
+ * @category mutations
133
+ */
134
+ export const acquireRead = (self: TxReentrantLock): Effect.Effect<number, never, Effect.Transaction> =>
135
+ Effect.withFiber((fiber) =>
136
+ Effect.gen(function*() {
137
+ const state = yield* TxRef.get(self.stateRef)
138
+ const fiberId = fiber.id
139
+
140
+ // If another fiber holds the write lock, retry
141
+ if (Option.isSome(state.writer) && state.writer.value[0] !== fiberId) {
142
+ return yield* Effect.retryTransaction
143
+ }
144
+
145
+ // Grant read lock
146
+ const currentCount = Option.getOrElse(HashMap.get(state.readers, fiberId), () => 0)
147
+ const newCount = currentCount + 1
148
+ yield* TxRef.set(self.stateRef, {
149
+ ...state,
150
+ readers: HashMap.set(state.readers, fiberId, newCount)
151
+ })
152
+ return newCount
153
+ })
154
+ )
155
+
156
+ /**
157
+ * Acquires a write lock. Blocks if any other fiber holds any lock.
158
+ * If the current fiber already holds the write lock, the count is incremented (reentrancy).
159
+ * If the current fiber holds a read lock, the write lock is granted (upgrade).
160
+ * Returns the current number of write locks held by this fiber.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * import { Effect, TxReentrantLock } from "effect"
165
+ *
166
+ * const program = Effect.gen(function*() {
167
+ * const lock = yield* TxReentrantLock.make()
168
+ * const count = yield* TxReentrantLock.acquireWrite(lock)
169
+ * console.log(count) // 1
170
+ * yield* TxReentrantLock.releaseWrite(lock)
171
+ * })
172
+ * ```
173
+ *
174
+ * @since 4.0.0
175
+ * @category mutations
176
+ */
177
+ export const acquireWrite = (self: TxReentrantLock): Effect.Effect<number, never, Effect.Transaction> =>
178
+ Effect.withFiber((fiber) =>
179
+ Effect.gen(function*() {
180
+ const state = yield* TxRef.get(self.stateRef)
181
+ const fiberId = fiber.id
182
+
183
+ // If another fiber holds the write lock, retry
184
+ if (Option.isSome(state.writer) && state.writer.value[0] !== fiberId) {
185
+ return yield* Effect.retryTransaction
186
+ }
187
+
188
+ // If other fibers hold read locks, retry
189
+ for (const [readerId] of state.readers) {
190
+ if (readerId !== fiberId && Option.getOrElse(HashMap.get(state.readers, readerId), () => 0) > 0) {
191
+ return yield* Effect.retryTransaction
192
+ }
193
+ }
194
+
195
+ // Grant write lock
196
+ if (Option.isSome(state.writer)) {
197
+ // Reentrant: increment write count
198
+ const newCount = state.writer.value[1] + 1
199
+ yield* TxRef.set(self.stateRef, {
200
+ ...state,
201
+ writer: Option.some([fiberId, newCount] as const)
202
+ })
203
+ return newCount
204
+ }
205
+
206
+ // First write lock acquisition
207
+ yield* TxRef.set(self.stateRef, {
208
+ ...state,
209
+ writer: Option.some([fiberId, 1] as const)
210
+ })
211
+ return 1
212
+ })
213
+ )
214
+
215
+ /**
216
+ * Releases a read lock held by the current fiber.
217
+ * Returns the remaining number of read locks held by this fiber.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * import { Effect, TxReentrantLock } from "effect"
222
+ *
223
+ * const program = Effect.gen(function*() {
224
+ * const lock = yield* TxReentrantLock.make()
225
+ * yield* TxReentrantLock.acquireRead(lock)
226
+ * const remaining = yield* TxReentrantLock.releaseRead(lock)
227
+ * console.log(remaining) // 0
228
+ * })
229
+ * ```
230
+ *
231
+ * @since 4.0.0
232
+ * @category mutations
233
+ */
234
+ export const releaseRead = (self: TxReentrantLock): Effect.Effect<number, never, Effect.Transaction> =>
235
+ Effect.withFiber((fiber) =>
236
+ Effect.gen(function*() {
237
+ const state = yield* TxRef.get(self.stateRef)
238
+ const fiberId = fiber.id
239
+ const currentCount = Option.getOrElse(HashMap.get(state.readers, fiberId), () => 0)
240
+
241
+ if (currentCount <= 0) return 0
242
+
243
+ const newCount = currentCount - 1
244
+ const newReaders = newCount === 0
245
+ ? HashMap.remove(state.readers, fiberId)
246
+ : HashMap.set(state.readers, fiberId, newCount)
247
+
248
+ yield* TxRef.set(self.stateRef, { ...state, readers: newReaders })
249
+ return newCount
250
+ })
251
+ )
252
+
253
+ /**
254
+ * Releases a write lock held by the current fiber.
255
+ * Returns the remaining number of write locks held by this fiber.
256
+ *
257
+ * @example
258
+ * ```ts
259
+ * import { Effect, TxReentrantLock } from "effect"
260
+ *
261
+ * const program = Effect.gen(function*() {
262
+ * const lock = yield* TxReentrantLock.make()
263
+ * yield* TxReentrantLock.acquireWrite(lock)
264
+ * const remaining = yield* TxReentrantLock.releaseWrite(lock)
265
+ * console.log(remaining) // 0
266
+ * })
267
+ * ```
268
+ *
269
+ * @since 4.0.0
270
+ * @category mutations
271
+ */
272
+ export const releaseWrite = (self: TxReentrantLock): Effect.Effect<number, never, Effect.Transaction> =>
273
+ Effect.withFiber((fiber) =>
274
+ Effect.gen(function*() {
275
+ const state = yield* TxRef.get(self.stateRef)
276
+ const fiberId = fiber.id
277
+
278
+ if (Option.isNone(state.writer) || state.writer.value[0] !== fiberId) return 0
279
+
280
+ const newCount = state.writer.value[1] - 1
281
+ const newWriter = newCount <= 0
282
+ ? Option.none<readonly [number, number]>()
283
+ : Option.some([fiberId, newCount] as const)
284
+
285
+ yield* TxRef.set(self.stateRef, { ...state, writer: newWriter })
286
+ return newCount
287
+ })
288
+ )
289
+
290
+ /**
291
+ * Acquires a read lock for the duration of the scope.
292
+ * The lock is automatically released when the scope closes.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * import { Effect, TxReentrantLock } from "effect"
297
+ *
298
+ * const program = Effect.gen(function*() {
299
+ * const lock = yield* TxReentrantLock.make()
300
+ *
301
+ * yield* Effect.scoped(
302
+ * Effect.gen(function*() {
303
+ * yield* TxReentrantLock.readLock(lock)
304
+ * // read lock is held for the duration of the scope
305
+ * })
306
+ * )
307
+ * // read lock is released
308
+ * })
309
+ * ```
310
+ *
311
+ * @since 4.0.0
312
+ * @category mutations
313
+ */
314
+ export const readLock = (self: TxReentrantLock): Effect.Effect<number, never, Scope.Scope> =>
315
+ Effect.acquireRelease(
316
+ Effect.transaction(acquireRead(self)),
317
+ () => Effect.transaction(releaseRead(self))
318
+ )
319
+
320
+ /**
321
+ * Acquires a write lock for the duration of the scope.
322
+ * The lock is automatically released when the scope closes.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * import { Effect, TxReentrantLock } from "effect"
327
+ *
328
+ * const program = Effect.gen(function*() {
329
+ * const lock = yield* TxReentrantLock.make()
330
+ *
331
+ * yield* Effect.scoped(
332
+ * Effect.gen(function*() {
333
+ * yield* TxReentrantLock.writeLock(lock)
334
+ * // write lock is held for the duration of the scope
335
+ * })
336
+ * )
337
+ * // write lock is released
338
+ * })
339
+ * ```
340
+ *
341
+ * @since 4.0.0
342
+ * @category mutations
343
+ */
344
+ export const writeLock = (self: TxReentrantLock): Effect.Effect<number, never, Scope.Scope> =>
345
+ Effect.acquireRelease(
346
+ Effect.transaction(acquireWrite(self)),
347
+ () => Effect.transaction(releaseWrite(self))
348
+ )
349
+
350
+ /**
351
+ * Alias for `writeLock`. Acquires a write lock for the duration of the scope.
352
+ *
353
+ * @example
354
+ * ```ts
355
+ * import { Effect, TxReentrantLock } from "effect"
356
+ *
357
+ * const program = Effect.gen(function*() {
358
+ * const lock = yield* TxReentrantLock.make()
359
+ *
360
+ * yield* Effect.scoped(
361
+ * Effect.gen(function*() {
362
+ * yield* TxReentrantLock.lock(lock)
363
+ * // exclusive lock is held
364
+ * })
365
+ * )
366
+ * })
367
+ * ```
368
+ *
369
+ * @since 4.0.0
370
+ * @category mutations
371
+ */
372
+ export const lock = writeLock
373
+
374
+ /**
375
+ * Runs the provided effect while holding a read lock. The lock is automatically
376
+ * released after the effect completes, fails, or is interrupted.
377
+ *
378
+ * @example
379
+ * ```ts
380
+ * import { Effect, TxReentrantLock } from "effect"
381
+ *
382
+ * const program = Effect.gen(function*() {
383
+ * const lock = yield* TxReentrantLock.make()
384
+ * const result = yield* TxReentrantLock.withReadLock(
385
+ * lock,
386
+ * Effect.succeed("read data")
387
+ * )
388
+ * console.log(result) // "read data"
389
+ * })
390
+ * ```
391
+ *
392
+ * @since 4.0.0
393
+ * @category mutations
394
+ */
395
+ export const withReadLock: {
396
+ /**
397
+ * Runs the provided effect while holding a read lock. The lock is automatically
398
+ * released after the effect completes, fails, or is interrupted.
399
+ *
400
+ * @example
401
+ * ```ts
402
+ * import { Effect, TxReentrantLock } from "effect"
403
+ *
404
+ * const program = Effect.gen(function*() {
405
+ * const lock = yield* TxReentrantLock.make()
406
+ * const result = yield* TxReentrantLock.withReadLock(
407
+ * lock,
408
+ * Effect.succeed("read data")
409
+ * )
410
+ * console.log(result) // "read data"
411
+ * })
412
+ * ```
413
+ *
414
+ * @since 4.0.0
415
+ * @category mutations
416
+ */
417
+ <A, E, R>(effect: Effect.Effect<A, E, R>): (self: TxReentrantLock) => Effect.Effect<A, E, R>
418
+ /**
419
+ * Runs the provided effect while holding a read lock. The lock is automatically
420
+ * released after the effect completes, fails, or is interrupted.
421
+ *
422
+ * @example
423
+ * ```ts
424
+ * import { Effect, TxReentrantLock } from "effect"
425
+ *
426
+ * const program = Effect.gen(function*() {
427
+ * const lock = yield* TxReentrantLock.make()
428
+ * const result = yield* TxReentrantLock.withReadLock(
429
+ * lock,
430
+ * Effect.succeed("read data")
431
+ * )
432
+ * console.log(result) // "read data"
433
+ * })
434
+ * ```
435
+ *
436
+ * @since 4.0.0
437
+ * @category mutations
438
+ */
439
+ <A, E, R>(self: TxReentrantLock, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
440
+ } = ((...args: Array<any>) => {
441
+ if (args.length === 1) {
442
+ const [effect] = args
443
+ return (self: TxReentrantLock) =>
444
+ Effect.acquireUseRelease(
445
+ Effect.transaction(acquireRead(self)),
446
+ () => effect,
447
+ () => Effect.transaction(releaseRead(self))
448
+ )
449
+ }
450
+ const [self, effect] = args
451
+ return Effect.acquireUseRelease(
452
+ Effect.transaction(acquireRead(self)),
453
+ () => effect,
454
+ () => Effect.transaction(releaseRead(self))
455
+ )
456
+ }) as any
457
+
458
+ /**
459
+ * Runs the provided effect while holding a write lock. The lock is automatically
460
+ * released after the effect completes, fails, or is interrupted.
461
+ *
462
+ * @example
463
+ * ```ts
464
+ * import { Effect, TxReentrantLock } from "effect"
465
+ *
466
+ * const program = Effect.gen(function*() {
467
+ * const lock = yield* TxReentrantLock.make()
468
+ * const result = yield* TxReentrantLock.withWriteLock(
469
+ * lock,
470
+ * Effect.succeed("wrote data")
471
+ * )
472
+ * console.log(result) // "wrote data"
473
+ * })
474
+ * ```
475
+ *
476
+ * @since 4.0.0
477
+ * @category mutations
478
+ */
479
+ export const withWriteLock: {
480
+ /**
481
+ * Runs the provided effect while holding a write lock. The lock is automatically
482
+ * released after the effect completes, fails, or is interrupted.
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * import { Effect, TxReentrantLock } from "effect"
487
+ *
488
+ * const program = Effect.gen(function*() {
489
+ * const lock = yield* TxReentrantLock.make()
490
+ * const result = yield* TxReentrantLock.withWriteLock(
491
+ * lock,
492
+ * Effect.succeed("wrote data")
493
+ * )
494
+ * console.log(result) // "wrote data"
495
+ * })
496
+ * ```
497
+ *
498
+ * @since 4.0.0
499
+ * @category mutations
500
+ */
501
+ <A, E, R>(effect: Effect.Effect<A, E, R>): (self: TxReentrantLock) => Effect.Effect<A, E, R>
502
+ /**
503
+ * Runs the provided effect while holding a write lock. The lock is automatically
504
+ * released after the effect completes, fails, or is interrupted.
505
+ *
506
+ * @example
507
+ * ```ts
508
+ * import { Effect, TxReentrantLock } from "effect"
509
+ *
510
+ * const program = Effect.gen(function*() {
511
+ * const lock = yield* TxReentrantLock.make()
512
+ * const result = yield* TxReentrantLock.withWriteLock(
513
+ * lock,
514
+ * Effect.succeed("wrote data")
515
+ * )
516
+ * console.log(result) // "wrote data"
517
+ * })
518
+ * ```
519
+ *
520
+ * @since 4.0.0
521
+ * @category mutations
522
+ */
523
+ <A, E, R>(self: TxReentrantLock, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
524
+ } = ((...args: Array<any>) => {
525
+ if (args.length === 1) {
526
+ const [effect] = args
527
+ return (self: TxReentrantLock) =>
528
+ Effect.acquireUseRelease(
529
+ Effect.transaction(acquireWrite(self)),
530
+ () => effect,
531
+ () => Effect.transaction(releaseWrite(self))
532
+ )
533
+ }
534
+ const [self, effect] = args
535
+ return Effect.acquireUseRelease(
536
+ Effect.transaction(acquireWrite(self)),
537
+ () => effect,
538
+ () => Effect.transaction(releaseWrite(self))
539
+ )
540
+ }) as any
541
+
542
+ /**
543
+ * Alias for `withWriteLock`. Runs the provided effect while holding a write lock.
544
+ *
545
+ * @example
546
+ * ```ts
547
+ * import { Effect, TxReentrantLock } from "effect"
548
+ *
549
+ * const program = Effect.gen(function*() {
550
+ * const lock = yield* TxReentrantLock.make()
551
+ * const result = yield* TxReentrantLock.withLock(
552
+ * lock,
553
+ * Effect.succeed("exclusive operation")
554
+ * )
555
+ * console.log(result) // "exclusive operation"
556
+ * })
557
+ * ```
558
+ *
559
+ * @since 4.0.0
560
+ * @category mutations
561
+ */
562
+ export const withLock: {
563
+ /**
564
+ * Alias for `withWriteLock`. Runs the provided effect while holding a write lock.
565
+ *
566
+ * @example
567
+ * ```ts
568
+ * import { Effect, TxReentrantLock } from "effect"
569
+ *
570
+ * const program = Effect.gen(function*() {
571
+ * const lock = yield* TxReentrantLock.make()
572
+ * const result = yield* TxReentrantLock.withLock(
573
+ * lock,
574
+ * Effect.succeed("exclusive operation")
575
+ * )
576
+ * console.log(result) // "exclusive operation"
577
+ * })
578
+ * ```
579
+ *
580
+ * @since 4.0.0
581
+ * @category mutations
582
+ */
583
+ <A, E, R>(effect: Effect.Effect<A, E, R>): (self: TxReentrantLock) => Effect.Effect<A, E, R>
584
+ /**
585
+ * Alias for `withWriteLock`. Runs the provided effect while holding a write lock.
586
+ *
587
+ * @example
588
+ * ```ts
589
+ * import { Effect, TxReentrantLock } from "effect"
590
+ *
591
+ * const program = Effect.gen(function*() {
592
+ * const lock = yield* TxReentrantLock.make()
593
+ * const result = yield* TxReentrantLock.withLock(
594
+ * lock,
595
+ * Effect.succeed("exclusive operation")
596
+ * )
597
+ * console.log(result) // "exclusive operation"
598
+ * })
599
+ * ```
600
+ *
601
+ * @since 4.0.0
602
+ * @category mutations
603
+ */
604
+ <A, E, R>(self: TxReentrantLock, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
605
+ } = withWriteLock
606
+
607
+ // =============================================================================
608
+ // Getters
609
+ // =============================================================================
610
+
611
+ /**
612
+ * Returns the total number of read locks held across all fibers.
613
+ *
614
+ * @example
615
+ * ```ts
616
+ * import { Effect, TxReentrantLock } from "effect"
617
+ *
618
+ * const program = Effect.gen(function*() {
619
+ * const lock = yield* TxReentrantLock.make()
620
+ * yield* TxReentrantLock.acquireRead(lock)
621
+ * const count = yield* TxReentrantLock.readLocks(lock)
622
+ * console.log(count) // 1
623
+ * yield* TxReentrantLock.releaseRead(lock)
624
+ * })
625
+ * ```
626
+ *
627
+ * @since 4.0.0
628
+ * @category getters
629
+ */
630
+ export const readLocks = (self: TxReentrantLock): Effect.Effect<number, never, Effect.Transaction> =>
631
+ Effect.gen(function*() {
632
+ const state = yield* TxRef.get(self.stateRef)
633
+ let total = 0
634
+ for (const [, count] of state.readers) {
635
+ total += count
636
+ }
637
+ return total
638
+ })
639
+
640
+ /**
641
+ * Returns the number of write locks held (0 or the reentrant count).
642
+ *
643
+ * @example
644
+ * ```ts
645
+ * import { Effect, TxReentrantLock } from "effect"
646
+ *
647
+ * const program = Effect.gen(function*() {
648
+ * const lock = yield* TxReentrantLock.make()
649
+ * const count = yield* TxReentrantLock.writeLocks(lock)
650
+ * console.log(count) // 0
651
+ * })
652
+ * ```
653
+ *
654
+ * @since 4.0.0
655
+ * @category getters
656
+ */
657
+ export const writeLocks = (self: TxReentrantLock): Effect.Effect<number, never, Effect.Transaction> =>
658
+ Effect.gen(function*() {
659
+ const state = yield* TxRef.get(self.stateRef)
660
+ return Option.isSome(state.writer) ? state.writer.value[1] : 0
661
+ })
662
+
663
+ /**
664
+ * Checks if the lock is held by any fiber (read or write).
665
+ *
666
+ * @example
667
+ * ```ts
668
+ * import { Effect, TxReentrantLock } from "effect"
669
+ *
670
+ * const program = Effect.gen(function*() {
671
+ * const lock = yield* TxReentrantLock.make()
672
+ * const isLocked = yield* TxReentrantLock.locked(lock)
673
+ * console.log(isLocked) // false
674
+ * })
675
+ * ```
676
+ *
677
+ * @since 4.0.0
678
+ * @category getters
679
+ */
680
+ export const locked = (self: TxReentrantLock): Effect.Effect<boolean, never, Effect.Transaction> =>
681
+ Effect.gen(function*() {
682
+ const state = yield* TxRef.get(self.stateRef)
683
+ return HashMap.size(state.readers) > 0 || Option.isSome(state.writer)
684
+ })
685
+
686
+ /**
687
+ * Checks if any fiber holds a read lock.
688
+ *
689
+ * @example
690
+ * ```ts
691
+ * import { Effect, TxReentrantLock } from "effect"
692
+ *
693
+ * const program = Effect.gen(function*() {
694
+ * const lock = yield* TxReentrantLock.make()
695
+ * const isReadLocked = yield* TxReentrantLock.readLocked(lock)
696
+ * console.log(isReadLocked) // false
697
+ * })
698
+ * ```
699
+ *
700
+ * @since 4.0.0
701
+ * @category getters
702
+ */
703
+ export const readLocked = (self: TxReentrantLock): Effect.Effect<boolean, never, Effect.Transaction> =>
704
+ Effect.gen(function*() {
705
+ const state = yield* TxRef.get(self.stateRef)
706
+ return HashMap.size(state.readers) > 0
707
+ })
708
+
709
+ /**
710
+ * Checks if any fiber holds a write lock.
711
+ *
712
+ * @example
713
+ * ```ts
714
+ * import { Effect, TxReentrantLock } from "effect"
715
+ *
716
+ * const program = Effect.gen(function*() {
717
+ * const lock = yield* TxReentrantLock.make()
718
+ * const isWriteLocked = yield* TxReentrantLock.writeLocked(lock)
719
+ * console.log(isWriteLocked) // false
720
+ * })
721
+ * ```
722
+ *
723
+ * @since 4.0.0
724
+ * @category getters
725
+ */
726
+ export const writeLocked = (self: TxReentrantLock): Effect.Effect<boolean, never, Effect.Transaction> =>
727
+ Effect.gen(function*() {
728
+ const state = yield* TxRef.get(self.stateRef)
729
+ return Option.isSome(state.writer)
730
+ })
731
+
732
+ // =============================================================================
733
+ // Guards
734
+ // =============================================================================
735
+
736
+ /**
737
+ * Checks if the given value is a TxReentrantLock.
738
+ *
739
+ * @example
740
+ * ```ts
741
+ * import { TxReentrantLock } from "effect"
742
+ *
743
+ * declare const someValue: unknown
744
+ *
745
+ * if (TxReentrantLock.isTxReentrantLock(someValue)) {
746
+ * console.log("This is a TxReentrantLock")
747
+ * }
748
+ * ```
749
+ *
750
+ * @since 4.0.0
751
+ * @category guards
752
+ */
753
+ export const isTxReentrantLock = (u: unknown): u is TxReentrantLock => hasProperty(u, TypeId)