@typed/fx 1.13.0 → 1.15.0

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 (398) hide show
  1. package/dist/Computed.d.ts +42 -0
  2. package/dist/Computed.d.ts.map +1 -0
  3. package/dist/Computed.js +39 -0
  4. package/dist/Computed.js.map +1 -0
  5. package/dist/Filtered.d.ts +34 -0
  6. package/dist/Filtered.d.ts.map +1 -0
  7. package/dist/Filtered.js +40 -0
  8. package/dist/Filtered.js.map +1 -0
  9. package/dist/Fx.d.ts +2 -3
  10. package/dist/Fx.d.ts.map +1 -1
  11. package/dist/Fx.js +11 -26
  12. package/dist/Fx.js.map +1 -1
  13. package/dist/RefArray.d.ts +116 -0
  14. package/dist/RefArray.d.ts.map +1 -0
  15. package/dist/RefArray.js +67 -0
  16. package/dist/RefArray.js.map +1 -0
  17. package/dist/RefSubject.d.ts +23 -20
  18. package/dist/RefSubject.d.ts.map +1 -1
  19. package/dist/RefSubject.js +352 -247
  20. package/dist/RefSubject.js.map +1 -1
  21. package/dist/RefTransform.d.ts +51 -0
  22. package/dist/RefTransform.d.ts.map +1 -0
  23. package/dist/RefTransform.js +69 -0
  24. package/dist/RefTransform.js.map +1 -0
  25. package/dist/Subject.d.ts.map +1 -1
  26. package/dist/Subject.js +2 -3
  27. package/dist/Subject.js.map +1 -1
  28. package/dist/catchAllCause.d.ts +6 -0
  29. package/dist/catchAllCause.d.ts.map +1 -1
  30. package/dist/catchAllCause.js +21 -2
  31. package/dist/catchAllCause.js.map +1 -1
  32. package/dist/cjs/Computed.d.ts +42 -0
  33. package/dist/cjs/Computed.d.ts.map +1 -0
  34. package/dist/cjs/Computed.js +66 -0
  35. package/dist/cjs/Computed.js.map +1 -0
  36. package/dist/cjs/Filtered.d.ts +34 -0
  37. package/dist/cjs/Filtered.d.ts.map +1 -0
  38. package/dist/cjs/Filtered.js +67 -0
  39. package/dist/cjs/Filtered.js.map +1 -0
  40. package/dist/cjs/Fx.d.ts +2 -3
  41. package/dist/cjs/Fx.d.ts.map +1 -1
  42. package/dist/cjs/Fx.js +13 -28
  43. package/dist/cjs/Fx.js.map +1 -1
  44. package/dist/cjs/RefArray.d.ts +116 -0
  45. package/dist/cjs/RefArray.d.ts.map +1 -0
  46. package/dist/cjs/RefArray.js +97 -0
  47. package/dist/cjs/RefArray.js.map +1 -0
  48. package/dist/cjs/RefSubject.d.ts +23 -20
  49. package/dist/cjs/RefSubject.d.ts.map +1 -1
  50. package/dist/cjs/RefSubject.js +358 -249
  51. package/dist/cjs/RefSubject.js.map +1 -1
  52. package/dist/cjs/RefTransform.d.ts +51 -0
  53. package/dist/cjs/RefTransform.d.ts.map +1 -0
  54. package/dist/cjs/RefTransform.js +96 -0
  55. package/dist/cjs/RefTransform.js.map +1 -0
  56. package/dist/cjs/Subject.d.ts.map +1 -1
  57. package/dist/cjs/Subject.js +2 -3
  58. package/dist/cjs/Subject.js.map +1 -1
  59. package/dist/cjs/catchAllCause.d.ts +6 -0
  60. package/dist/cjs/catchAllCause.d.ts.map +1 -1
  61. package/dist/cjs/catchAllCause.js +23 -2
  62. package/dist/cjs/catchAllCause.js.map +1 -1
  63. package/dist/cjs/combineAll.d.ts.map +1 -1
  64. package/dist/cjs/combineAll.js +4 -4
  65. package/dist/cjs/combineAll.js.map +1 -1
  66. package/dist/cjs/combineAllDiscard.d.ts.map +1 -1
  67. package/dist/cjs/combineAllDiscard.js +4 -4
  68. package/dist/cjs/combineAllDiscard.js.map +1 -1
  69. package/dist/cjs/data-first.d.ts +10 -0
  70. package/dist/cjs/data-first.d.ts.map +1 -1
  71. package/dist/cjs/data-first.js +10 -0
  72. package/dist/cjs/data-first.js.map +1 -1
  73. package/dist/cjs/empty.js +1 -1
  74. package/dist/cjs/empty.js.map +1 -1
  75. package/dist/cjs/exhaustMapCause.js +1 -1
  76. package/dist/cjs/exhaustMapCause.js.map +1 -1
  77. package/dist/cjs/exhaustMapLatestCause.js +1 -1
  78. package/dist/cjs/exhaustMapLatestCause.js.map +1 -1
  79. package/dist/cjs/failCause.d.ts +1 -0
  80. package/dist/cjs/failCause.d.ts.map +1 -1
  81. package/dist/cjs/failCause.js +5 -1
  82. package/dist/cjs/failCause.js.map +1 -1
  83. package/dist/cjs/filter.d.ts.map +1 -1
  84. package/dist/cjs/filter.js +1 -1
  85. package/dist/cjs/filter.js.map +1 -1
  86. package/dist/cjs/filterMap.d.ts.map +1 -1
  87. package/dist/cjs/filterMap.js +1 -1
  88. package/dist/cjs/filterMap.js.map +1 -1
  89. package/dist/cjs/fromArray.js +1 -1
  90. package/dist/cjs/fromArray.js.map +1 -1
  91. package/dist/cjs/fromDequeue.d.ts +5 -0
  92. package/dist/cjs/fromDequeue.d.ts.map +1 -0
  93. package/dist/cjs/fromDequeue.js +49 -0
  94. package/dist/cjs/fromDequeue.js.map +1 -0
  95. package/dist/cjs/fromEffect.d.ts.map +1 -1
  96. package/dist/cjs/fromEffect.js +9 -1
  97. package/dist/cjs/fromEffect.js.map +1 -1
  98. package/dist/cjs/fromEmitter.d.ts.map +1 -1
  99. package/dist/cjs/fromEmitter.js +4 -5
  100. package/dist/cjs/fromEmitter.js.map +1 -1
  101. package/dist/cjs/fromFxEffect.d.ts.map +1 -1
  102. package/dist/cjs/fromFxEffect.js +1 -1
  103. package/dist/cjs/fromFxEffect.js.map +1 -1
  104. package/dist/cjs/fromHub.d.ts +5 -0
  105. package/dist/cjs/fromHub.d.ts.map +1 -0
  106. package/dist/cjs/fromHub.js +34 -0
  107. package/dist/cjs/fromHub.js.map +1 -0
  108. package/dist/cjs/fromIterable.js +1 -1
  109. package/dist/cjs/fromIterable.js.map +1 -1
  110. package/dist/cjs/fromStream.d.ts +4 -0
  111. package/dist/cjs/fromStream.d.ts.map +1 -0
  112. package/dist/cjs/fromStream.js +34 -0
  113. package/dist/cjs/fromStream.js.map +1 -0
  114. package/dist/cjs/helpers.d.ts +3 -2
  115. package/dist/cjs/helpers.d.ts.map +1 -1
  116. package/dist/cjs/helpers.js +28 -69
  117. package/dist/cjs/helpers.js.map +1 -1
  118. package/dist/cjs/hold.d.ts +2 -4
  119. package/dist/cjs/hold.d.ts.map +1 -1
  120. package/dist/cjs/hold.js +0 -4
  121. package/dist/cjs/hold.js.map +1 -1
  122. package/dist/cjs/index.d.ts +36 -1
  123. package/dist/cjs/index.d.ts.map +1 -1
  124. package/dist/cjs/index.js +185 -119
  125. package/dist/cjs/index.js.map +1 -1
  126. package/dist/cjs/keyed.d.ts.map +1 -1
  127. package/dist/cjs/keyed.js +23 -12
  128. package/dist/cjs/keyed.js.map +1 -1
  129. package/dist/cjs/mergeAll.d.ts.map +1 -1
  130. package/dist/cjs/mergeAll.js +1 -1
  131. package/dist/cjs/mergeAll.js.map +1 -1
  132. package/dist/cjs/mergeBufferConcurrently.d.ts +8 -0
  133. package/dist/cjs/mergeBufferConcurrently.d.ts.map +1 -0
  134. package/dist/cjs/mergeBufferConcurrently.js +95 -0
  135. package/dist/cjs/mergeBufferConcurrently.js.map +1 -0
  136. package/dist/cjs/mergeConcurrently.d.ts +3 -0
  137. package/dist/cjs/mergeConcurrently.d.ts.map +1 -0
  138. package/dist/cjs/mergeConcurrently.js +69 -0
  139. package/dist/cjs/mergeConcurrently.js.map +1 -0
  140. package/dist/cjs/multicast.d.ts +5 -5
  141. package/dist/cjs/multicast.d.ts.map +1 -1
  142. package/dist/cjs/multicast.js +14 -14
  143. package/dist/cjs/multicast.js.map +1 -1
  144. package/dist/cjs/never.js +1 -1
  145. package/dist/cjs/never.js.map +1 -1
  146. package/dist/cjs/observe.d.ts +3 -0
  147. package/dist/cjs/observe.d.ts.map +1 -1
  148. package/dist/cjs/observe.js +12 -7
  149. package/dist/cjs/observe.js.map +1 -1
  150. package/dist/cjs/onExit.d.ts +5 -0
  151. package/dist/cjs/onExit.d.ts.map +1 -0
  152. package/dist/cjs/onExit.js +33 -0
  153. package/dist/cjs/onExit.js.map +1 -0
  154. package/dist/cjs/orElse.d.ts +4 -0
  155. package/dist/cjs/orElse.d.ts.map +1 -0
  156. package/dist/cjs/orElse.js +34 -0
  157. package/dist/cjs/orElse.js.map +1 -0
  158. package/dist/cjs/promise.js +4 -4
  159. package/dist/cjs/promise.js.map +1 -1
  160. package/dist/cjs/provide.d.ts.map +1 -1
  161. package/dist/cjs/provide.js +6 -3
  162. package/dist/cjs/provide.js.map +1 -1
  163. package/dist/cjs/skipRepeats.d.ts +1 -1
  164. package/dist/cjs/skipRepeats.d.ts.map +1 -1
  165. package/dist/cjs/skipRepeats.js +7 -6
  166. package/dist/cjs/skipRepeats.js.map +1 -1
  167. package/dist/cjs/skipWhile.js +1 -1
  168. package/dist/cjs/skipWhile.js.map +1 -1
  169. package/dist/cjs/slice.js +3 -3
  170. package/dist/cjs/slice.js.map +1 -1
  171. package/dist/cjs/struct.d.ts +5 -0
  172. package/dist/cjs/struct.d.ts.map +1 -0
  173. package/dist/cjs/struct.js +10 -0
  174. package/dist/cjs/struct.js.map +1 -0
  175. package/dist/cjs/switchMapCause.d.ts +1 -0
  176. package/dist/cjs/switchMapCause.d.ts.map +1 -1
  177. package/dist/cjs/switchMapCause.js +13 -2
  178. package/dist/cjs/switchMapCause.js.map +1 -1
  179. package/dist/cjs/switchMatch.js +1 -1
  180. package/dist/cjs/switchMatch.js.map +1 -1
  181. package/dist/cjs/takeWhile.js +1 -1
  182. package/dist/cjs/takeWhile.js.map +1 -1
  183. package/dist/cjs/tap.d.ts.map +1 -1
  184. package/dist/cjs/tap.js +1 -1
  185. package/dist/cjs/tap.js.map +1 -1
  186. package/dist/cjs/tapCause.d.ts.map +1 -1
  187. package/dist/cjs/tapCause.js +5 -2
  188. package/dist/cjs/tapCause.js.map +1 -1
  189. package/dist/cjs/test-utils.js +2 -2
  190. package/dist/cjs/test-utils.js.map +1 -1
  191. package/dist/cjs/toArray.d.ts.map +1 -1
  192. package/dist/cjs/toArray.js +2 -3
  193. package/dist/cjs/toArray.js.map +1 -1
  194. package/dist/cjs/toEnqueue.d.ts +6 -0
  195. package/dist/cjs/toEnqueue.d.ts.map +1 -0
  196. package/dist/cjs/toEnqueue.js +9 -0
  197. package/dist/cjs/toEnqueue.js.map +1 -0
  198. package/dist/cjs/toStream.d.ts +4 -0
  199. package/dist/cjs/toStream.d.ts.map +1 -0
  200. package/dist/cjs/toStream.js +35 -0
  201. package/dist/cjs/toStream.js.map +1 -0
  202. package/dist/combineAll.d.ts.map +1 -1
  203. package/dist/combineAll.js +4 -4
  204. package/dist/combineAll.js.map +1 -1
  205. package/dist/combineAllDiscard.d.ts.map +1 -1
  206. package/dist/combineAllDiscard.js +4 -4
  207. package/dist/combineAllDiscard.js.map +1 -1
  208. package/dist/data-first.d.ts +10 -0
  209. package/dist/data-first.d.ts.map +1 -1
  210. package/dist/data-first.js +10 -0
  211. package/dist/data-first.js.map +1 -1
  212. package/dist/empty.js +1 -1
  213. package/dist/empty.js.map +1 -1
  214. package/dist/exhaustMapCause.js +1 -1
  215. package/dist/exhaustMapCause.js.map +1 -1
  216. package/dist/exhaustMapLatestCause.js +1 -1
  217. package/dist/exhaustMapLatestCause.js.map +1 -1
  218. package/dist/failCause.d.ts +1 -0
  219. package/dist/failCause.d.ts.map +1 -1
  220. package/dist/failCause.js +3 -0
  221. package/dist/failCause.js.map +1 -1
  222. package/dist/filter.d.ts.map +1 -1
  223. package/dist/filter.js +1 -1
  224. package/dist/filter.js.map +1 -1
  225. package/dist/filterMap.d.ts.map +1 -1
  226. package/dist/filterMap.js +1 -1
  227. package/dist/filterMap.js.map +1 -1
  228. package/dist/fromArray.js +1 -1
  229. package/dist/fromArray.js.map +1 -1
  230. package/dist/fromDequeue.d.ts +5 -0
  231. package/dist/fromDequeue.d.ts.map +1 -0
  232. package/dist/fromDequeue.js +21 -0
  233. package/dist/fromDequeue.js.map +1 -0
  234. package/dist/fromEffect.d.ts.map +1 -1
  235. package/dist/fromEffect.js +10 -2
  236. package/dist/fromEffect.js.map +1 -1
  237. package/dist/fromEmitter.d.ts.map +1 -1
  238. package/dist/fromEmitter.js +4 -5
  239. package/dist/fromEmitter.js.map +1 -1
  240. package/dist/fromFxEffect.d.ts.map +1 -1
  241. package/dist/fromFxEffect.js +1 -1
  242. package/dist/fromFxEffect.js.map +1 -1
  243. package/dist/fromHub.d.ts +5 -0
  244. package/dist/fromHub.d.ts.map +1 -0
  245. package/dist/fromHub.js +7 -0
  246. package/dist/fromHub.js.map +1 -0
  247. package/dist/fromIterable.js +1 -1
  248. package/dist/fromIterable.js.map +1 -1
  249. package/dist/fromStream.d.ts +4 -0
  250. package/dist/fromStream.d.ts.map +1 -0
  251. package/dist/fromStream.js +7 -0
  252. package/dist/fromStream.js.map +1 -0
  253. package/dist/helpers.d.ts +3 -2
  254. package/dist/helpers.d.ts.map +1 -1
  255. package/dist/helpers.js +28 -69
  256. package/dist/helpers.js.map +1 -1
  257. package/dist/hold.d.ts +2 -4
  258. package/dist/hold.d.ts.map +1 -1
  259. package/dist/hold.js +0 -4
  260. package/dist/hold.js.map +1 -1
  261. package/dist/index.d.ts +36 -1
  262. package/dist/index.d.ts.map +1 -1
  263. package/dist/index.js +132 -116
  264. package/dist/index.js.map +1 -1
  265. package/dist/keyed.d.ts.map +1 -1
  266. package/dist/keyed.js +24 -13
  267. package/dist/keyed.js.map +1 -1
  268. package/dist/mergeAll.d.ts.map +1 -1
  269. package/dist/mergeAll.js +1 -1
  270. package/dist/mergeAll.js.map +1 -1
  271. package/dist/mergeBufferConcurrently.d.ts +8 -0
  272. package/dist/mergeBufferConcurrently.d.ts.map +1 -0
  273. package/dist/mergeBufferConcurrently.js +68 -0
  274. package/dist/mergeBufferConcurrently.js.map +1 -0
  275. package/dist/mergeConcurrently.d.ts +3 -0
  276. package/dist/mergeConcurrently.d.ts.map +1 -0
  277. package/dist/mergeConcurrently.js +42 -0
  278. package/dist/mergeConcurrently.js.map +1 -0
  279. package/dist/multicast.d.ts +5 -5
  280. package/dist/multicast.d.ts.map +1 -1
  281. package/dist/multicast.js +15 -15
  282. package/dist/multicast.js.map +1 -1
  283. package/dist/never.js +1 -1
  284. package/dist/never.js.map +1 -1
  285. package/dist/observe.d.ts +3 -0
  286. package/dist/observe.d.ts.map +1 -1
  287. package/dist/observe.js +9 -6
  288. package/dist/observe.js.map +1 -1
  289. package/dist/onExit.d.ts +5 -0
  290. package/dist/onExit.d.ts.map +1 -0
  291. package/dist/onExit.js +6 -0
  292. package/dist/onExit.js.map +1 -0
  293. package/dist/orElse.d.ts +4 -0
  294. package/dist/orElse.d.ts.map +1 -0
  295. package/dist/orElse.js +7 -0
  296. package/dist/orElse.js.map +1 -0
  297. package/dist/promise.js +4 -4
  298. package/dist/promise.js.map +1 -1
  299. package/dist/provide.d.ts.map +1 -1
  300. package/dist/provide.js +6 -3
  301. package/dist/provide.js.map +1 -1
  302. package/dist/skipRepeats.d.ts +1 -1
  303. package/dist/skipRepeats.d.ts.map +1 -1
  304. package/dist/skipRepeats.js +4 -6
  305. package/dist/skipRepeats.js.map +1 -1
  306. package/dist/skipWhile.js +1 -1
  307. package/dist/skipWhile.js.map +1 -1
  308. package/dist/slice.js +3 -3
  309. package/dist/slice.js.map +1 -1
  310. package/dist/struct.d.ts +5 -0
  311. package/dist/struct.d.ts.map +1 -0
  312. package/dist/struct.js +6 -0
  313. package/dist/struct.js.map +1 -0
  314. package/dist/switchMapCause.d.ts +1 -0
  315. package/dist/switchMapCause.d.ts.map +1 -1
  316. package/dist/switchMapCause.js +11 -1
  317. package/dist/switchMapCause.js.map +1 -1
  318. package/dist/switchMatch.js +1 -1
  319. package/dist/switchMatch.js.map +1 -1
  320. package/dist/takeWhile.js +1 -1
  321. package/dist/takeWhile.js.map +1 -1
  322. package/dist/tap.d.ts.map +1 -1
  323. package/dist/tap.js +1 -1
  324. package/dist/tap.js.map +1 -1
  325. package/dist/tapCause.d.ts.map +1 -1
  326. package/dist/tapCause.js +5 -2
  327. package/dist/tapCause.js.map +1 -1
  328. package/dist/test-utils.js +2 -2
  329. package/dist/test-utils.js.map +1 -1
  330. package/dist/toArray.d.ts.map +1 -1
  331. package/dist/toArray.js +2 -3
  332. package/dist/toArray.js.map +1 -1
  333. package/dist/toEnqueue.d.ts +6 -0
  334. package/dist/toEnqueue.d.ts.map +1 -0
  335. package/dist/toEnqueue.js +5 -0
  336. package/dist/toEnqueue.js.map +1 -0
  337. package/dist/toStream.d.ts +4 -0
  338. package/dist/toStream.d.ts.map +1 -0
  339. package/dist/toStream.js +8 -0
  340. package/dist/toStream.js.map +1 -0
  341. package/dist/tsconfig.cjs.build.tsbuildinfo +1 -1
  342. package/package.json +5 -5
  343. package/src/Computed.ts +114 -0
  344. package/src/Filtered.ts +112 -0
  345. package/src/Fx.ts +17 -42
  346. package/src/RefArray.ts +226 -0
  347. package/src/RefSubject.test.ts +67 -6
  348. package/src/RefSubject.ts +601 -581
  349. package/src/RefTransform.ts +134 -0
  350. package/src/Subject.ts +4 -13
  351. package/src/catchAllCause.ts +43 -2
  352. package/src/combineAll.ts +16 -13
  353. package/src/combineAllDiscard.ts +16 -13
  354. package/src/data-first.ts +10 -0
  355. package/src/empty.ts +1 -1
  356. package/src/exhaustMapCause.ts +1 -1
  357. package/src/exhaustMapLatestCause.ts +1 -1
  358. package/src/failCause.ts +4 -0
  359. package/src/filter.ts +1 -3
  360. package/src/filterMap.ts +8 -1
  361. package/src/fromArray.ts +1 -1
  362. package/src/fromDequeue.ts +39 -0
  363. package/src/fromEffect.ts +12 -2
  364. package/src/fromEmitter.ts +4 -10
  365. package/src/fromFxEffect.ts +3 -1
  366. package/src/fromHub.ts +10 -0
  367. package/src/fromIterable.ts +1 -1
  368. package/src/helpers.ts +73 -106
  369. package/src/hold.ts +1 -7
  370. package/src/index.ts +573 -607
  371. package/src/keyed.ts +45 -28
  372. package/src/mergeAll.ts +8 -5
  373. package/src/mergeBufferConcurrently.test.ts +37 -0
  374. package/src/mergeBufferConcurrently.ts +105 -0
  375. package/src/mergeConcurrently.test.ts +20 -0
  376. package/src/mergeConcurrently.ts +57 -0
  377. package/src/multicast.ts +30 -22
  378. package/src/never.ts +1 -1
  379. package/src/observe.ts +16 -7
  380. package/src/onExit.ts +13 -0
  381. package/src/orElse.ts +16 -0
  382. package/src/promise.ts +4 -4
  383. package/src/provide.ts +9 -7
  384. package/src/skipRepeats.ts +5 -7
  385. package/src/skipWhile.ts +1 -1
  386. package/src/slice.ts +3 -3
  387. package/src/struct.ts +18 -0
  388. package/src/switchMapCause.ts +17 -1
  389. package/src/switchMatch.ts +1 -1
  390. package/src/takeWhile.ts +1 -1
  391. package/src/tap.ts +5 -1
  392. package/src/tapCause.ts +8 -6
  393. package/src/test-utils.ts +2 -2
  394. package/src/toArray.ts +5 -4
  395. package/src/toEnqueue.ts +13 -0
  396. package/tsconfig.build.json +2 -1
  397. package/tsconfig.build.tsbuildinfo +1 -1
  398. package/vite.config.js +3 -0
package/src/RefSubject.ts CHANGED
@@ -1,34 +1,47 @@
1
1
  import * as Context from '@effect/data/Context'
2
- import type { Trace } from '@effect/data/Debug'
3
- import { methodWithTrace } from '@effect/data/Debug'
4
- import { equals } from '@effect/data/Equal'
5
2
  import * as Equal from '@effect/data/Equal'
6
3
  import { identity, pipe } from '@effect/data/Function'
7
4
  import * as Hash from '@effect/data/Hash'
8
5
  import * as MutableRef from '@effect/data/MutableRef'
9
6
  import * as Option from '@effect/data/Option'
10
- import * as RR from '@effect/data/ReadonlyRecord'
11
- import * as Equivalence from '@effect/data/typeclass/Equivalence'
7
+ import { Pipeable, pipeArguments } from '@effect/data/Pipeable'
8
+ import * as Equivalence from '@effect/data/Equivalence'
9
+ import * as Deferred from '@effect/io/Deferred'
12
10
  import * as Effect from '@effect/io/Effect'
13
11
  import * as Fiber from '@effect/io/Fiber'
14
-
15
- import { Fx, Sink, isFx, Traced, FxTypeId } from './Fx.js'
16
- import type { Subject } from './Subject.js'
12
+ import * as Scope from '@effect/io/Scope'
13
+ import fastDeepEqual from 'fast-deep-equal'
14
+
15
+ import { Computed, ComputedImpl, ComputedTypeId } from './Computed.js'
16
+ import { FilteredImpl } from './Filtered.js'
17
+ import { Fx, FxTypeId, Sink, isFx } from './Fx.js'
18
+ import { RefTransform, RefTransformImpl } from './RefTransform.js'
19
+ import { Subject } from './Subject.js'
17
20
  import { combineAll } from './combineAll.js'
18
21
  import { HoldFx } from './hold.js'
19
- import { map } from './map.js'
20
- import { multicast } from './multicast.js'
21
22
  import { never } from './never.js'
22
- import { switchMapEffect } from './switchMap.js'
23
+ import { drain } from './observe.js'
24
+ import { struct } from './struct.js'
25
+ import { switchMatchCauseEffect } from './switchMatch.js'
26
+
27
+ const unboundedConcurrency = { concurrency: 'unbounded' } as const
28
+
29
+ const refVariance = {
30
+ _R: identity,
31
+ _E: identity,
32
+ _A: identity,
33
+ }
23
34
 
24
- export const RefSubjectTypeId = Symbol.for('./RefSubject')
35
+ export const RefSubjectTypeId = Symbol.for('@typed/fx/RefSubject')
25
36
  export type RefSubjectTypeId = typeof RefSubjectTypeId
26
37
 
27
- export interface RefSubject<in out E, in out A> extends Subject<E, A>, Effect.Effect<never, E, A> {
38
+ export interface RefSubject<in out E, in out A>
39
+ extends Subject<E, A>,
40
+ Computed<never, E, A>,
41
+ Pipeable {
28
42
  readonly [RefSubjectTypeId]: RefSubjectTypeId
29
43
 
30
44
  readonly eq: Equivalence.Equivalence<A>
31
- readonly get: Effect.Effect<never, E, A>
32
45
 
33
46
  readonly modifyEffect: <R2, E2, B>(
34
47
  f: (a: A) => Effect.Effect<R2, E2, readonly [B, A]>,
@@ -42,57 +55,75 @@ export interface RefSubject<in out E, in out A> extends Subject<E, A>, Effect.Ef
42
55
 
43
56
  readonly update: (f: (a: A) => A) => Effect.Effect<never, E, A>
44
57
 
45
- readonly set: (a: A) => Effect.Effect<never, E, A>
58
+ readonly set: (a: A) => Effect.Effect<never, never, A>
46
59
 
47
60
  readonly delete: Effect.Effect<never, E, Option.Option<A>>
48
61
 
49
- readonly mapEffect: <R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, B>) => Computed<R2, E | E2, B>
50
-
51
- readonly map: <B>(f: (a: A) => B) => Computed<never, E, B>
62
+ /**
63
+ * The current version of the RefSubject, starting with 0, 1 when initialized,
64
+ * and incremented each time the value is updated.
65
+ */
66
+ readonly version: () => number
52
67
  }
53
68
 
54
- export interface Computed<R, E, A> extends Fx<R, E, A>, Effect.Effect<R, E, A> {
55
- readonly get: Effect.Effect<R, E, A>
56
-
57
- readonly mapEffect: <R2, E2, B>(
58
- f: (a: A) => Effect.Effect<R2, E2, B>,
59
- ) => Computed<R | R2, E | E2, B>
60
-
61
- readonly map: <B>(f: (a: A) => B) => Computed<R, E, B>
62
- }
69
+ type Lock = <R2, E2, B>(effect: Effect.Effect<R2, E2, B>) => Effect.Effect<R2, E2, B>
63
70
 
64
71
  export function makeRef<R, E, A>(
65
72
  effect: Effect.Effect<R, E, A>,
66
- eq: Equivalence.Equivalence<A> = equals,
67
- ): Effect.Effect<R, never, RefSubject<E, A>> {
68
- return Effect.contextWith(
69
- (ctx: Context.Context<R>) => new RefSubjectImpl(Effect.provideContext(effect, ctx), eq),
73
+ eq?: Equivalence.Equivalence<A>,
74
+ ): Effect.Effect<R | Scope.Scope, never, RefSubject<E, A>> {
75
+ return Effect.contextWithEffect((context) =>
76
+ Effect.suspend(() => {
77
+ const ref = RefSubject.unsafeMake(
78
+ Effect.provideContext(effect, context),
79
+ Context.get(context, Scope.Scope),
80
+ eq,
81
+ )
82
+
83
+ return Effect.as(
84
+ Effect.addFinalizer(() => ref.end()),
85
+ ref,
86
+ )
87
+ }),
70
88
  )
71
89
  }
72
90
 
73
91
  export namespace RefSubject {
74
92
  export type Any = RefSubject<any, any> | RefSubject<never, any>
75
93
 
76
- export function tuple<S extends ReadonlyArray<Any>>(
77
- ...subjects: S
94
+ export function unsafeMake<E, A>(
95
+ initial: Effect.Effect<never, E, A>,
96
+ scope: Scope.Scope,
97
+ eq: Equivalence.Equivalence<A> = fastDeepEqual,
98
+ ): RefSubject<E, A> {
99
+ return makeRefFromPrimitive(unsafeMakeRefPrimitive(initial, scope, eq))
100
+ }
101
+
102
+ export function tuple<const Refs extends readonly Any[]>(
103
+ ...refs: Refs
78
104
  ): RefSubject<
79
- Fx.ErrorsOf<S[number]>,
105
+ Fx.ErrorsOf<Refs[number]>,
80
106
  {
81
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
107
+ readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]>
82
108
  }
83
109
  > {
84
- return new TupleRefSubjectImpl(subjects)
110
+ return makeRefFromPrimitive<
111
+ Fx.ErrorsOf<Refs[number]>,
112
+ {
113
+ readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]>
114
+ }
115
+ >(tupleRefPrimitive<Refs>(refs))
85
116
  }
86
117
 
87
- export function struct<S extends RR.ReadonlyRecord<Any>>(
88
- subjects: S,
118
+ export function struct<const Refs extends Readonly<Record<string, Any>>>(
119
+ refs: Refs,
89
120
  ): RefSubject<
90
- Fx.ErrorsOf<S[keyof S]>,
121
+ Fx.ErrorsOf<Refs[string]>,
91
122
  {
92
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
123
+ readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]>
93
124
  }
94
125
  > {
95
- return new StructRefSubjectImpl(subjects)
126
+ return makeRefFromPrimitive(structRefPrimitive<Refs>(refs))
96
127
  }
97
128
 
98
129
  export function all<S extends ReadonlyArray<Any>>(
@@ -104,7 +135,16 @@ export namespace RefSubject {
104
135
  }
105
136
  >
106
137
 
107
- export function all<S extends RR.ReadonlyRecord<Any>>(
138
+ export function all<S extends ReadonlyArray<Any>>(
139
+ ...subjects: S
140
+ ): RefSubject<
141
+ Fx.ErrorsOf<S[number]>,
142
+ {
143
+ readonly [K in keyof S]: Fx.OutputOf<S[K]>
144
+ }
145
+ >
146
+
147
+ export function all<S extends Readonly<Record<string, Any>>>(
108
148
  subjects: S,
109
149
  ): RefSubject<
110
150
  Fx.ErrorsOf<S[string]>,
@@ -113,643 +153,623 @@ export namespace RefSubject {
113
153
  }
114
154
  >
115
155
 
116
- export function all(subjects: any): any {
117
- return (Array.isArray(subjects) ? tuple(...subjects) : struct(subjects)) as any
118
- }
156
+ export function all(...subjects: any): any {
157
+ /// MUST be a tuple if more than one argument
158
+ if (subjects.length > 1) {
159
+ return tuple(...subjects)
160
+ }
119
161
 
120
- export function unsafeMake<E, A>(
121
- get: Effect.Effect<never, E, A>,
122
- eq: Equivalence.Equivalence<A> = equals,
123
- ): RefSubject<E, A> {
124
- return new RefSubjectImpl(get, eq)
162
+ // Otherwise a single param is either a tuple or a struct
163
+ const singleParam = subjects[0]
164
+
165
+ if (Array.isArray(singleParam)) {
166
+ return tuple(...singleParam)
167
+ }
168
+
169
+ return struct(singleParam)
125
170
  }
126
171
  }
127
172
 
128
- const refSubjectVariant = {
129
- _R: identity,
130
- _E: identity,
131
- _A: identity,
173
+ export function isRefSubject<E, A>(u: unknown): u is RefSubject<E, A> {
174
+ return isFx<never, E, A>(u) && RefSubjectTypeId in u
132
175
  }
133
176
 
134
- class RefSubjectImpl<E, A> extends HoldFx<never, E, A> implements RefSubject<E, A> {
135
- readonly _tag = 'Commit'
136
- public i2: any = undefined
137
- public trace: Trace = undefined;
138
-
139
- readonly [Effect.EffectTypeId] = refSubjectVariant;
140
- readonly [RefSubjectTypeId]: RefSubjectTypeId = RefSubjectTypeId
141
-
142
- readonly lock = Effect.unsafeMakeSemaphore(1).withPermits(1)
143
- readonly initializeFiber: MutableRef.MutableRef<Option.Option<Fiber.RuntimeFiber<E, A>>> =
144
- MutableRef.make(Option.none())
177
+ // Internals for RefSubject
145
178
 
146
- readonly eq: Equivalence.Equivalence<A>
147
-
148
- constructor(readonly i0: Effect.Effect<never, E, A>, readonly i1: Equivalence.Equivalence<A>) {
149
- super(never<E, A>())
179
+ function makeGetFromContext<E, A>(ctx: RefSubjectContext<E, A>): RefSubject<E, A>['get'] {
180
+ return Effect.suspend(() => {
181
+ const current = MutableRef.get(ctx.currentRef)
150
182
 
151
- this.modifyEffect = this.modifyEffect.bind(this)
152
- this.eq = i1
153
- }
183
+ if (Option.isSome(current)) {
184
+ return Effect.succeed(current.value)
185
+ }
154
186
 
155
- run<R2>(sink: Sink<R2, E, A>) {
156
- return Effect.suspend(() => {
157
- const current = MutableRef.get(this.current)
187
+ const fiber = MutableRef.get(ctx.initializingFiberRef)
158
188
 
159
- if (Option.isNone(current)) {
160
- return pipe(
161
- this.get,
162
- Effect.catchAllCause(sink.error),
163
- Effect.flatMap(() => super.run(sink)),
164
- )
165
- }
189
+ if (Option.isSome(fiber)) {
190
+ return Fiber.join(fiber.value)
191
+ }
166
192
 
167
- return super.run(sink)
168
- })
169
- }
193
+ return Effect.tap(ctx.lock(initializeFromContext(ctx)), (a) => ctx.hold.event(a))
194
+ })
195
+ }
170
196
 
171
- readonly event: RefSubject<E, A>['event'] = methodWithTrace(
172
- (trace) => (a: A) => Effect.catchAllCause(this.set(a), this.error).traced(trace),
197
+ function initializeFromContext<E, A>(ctx: RefSubjectContext<E, A>): Effect.Effect<never, E, A> {
198
+ return Effect.uninterruptibleMask((restore) =>
199
+ Effect.flatMap(Effect.forkIn(restore(ctx.initial), ctx.scope), (fiber) => {
200
+ MutableRef.set(ctx.initializingFiberRef, Option.some(fiber))
201
+
202
+ return Effect.tap(Fiber.join(fiber), (a) =>
203
+ Effect.sync(() => {
204
+ MutableRef.increment(ctx.version)
205
+ MutableRef.set(ctx.currentRef, Option.some(a))
206
+ MutableRef.set(ctx.initializingFiberRef, Option.none())
207
+ }),
208
+ )
209
+ }),
173
210
  )
211
+ }
174
212
 
175
- readonly end = methodWithTrace(
176
- (trace) => () =>
177
- Effect.suspend(() =>
178
- Effect.zipPar(this.interruptFibers(), this.interruptInitializeFiber()),
179
- ).traced(trace),
180
- )
213
+ function makeRefMethods<E, A>(
214
+ primitive: RefPrimitive<E, A>,
215
+ ): Pick<RefSubject<E, A>, 'modify' | 'updateEffect' | 'update'> {
216
+ const modify = makeModify<E, A>(primitive.modifyEffect)
217
+ const updateEffect = makeUpdateEffect<E, A>(primitive.modifyEffect)
218
+ const update = makeUpdate<E, A>(updateEffect)
219
+
220
+ return {
221
+ modify,
222
+ updateEffect,
223
+ update,
224
+ } as const
225
+ }
181
226
 
182
- protected interruptFibers() {
183
- return this.fiber ? Fiber.interrupt(this.fiber) : Effect.unit()
184
- }
227
+ function makeModifyEffectFromContext<E, A>(
228
+ get: RefSubject<E, A>['get'],
229
+ ctx: RefSubjectContext<E, A>,
230
+ ): RefSubject<E, A>['modifyEffect'] {
231
+ return (f) =>
232
+ Effect.flatMap(get, (a1) =>
233
+ ctx.lock(
234
+ Effect.flatMap(f(a1), ([b, a2]) =>
235
+ Effect.suspend(() => {
236
+ MutableRef.set(ctx.currentRef, Option.some(a2))
185
237
 
186
- protected interruptInitializeFiber() {
187
- const fiber = MutableRef.get(this.initializeFiber)
188
- if (Option.isSome(fiber)) {
189
- return Fiber.interrupt(fiber.value)
190
- }
238
+ if (ctx.eq(a1, a2)) {
239
+ return Effect.succeed(b)
240
+ }
191
241
 
192
- return Effect.unit()
193
- }
242
+ MutableRef.increment(ctx.version)
194
243
 
195
- readonly get: RefSubject<E, A>['get'] = Effect.suspend(() =>
196
- pipe(
197
- MutableRef.get(this.current),
198
- Option.match(
199
- () =>
200
- pipe(
201
- MutableRef.get(this.initializeFiber),
202
- Option.match(
203
- () =>
204
- this.lock(
205
- Effect.uninterruptibleMask((restore) =>
206
- pipe(
207
- Effect.forkDaemon(restore(this.i0)),
208
- Effect.tap((fiber) =>
209
- Effect.sync(() => MutableRef.set(this.initializeFiber, Option.some(fiber))),
210
- ),
211
- Effect.flatMap(Fiber.join),
212
- Effect.tap((a) =>
213
- Effect.suspend(() => {
214
- MutableRef.set(this.current, Option.some(a))
215
- MutableRef.set(this.initializeFiber, Option.none())
216
-
217
- return super.event(a)
218
- }),
219
- ),
220
- ),
221
- ),
222
- ),
223
- Fiber.join,
224
- ),
225
- ),
226
- Effect.succeed,
244
+ return Effect.as(ctx.hold.event(a2), b)
245
+ }),
246
+ ),
227
247
  ),
228
- ),
229
- )
230
-
231
- modifyEffect<R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, readonly [B, A]>) {
232
- return methodWithTrace(
233
- (trace) =>
234
- <R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, readonly [B, A]>) =>
235
- Effect.flatMap(this.get, (a1) =>
236
- this.lock(
237
- Effect.flatMap(f(a1), ([b, a2]) =>
238
- Effect.suspend(() => {
239
- MutableRef.set(this.current, Option.some(a2))
240
-
241
- if (this.i1(a1, a2)) {
242
- return Effect.succeed(b)
243
- }
244
-
245
- return Effect.as(super.event(a2), b)
246
- }),
247
- ),
248
- ),
249
- ).traced(trace),
250
- )(f)
251
- }
248
+ )
249
+ }
252
250
 
253
- readonly modify: RefSubject<E, A>['modify'] = (f) =>
254
- this.modifyEffect((a) => Effect.sync(() => f(a)))
251
+ function makeModify<E, A>(
252
+ modifyEffect: RefSubject<E, A>['modifyEffect'],
253
+ ): RefSubject<E, A>['modify'] {
254
+ return (f) => modifyEffect((a) => Effect.sync(() => f(a)))
255
+ }
255
256
 
256
- readonly updateEffect: RefSubject<E, A>['updateEffect'] = (f) =>
257
- this.modifyEffect((a) => Effect.map(f(a), (a) => [a, a]))
257
+ function makeUpdateEffect<E, A>(
258
+ modifyEffect: RefSubject<E, A>['modifyEffect'],
259
+ ): RefSubject<E, A>['updateEffect'] {
260
+ return (f) => modifyEffect((a) => Effect.map(f(a), (a) => [a, a]))
261
+ }
258
262
 
259
- readonly update: RefSubject<E, A>['update'] = (f) =>
260
- this.updateEffect((a) => Effect.sync(() => f(a)))
263
+ function makeUpdate<E, A>(
264
+ updateEffect: RefSubject<E, A>['updateEffect'],
265
+ ): RefSubject<E, A>['update'] {
266
+ return (f) => updateEffect((a) => Effect.sync(() => f(a)))
267
+ }
261
268
 
262
- readonly set: RefSubject<E, A>['set'] = (a) => this.update(() => a)
269
+ function makeSetFromContext<E, A>(ctx: RefSubjectContext<E, A>): RefSubject<E, A>['set'] {
270
+ return (a: A) =>
271
+ Effect.suspend(() => {
272
+ const fiber = MutableRef.get(ctx.initializingFiberRef)
273
+
274
+ return pipe(
275
+ fiber,
276
+ Option.match({ onNone: () => Effect.unit, onSome: Fiber.await }),
277
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
278
+ Effect.flatMap((_: unknown) => {
279
+ const current = MutableRef.get(ctx.currentRef)
280
+
281
+ MutableRef.set(ctx.currentRef, Option.some(a))
282
+
283
+ // Only emit if the value has changed
284
+ if (Option.isNone(current) || (Option.isSome(current) && !ctx.eq(current.value, a))) {
285
+ // Increment the version
286
+ MutableRef.increment(ctx.version)
287
+ return Effect.as(ctx.hold.event(a), a)
288
+ }
289
+
290
+ return Effect.succeed(a)
291
+ }),
292
+ )
293
+ })
294
+ }
263
295
 
264
- readonly delete: RefSubject<E, A>['delete'] = Effect.suspend(() => {
265
- const current = MutableRef.get(this.current)
296
+ function makeDeleteFromContext<E, A>(ctx: RefSubjectContext<E, A>): RefSubject<E, A>['delete'] {
297
+ return Effect.sync(() => {
298
+ const current = MutableRef.get(ctx.currentRef)
266
299
 
267
300
  if (Option.isSome(current)) {
268
- MutableRef.set(this.current, Option.none())
301
+ MutableRef.set(ctx.version, 0)
302
+ MutableRef.set(ctx.currentRef, Option.none())
269
303
  }
270
304
 
271
- return Effect.succeed<Option.Option<A>>(current)
305
+ return current
272
306
  })
307
+ }
273
308
 
274
- readonly mapEffect: RefSubject<E, A>['mapEffect'] = <R2, E2, B>(
275
- f: (a: A) => Effect.Effect<R2, E2, B>,
276
- ) => new ComputedImpl<never, E, A, R2, E2, B>(this, f)
277
-
278
- readonly map: RefSubject<E, A>['map'] = (f) => this.mapEffect((a) => Effect.sync(() => f(a)));
309
+ function makeEndFromContext<E, A>(ctx: RefSubjectContext<E, A>): RefSubject<E, A>['end'] {
310
+ return () =>
311
+ Effect.suspend(() => {
312
+ MutableRef.set(ctx.version, 0)
279
313
 
280
- [Equal.symbol](that: unknown) {
281
- return this === that
282
- }
314
+ const fibers = [
315
+ ctx.hold.fiber || Fiber.unit,
316
+ Option.getOrElse(MutableRef.get(ctx.initializingFiberRef), () => Fiber.unit),
317
+ ]
283
318
 
284
- [Hash.symbol]() {
285
- return Hash.random(this)
286
- }
319
+ return Fiber.interruptAll(fibers)
320
+ })
321
+ }
287
322
 
288
- traced(trace: Trace): Effect.Effect<never, E, A> {
289
- if (trace) {
290
- const traced = new RefSubjectImpl(this.i0, this.i1)
291
- traced.trace = trace
292
- return traced
293
- }
323
+ function makeFiltered<E, A>(
324
+ f: () => RefSubject<E, A>,
325
+ ): Pick<
326
+ RefSubject<E, A>,
327
+ 'filterMapEffect' | 'filterMap' | 'filterEffect' | 'filter' | 'filterNotEffect' | 'filterNot'
328
+ > {
329
+ const get = makeMemoizedGet(f)
294
330
 
295
- return this
331
+ function filterMapEffect<R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, Option.Option<B>>) {
332
+ return new FilteredImpl(get(), f)
296
333
  }
297
334
 
298
- commit(): Effect.Effect<never, E, A> {
299
- return this.get.traced(this.trace)
335
+ function filterMap<B>(f: (a: A) => Option.Option<B>) {
336
+ return filterMapEffect((a) => Effect.sync(() => f(a)))
300
337
  }
301
- }
302
338
 
303
- class TupleRefSubjectImpl<S extends ReadonlyArray<RefSubject.Any>>
304
- extends HoldFx<
305
- never,
306
- Fx.ErrorsOf<S[number]>,
307
- {
308
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
309
- }
310
- >
311
- implements
312
- RefSubject<
313
- Fx.ErrorsOf<S[number]>,
314
- {
315
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
316
- }
317
- >
318
- {
319
- readonly _tag = 'Commit'
320
- public trace: Trace = undefined;
321
-
322
- readonly [Effect.EffectTypeId] = refSubjectVariant;
323
- readonly [RefSubjectTypeId]: RefSubjectTypeId = RefSubjectTypeId
324
-
325
- readonly i1: Equivalence.Equivalence<{ readonly [K in keyof S]: Fx.OutputOf<S[K]> }>
326
- public i2: any = undefined
327
-
328
- readonly lock = Effect.unsafeMakeSemaphore(1).withPermits(1)
329
-
330
- readonly eq: Equivalence.Equivalence<{ readonly [K in keyof S]: Fx.OutputOf<S[K]> }>
331
-
332
- constructor(readonly i0: S) {
333
- super(combineAll(...i0) as any)
334
-
335
- this.i1 = this.eq = Equivalence.tuple(...i0.map((s) => s.eq)) as Equivalence.Equivalence<{
336
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
337
- }>
339
+ function filterEffect<R2, E2>(f: (a: A) => Effect.Effect<R2, E2, boolean>) {
340
+ return filterMapEffect((a) => Effect.map(f(a), (b) => (b ? Option.some(a) : Option.none())))
338
341
  }
339
342
 
340
- end() {
341
- return Effect.allPar(this.i0.map((s) => s.end()))
343
+ function filter(f: (a: A) => boolean) {
344
+ return filterEffect((a) => Effect.sync(() => f(a)))
342
345
  }
343
346
 
344
- readonly get: RefSubject<
345
- Fx.ErrorsOf<S[number]>,
346
- {
347
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
348
- }
349
- >['get'] = Effect.suspend(
350
- () =>
351
- Effect.allPar(this.i0.map((s) => s.get)) as Effect.Effect<
352
- never,
353
- Fx.ErrorsOf<S[number]>,
354
- {
355
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
356
- }
357
- >,
358
- )
359
-
360
- modifyEffect<R2, E2, B>(
361
- f: (a: {
362
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
363
- }) => Effect.Effect<R2, E2, readonly [B, { readonly [K in keyof S]: Fx.OutputOf<S[K]> }]>,
364
- ) {
365
- const { current, i0 } = this
347
+ function filterNotEffect<R2, E2>(f: (a: A) => Effect.Effect<R2, E2, boolean>) {
348
+ return filterEffect((a) => Effect.map(f(a), (b) => !b))
349
+ }
366
350
 
367
- return pipe(
368
- this.get,
369
- Effect.flatMap((a) =>
370
- this.lock(
371
- Effect.gen(function* ($) {
372
- const [b, a2] = yield* $(f(a))
351
+ function filterNot(f: (a: A) => boolean) {
352
+ return filterNotEffect((a) => Effect.sync(() => f(a)))
353
+ }
373
354
 
374
- MutableRef.set(current, Option.some(a2))
355
+ return {
356
+ filterMapEffect,
357
+ filterMap,
358
+ filterEffect,
359
+ filter,
360
+ filterNotEffect,
361
+ filterNot,
362
+ } as const
363
+ }
375
364
 
376
- yield* $(Effect.allPar(i0.map((s, i) => s.set(a2[i]))))
365
+ function makeComputedMethods<E, A>(
366
+ f: () => RefSubject<E, A>,
367
+ ): Pick<RefSubject<E, A>, 'mapEffect' | 'map'> {
368
+ const get = makeMemoizedGet(f)
377
369
 
378
- return b
379
- }),
380
- ),
381
- ),
382
- )
370
+ function mapEffect<R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, B>): Computed<R2, E | E2, B> {
371
+ return new ComputedImpl(get(), f)
383
372
  }
384
373
 
385
- readonly modify: RefSubject<
386
- Fx.ErrorsOf<S[number]>,
387
- {
388
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
389
- }
390
- >['modify'] = (f) => this.modifyEffect((a) => Effect.sync(() => f(a)))
391
-
392
- readonly updateEffect: RefSubject<
393
- Fx.ErrorsOf<S[number]>,
394
- {
395
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
396
- }
397
- >['updateEffect'] = (f) => this.modifyEffect((a) => Effect.map(f(a), (a) => [a, a]))
398
-
399
- readonly update: RefSubject<
400
- Fx.ErrorsOf<S[number]>,
401
- {
402
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
403
- }
404
- >['update'] = (f) => this.updateEffect((a) => Effect.sync(() => f(a)))
374
+ function map<B>(f: (a: A) => B): Computed<never, E, B> {
375
+ return mapEffect((a) => Effect.sync(() => f(a)))
376
+ }
405
377
 
406
- readonly set: RefSubject<
407
- Fx.ErrorsOf<S[number]>,
408
- {
409
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
410
- }
411
- >['set'] = (a) => this.update(() => a)
378
+ return {
379
+ mapEffect,
380
+ map,
381
+ } as const
382
+ }
412
383
 
413
- readonly delete: RefSubject<
414
- Fx.ErrorsOf<S[number]>,
415
- {
416
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
417
- }
418
- >['delete'] = Effect.suspend(() => {
419
- const current = MutableRef.get(this.current)
384
+ function makeTransformMethods<E, A>(
385
+ f: () => RefSubject<E, A>,
386
+ ): Pick<RefSubject<E, A>, 'transformBoth' | 'transform' | 'transformGet'> {
387
+ const get = makeMemoizedGet(f)
420
388
 
421
- if (Option.isSome(current)) {
422
- MutableRef.set(this.current, Option.none())
423
- }
389
+ function transformBoth<R3, E3, C, R4, E4, D>(
390
+ f: (fx: Fx<never, E, A>) => Fx<R3, E3, C>,
391
+ g: (effect: Effect.Effect<never, E, A>) => Effect.Effect<R4, E4, D>,
392
+ ): RefTransform<R3, E3, C, R4, E4, D> {
393
+ return new RefTransformImpl(get(), f, g)
394
+ }
424
395
 
425
- return Effect.succeed<
426
- Option.Option<{
427
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
428
- }>
429
- >(current)
430
- })
396
+ function transform<R3, E3, C>(
397
+ f: (fx: Fx<never, E, A>) => Fx<R3, E3, C>,
398
+ ): RefTransform<R3, E3, C, never, E, A> {
399
+ return transformBoth(f, identity)
400
+ }
431
401
 
432
- readonly mapEffect: RefSubject<
433
- Fx.ErrorsOf<S[number]>,
434
- {
435
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
436
- }
437
- >['mapEffect'] = <R2, E2, B>(
438
- f: (a: {
439
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
440
- }) => Effect.Effect<R2, E2, B>,
441
- ) =>
442
- new ComputedImpl<
443
- never,
444
- Fx.ErrorsOf<S[number]>,
445
- {
446
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
447
- },
448
- R2,
449
- E2,
450
- B
451
- >(this, f)
402
+ function transformGet<R3, E3, C>(
403
+ f: (effect: Effect.Effect<never, E, A>) => Effect.Effect<R3, E3, C>,
404
+ ): RefTransform<never, E, A, R3, E3, C> {
405
+ return transformBoth(identity, f)
406
+ }
452
407
 
453
- readonly map: RefSubject<
454
- Fx.ErrorsOf<S[number]>,
455
- {
456
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
457
- }
458
- >['map'] = (f) => this.mapEffect((a) => Effect.sync(() => f(a)));
408
+ return {
409
+ transformBoth,
410
+ transform,
411
+ transformGet,
412
+ } as const
413
+ }
459
414
 
415
+ const placeholders = {
416
+ _tag: 'Commit',
417
+ [Effect.EffectTypeId]: refVariance,
418
+ i0: undefined,
419
+ i1: undefined,
420
+ i2: undefined,
460
421
  [Equal.symbol](that: unknown) {
461
422
  return this === that
462
- }
463
-
423
+ },
464
424
  [Hash.symbol]() {
465
425
  return Hash.random(this)
466
- }
426
+ },
427
+ pipe() {
428
+ // eslint-disable-next-line prefer-rest-params
429
+ return pipeArguments(this, arguments)
430
+ },
431
+ }
467
432
 
468
- traced(trace: Trace): Effect.Effect<
469
- never,
470
- Fx.ErrorsOf<S[number]>,
433
+ function makeEffectMethods<E, A>(
434
+ get: RefSubject<E, A>['get'],
435
+ ): Pick<RefSubject<E, A>, Extract<keyof Effect.Effect<never, E, A>, keyof RefSubject<E, A>>> {
436
+ return Object.assign(
471
437
  {
472
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
473
- }
474
- > {
475
- if (trace) {
476
- const traced = new TupleRefSubjectImpl(this.i0)
477
- traced.trace = trace
478
- return traced
479
- }
438
+ commit() {
439
+ return get
440
+ },
441
+ } as const,
442
+ placeholders,
443
+ ) as any
444
+ }
480
445
 
481
- return this
482
- }
446
+ function makeMemoizedGet<A>(f: () => A) {
447
+ let memoized: Option.Option<A> = Option.none()
483
448
 
484
- commit(): Effect.Effect<
485
- never,
486
- Fx.ErrorsOf<S[number]>,
487
- {
488
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
449
+ return () => {
450
+ if (Option.isNone(memoized)) {
451
+ memoized = Option.some(f())
489
452
  }
490
- > {
491
- return this.get.traced(this.trace)
453
+
454
+ return (memoized as Option.Some<A>).value
492
455
  }
493
456
  }
494
457
 
495
- class StructRefSubjectImpl<S extends RR.ReadonlyRecord<RefSubject.Any>>
496
- extends HoldFx<
497
- never,
498
- Fx.ErrorsOf<S[number]>,
499
- {
500
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
501
- }
502
- >
503
- implements
504
- RefSubject<
505
- Fx.ErrorsOf<S[number]>,
506
- {
507
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
508
- }
509
- >
510
- {
511
- readonly _tag = 'Commit'
512
- public trace: Trace = undefined;
513
-
514
- readonly [Effect.EffectTypeId] = refSubjectVariant;
515
- readonly [RefSubjectTypeId]: RefSubjectTypeId = RefSubjectTypeId
458
+ type RefSubjectContext<E, A> = {
459
+ initial: Effect.Effect<never, E, A>
460
+ currentRef: MutableRef.MutableRef<Option.Option<A>>
461
+ initializingFiberRef: MutableRef.MutableRef<Option.Option<Fiber.RuntimeFiber<E, A>>>
462
+ lock: Lock
463
+ scope: Scope.Scope
464
+ eq: Equivalence.Equivalence<A>
465
+ hold: HoldFx<never, E, A>
466
+ version: MutableRef.MutableRef<number>
467
+ }
516
468
 
517
- readonly i1: Equivalence.Equivalence<{ readonly [K in keyof S]: Fx.OutputOf<S[K]> }>
518
- public i2: any = undefined
469
+ function makeRefSubjectContext<E, A>(
470
+ initial: Effect.Effect<never, E, A>,
471
+ scope: Scope.Scope,
472
+ eq: Equivalence.Equivalence<A>,
473
+ ) {
474
+ const hold = new HoldFx(never<E, A>())
475
+ const ctx: RefSubjectContext<E, A> = {
476
+ initial,
477
+ currentRef: hold.current,
478
+ initializingFiberRef: MutableRef.make(Option.none()),
479
+ lock: Effect.unsafeMakeSemaphore(1).withPermits(1),
480
+ scope,
481
+ eq,
482
+ hold,
483
+ version: MutableRef.make(0),
484
+ }
485
+
486
+ return ctx
487
+ }
519
488
 
520
- readonly lock = Effect.unsafeMakeSemaphore(1).withPermits(1)
489
+ function unsafeMakeRefPrimitive<E, A>(
490
+ initial: Effect.Effect<never, E, A>,
491
+ scope: Scope.Scope,
492
+ eq: Equivalence.Equivalence<A>,
493
+ ): RefPrimitive<E, A> {
494
+ const ctx = makeRefSubjectContext(initial, scope, eq)
495
+ const get = makeGetFromContext(ctx)
496
+ const set = makeSetFromContext(ctx)
521
497
 
522
- readonly eq: Equivalence.Equivalence<{ readonly [K in keyof S]: Fx.OutputOf<S[K]> }>
498
+ function run<R2>(sink: Sink<R2, E, A>) {
499
+ return Effect.suspend(() => {
500
+ const current = MutableRef.get(ctx.hold.current)
523
501
 
524
- constructor(readonly i0: S) {
525
- super(
526
- map(
527
- combineAll(...Object.entries(i0).map(([k, s]) => map(s, (x) => [k, x]))),
528
- Object.fromEntries,
529
- ) as any,
530
- )
502
+ if (Option.isNone(current)) {
503
+ return pipe(
504
+ primitive.get,
505
+ Effect.catchAllCause(sink.error),
506
+ Effect.flatMap(() => ctx.hold.run(sink)),
507
+ )
508
+ }
531
509
 
532
- this.i1 = this.eq = Equivalence.struct(RR.map(i0, (s) => s.eq)) as Equivalence.Equivalence<{
533
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
534
- }>
510
+ return ctx.hold.run(sink)
511
+ })
535
512
  }
536
513
 
537
- end() {
538
- return Effect.allPar(RR.map(this.i0, (s) => s.end()))
514
+ const primitive: RefPrimitive<E, A> = {
515
+ delete: makeDeleteFromContext(ctx),
516
+ end: makeEndFromContext(ctx),
517
+ eq,
518
+ error: (cause) => ctx.hold.error(cause),
519
+ event: set,
520
+ get,
521
+ modifyEffect: makeModifyEffectFromContext(get, ctx),
522
+ run,
523
+ set,
524
+ version: ctx.version,
539
525
  }
540
526
 
541
- readonly get: RefSubject<
542
- Fx.ErrorsOf<S[number]>,
543
- {
544
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
545
- }
546
- >['get'] = Effect.suspend(
547
- () =>
548
- Effect.allPar(RR.map(this.i0, (s) => s.get)) as Effect.Effect<
549
- never,
550
- Fx.ErrorsOf<S[number]>,
551
- {
552
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
553
- }
554
- >,
555
- )
556
-
557
- modifyEffect<R2, E2, B>(
558
- f: (a: {
559
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
560
- }) => Effect.Effect<R2, E2, readonly [B, { readonly [K in keyof S]: Fx.OutputOf<S[K]> }]>,
561
- ) {
562
- const { current, i0: subjects } = this
563
-
564
- return pipe(
565
- this.get,
566
- Effect.flatMap((a) =>
567
- this.lock(
568
- Effect.gen(function* ($) {
569
- const [b, a2] = yield* $(f(a))
527
+ return primitive
528
+ }
570
529
 
571
- MutableRef.set(current, Option.some(a2))
530
+ function makeRefFromPrimitive<E, A>(primitive: RefPrimitive<E, A>): RefSubject<E, A> {
531
+ const ref: RefSubject<E, A> = {
532
+ [FxTypeId]: refVariance,
533
+ [RefSubjectTypeId]: RefSubjectTypeId,
534
+ [ComputedTypeId]: ComputedTypeId,
535
+ ...primitive,
536
+ ...makeRefMethods(primitive),
537
+ ...makeEffectMethods(primitive.get),
538
+ ...makeFiltered(() => ref),
539
+ ...makeComputedMethods(() => ref),
540
+ ...makeTransformMethods(() => ref),
541
+ version() {
542
+ return MutableRef.get(primitive.version)
543
+ },
544
+ }
545
+
546
+ return ref
547
+ }
572
548
 
573
- yield* $(Effect.allPar(RR.map(subjects, (s, i) => s.set(a2[i]))))
549
+ // Base Ref which provides all functionality that can otherwise be derived
550
+ // using makeRefFromPrimitive
551
+ interface RefPrimitive<E, A> {
552
+ // Fx
553
+ run: RefSubject<E, A>['run']
554
+
555
+ // Subject
556
+ event: RefSubject<E, A>['event']
557
+ error: RefSubject<E, A>['error']
558
+ end: RefSubject<E, A>['end']
559
+
560
+ // Ref
561
+ eq: RefSubject<E, A>['eq']
562
+ get: RefSubject<E, A>['get']
563
+ modifyEffect: RefSubject<E, A>['modifyEffect']
564
+ set: RefSubject<E, A>['set']
565
+ delete: RefSubject<E, A>['delete']
566
+
567
+ // Primitive
568
+ version: MutableRef.MutableRef<number>
569
+ }
574
570
 
575
- return b
576
- }),
577
- ),
571
+ // Internals for RefSubject.tuple
572
+
573
+ function tupleRefPrimitive<const Refs extends ReadonlyArray<RefSubject.Any>>(
574
+ refs: Refs,
575
+ ): RefPrimitive<Fx.ErrorsOf<Refs[number]>, { readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]> }> {
576
+ type _E = Fx.ErrorsOf<Refs[number]>
577
+ type _A = { readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]> }
578
+
579
+ const hold = new HoldFx(combineAll(...refs) as any as Fx<never, _E, _A>)
580
+ const eq = Equivalence.tuple(...refs.map((ref) => ref.eq))
581
+ const get = Effect.all(
582
+ refs.map((ref) => ref.get),
583
+ unboundedConcurrency,
584
+ ) as Effect.Effect<never, _E, _A>
585
+
586
+ const primitive: RefPrimitive<_E, _A> = {
587
+ delete: Effect.map(
588
+ Effect.all(
589
+ refs.map((ref) => ref.delete),
590
+ { concurrency: 'unbounded' },
578
591
  ),
579
- )
580
- }
581
-
582
- readonly modify: RefSubject<
583
- Fx.ErrorsOf<S[number]>,
584
- {
585
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
586
- }
587
- >['modify'] = (f) => this.modifyEffect((a) => Effect.sync(() => f(a)))
588
-
589
- readonly updateEffect: RefSubject<
590
- Fx.ErrorsOf<S[number]>,
591
- {
592
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
593
- }
594
- >['updateEffect'] = (f) => this.modifyEffect((a) => Effect.map(f(a), (a) => [a, a]))
595
-
596
- readonly update: RefSubject<
597
- Fx.ErrorsOf<S[number]>,
598
- {
599
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
600
- }
601
- >['update'] = (f) => this.updateEffect((a) => Effect.sync(() => f(a)))
602
-
603
- readonly set: RefSubject<
604
- Fx.ErrorsOf<S[number]>,
605
- {
606
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
607
- }
608
- >['set'] = (a) => this.update(() => a)
609
-
610
- readonly delete: RefSubject<
611
- Fx.ErrorsOf<S[number]>,
612
- {
613
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
614
- }
615
- >['delete'] = Effect.suspend(() => {
616
- const current = MutableRef.get(this.current)
617
-
618
- if (Option.isSome(current)) {
619
- MutableRef.set(this.current, Option.none())
620
- }
621
-
622
- return Effect.succeed<
623
- Option.Option<{
624
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
625
- }>
626
- >(current)
627
- })
628
-
629
- readonly mapEffect: RefSubject<
630
- Fx.ErrorsOf<S[number]>,
631
- {
632
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
633
- }
634
- >['mapEffect'] = <R2, E2, B>(
635
- f: (a: {
636
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
637
- }) => Effect.Effect<R2, E2, B>,
638
- ) =>
639
- new ComputedImpl<
640
- never,
641
- Fx.ErrorsOf<S[number]>,
642
- {
643
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
644
- },
645
- R2,
646
- E2,
647
- B
648
- >(this, f)
649
-
650
- readonly map: RefSubject<
651
- Fx.ErrorsOf<S[number]>,
652
- {
653
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
654
- }
655
- >['map'] = (f) => this.mapEffect((a) => Effect.sync(() => f(a)));
656
-
657
- [Equal.symbol](that: unknown) {
658
- return this === that
659
- }
660
-
661
- [Hash.symbol]() {
662
- return Hash.random(this)
663
- }
592
+ (values) => Option.all(values),
593
+ ) as Effect.Effect<never, _E, Option.Option<_A>>,
594
+ end: () =>
595
+ Effect.all(
596
+ refs.map((ref) => ref.end()),
597
+ unboundedConcurrency,
598
+ ),
599
+ eq,
600
+ error: (error) => hold.error(error),
601
+ event: (value) =>
602
+ Effect.all(
603
+ value.map((v, i) => refs[i].event(v)),
604
+ unboundedConcurrency,
605
+ ),
606
+ get,
607
+ modifyEffect: makeModifyEffectTuple(refs, get, eq),
608
+ run: (sink) => hold.run(sink),
609
+ set: (value) =>
610
+ Effect.all(
611
+ value.map((v, i) => refs[i].set(v)),
612
+ unboundedConcurrency,
613
+ ) as Effect.Effect<never, never, _A>,
614
+ version: MutableRef.make(0),
615
+ }
616
+
617
+ return primitive
618
+ }
664
619
 
665
- traced(trace: Trace): Effect.Effect<
666
- never,
667
- Fx.ErrorsOf<S[number]>,
668
- {
669
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
670
- }
671
- > {
672
- if (trace) {
673
- const traced = new StructRefSubjectImpl(this.i0)
674
- traced.trace = trace
675
- return traced
676
- }
620
+ function makeModifyEffectTuple<
621
+ const Refs extends ReadonlyArray<RefSubject.Any>,
622
+ E,
623
+ A extends readonly any[],
624
+ >(
625
+ refs: Refs,
626
+ get: Effect.Effect<never, E, A>,
627
+ eq: Equivalence.Equivalence<A>,
628
+ ): RefSubject<E, A>['modifyEffect'] {
629
+ return <R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, readonly [B, A]>) => {
630
+ return Effect.gen(function* ($) {
631
+ const current = yield* $(get)
632
+ const [b, a] = yield* $(f(current))
633
+
634
+ if (eq(a, current)) {
635
+ return b
636
+ }
677
637
 
678
- return this
679
- }
638
+ yield* $(
639
+ Effect.all(
640
+ refs.map((ref, i) => ref.set(a[i])),
641
+ unboundedConcurrency,
642
+ ),
643
+ )
680
644
 
681
- commit(): Effect.Effect<
682
- never,
683
- Fx.ErrorsOf<S[number]>,
684
- {
685
- readonly [K in keyof S]: Fx.OutputOf<S[K]>
686
- }
687
- > {
688
- return this.get.traced(this.trace)
645
+ return b
646
+ })
689
647
  }
690
648
  }
691
649
 
692
- class ComputedImpl<R, E, A, R2, E2, B> implements Computed<R | R2, E | E2, B> {
693
- readonly [FxTypeId] = {
694
- _R: identity,
695
- _E: identity,
696
- _A: identity,
697
- }
698
-
699
- readonly _tag = 'Commit'
700
- public trace: Trace = undefined;
650
+ function structRefPrimitive<const Refs extends Readonly<Record<string, RefSubject.Any>>>(
651
+ refs: Refs,
652
+ ): RefPrimitive<Fx.ErrorsOf<Refs[string]>, { readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]> }> {
653
+ type _E = Fx.ErrorsOf<Refs[string]>
654
+ type _A = { readonly [K in keyof Refs]: Fx.OutputOf<Refs[K]> }
655
+
656
+ const hold = new HoldFx(struct(refs)) as HoldFx<never, _E, _A>
657
+ const eq = Equivalence.struct(mapRecord(refs, (ref) => ref.eq))
658
+ const get = Effect.all(
659
+ mapRecord(refs, (ref) => ref.get),
660
+ unboundedConcurrency,
661
+ ) as Effect.Effect<never, _E, _A>
662
+
663
+ const primitive: RefPrimitive<_E, _A> = {
664
+ delete: Effect.map(
665
+ Effect.all(
666
+ mapRecord(refs, (ref) => ref.delete),
667
+ unboundedConcurrency,
668
+ ),
669
+ (values) => Option.all(values),
670
+ ) as Effect.Effect<never, _E, Option.Option<_A>>,
671
+ end: () =>
672
+ Effect.all(
673
+ mapRecord(refs, (ref) => ref.end()),
674
+ unboundedConcurrency,
675
+ ),
676
+ eq,
677
+ error: (error) => hold.error(error),
678
+ event: (value) =>
679
+ Effect.all(
680
+ mapRecord(value, (v, i) => refs[i].event(v)),
681
+ unboundedConcurrency,
682
+ ),
683
+ get,
684
+ modifyEffect: makeModifyEffectStruct(refs, get, eq),
685
+ run: (sink) => hold.run(sink),
686
+ set: (value) =>
687
+ Effect.all(
688
+ mapRecord(value, (v, i) => refs[i].set(v)),
689
+ unboundedConcurrency,
690
+ ) as Effect.Effect<never, never, _A>,
691
+ version: MutableRef.make(0),
692
+ }
693
+
694
+ return primitive
695
+ }
701
696
 
702
- readonly [Effect.EffectTypeId] = refSubjectVariant;
703
- readonly [RefSubjectTypeId]: RefSubjectTypeId = RefSubjectTypeId
697
+ function makeModifyEffectStruct<
698
+ const Refs extends Readonly<Record<string, RefSubject.Any>>,
699
+ E,
700
+ A extends Readonly<Record<string, any>>,
701
+ >(
702
+ refs: Refs,
703
+ get: Effect.Effect<never, E, A>,
704
+ eq: Equivalence.Equivalence<A>,
705
+ ): RefSubject<E, A>['modifyEffect'] {
706
+ return <R2, E2, B>(f: (a: A) => Effect.Effect<R2, E2, readonly [B, A]>) => {
707
+ return Effect.gen(function* ($) {
708
+ const current = yield* $(get)
709
+ const [b, a] = yield* $(f(current))
710
+
711
+ if (eq(a, current)) {
712
+ return b
713
+ }
704
714
 
705
- readonly i2: Fx<R | R2, E | E2, B>
715
+ yield* $(
716
+ Effect.all(
717
+ mapRecord(refs, (ref, i) => ref.set(a[i])),
718
+ unboundedConcurrency,
719
+ ),
720
+ )
706
721
 
707
- constructor(readonly i0: Computed<R, E, A>, readonly i1: (a: A) => Effect.Effect<R2, E2, B>) {
708
- // Create a stable reference to derived Fx
709
- this.i2 = multicast(switchMapEffect(this.i0, this.i1))
722
+ return b
723
+ })
710
724
  }
725
+ }
711
726
 
712
- run<R3>(sink: Sink<R3, E | E2, B>) {
713
- return this.i2.run(sink)
714
- }
727
+ function mapRecord<K extends string, A, B>(
728
+ record: Readonly<Record<K, A>>,
729
+ f: (a: A, k: K) => B,
730
+ ): { readonly [_ in K]: B } {
731
+ const result: Record<K, B> = {} as any
715
732
 
716
- addTrace(trace: Trace): Fx<R | R2, E | E2, B> {
717
- return Traced<R | R2, E | E2, B>(this, trace)
733
+ for (const k in record) {
734
+ result[k] = f(record[k], k)
718
735
  }
719
736
 
720
- readonly get = Effect.flatMap(this.i0.get, this.i1)
721
-
722
- readonly mapEffect: Computed<R | R2, E | E2, B>['mapEffect'] = <R3, E3, C>(
723
- f: (b: B) => Effect.Effect<R3, E3, C>,
724
- ): Computed<R | R2 | R3, E | E2 | E3, C> =>
725
- new ComputedImpl(this.i0, (a) => Effect.flatMap(this.i1(a), f))
726
-
727
- readonly map: Computed<R | R2, E | E2, B>['map'] = <C>(f: (b: B) => C) =>
728
- this.mapEffect((a) => Effect.sync(() => f(a)));
737
+ return result
738
+ }
729
739
 
730
- [Equal.symbol](that: unknown) {
731
- return this === that
732
- }
740
+ export function asRef<R, E, A>(fx: Fx<R, E, A>) {
741
+ return Effect.flatMap(Deferred.make<E, A>(), (deferred) =>
742
+ Effect.flatMap(makeRef(Deferred.await(deferred)), (ref) => {
743
+ const onValue = (value: A) =>
744
+ Effect.flatMap(Deferred.succeed(deferred, value), (closed) =>
745
+ closed ? Effect.unit : ref.set(value),
746
+ )
733
747
 
734
- [Hash.symbol]() {
735
- return Hash.random(this)
736
- }
748
+ return Effect.as(
749
+ Effect.forkScoped(
750
+ Effect.catchAllCause(drain(switchMatchCauseEffect(fx, ref.error, onValue)), ref.error),
751
+ ),
752
+ ref,
753
+ )
754
+ }),
755
+ )
737
756
 
738
- traced(trace: Trace): Effect.Effect<R | R2, E | E2, B> {
739
- if (trace) {
740
- const traced = new ComputedImpl(this.i0, this.i1)
741
- traced.trace = trace
742
- return traced
743
- }
757
+ return Effect.gen(function* ($) {
758
+ const deferred = yield* $(Deferred.make<E, A>())
759
+ const ref = yield* $(makeRef(Deferred.await(deferred)))
744
760
 
745
- return this
746
- }
761
+ const onValue = (value: A) =>
762
+ Effect.flatMap(Deferred.succeed(deferred, value), (closed) =>
763
+ closed ? Effect.unit : ref.set(value),
764
+ )
747
765
 
748
- commit(): Effect.Effect<R | R2, E | E2, B> {
749
- return this.get.traced(this.trace)
750
- }
751
- }
766
+ yield* $(
767
+ switchMatchCauseEffect(fx, ref.error, onValue),
768
+ drain,
769
+ Effect.catchAllCause(ref.error),
770
+ Effect.forkScoped,
771
+ )
752
772
 
753
- export function isRefSubject<E, A>(u: unknown): u is RefSubject<E, A> {
754
- return isFx<never, E, A>(u) && RefSubjectTypeId in u && u[RefSubjectTypeId] === RefSubjectTypeId
773
+ return ref
774
+ })
755
775
  }