farce 0 → 0.1.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 (420) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/CODE_OF_CONDUCT.md +26 -0
  4. data/CONTRIBUTING.md +71 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +1525 -0
  7. data/SECURITY.md +10 -0
  8. data/docs/benchmarks.md +185 -0
  9. data/docs/gems/dry-types.md +290 -0
  10. data/docs/gems/msgpack.md +70 -0
  11. data/docs/gems/ractor-shim.md +63 -0
  12. data/docs/modes.md +628 -0
  13. data/docs/scopes.md +649 -0
  14. data/docs/variants.md +346 -0
  15. data/ext/ext_helper.rb +20 -0
  16. data/ext/farce/README.md +21 -0
  17. data/ext/farce/atom.c +1023 -0
  18. data/ext/farce/bounded_map.c +1683 -0
  19. data/ext/farce/containers.h +77 -0
  20. data/ext/farce/counter.c +399 -0
  21. data/ext/farce/darwin.c +100 -0
  22. data/ext/farce/depend +12 -0
  23. data/ext/farce/dict.c +1523 -0
  24. data/ext/farce/dict.h +152 -0
  25. data/ext/farce/drivers.c +237 -0
  26. data/ext/farce/exchanger.c +299 -0
  27. data/ext/farce/extconf.rb +99 -0
  28. data/ext/farce/farce.c +359 -0
  29. data/ext/farce/flag.c +288 -0
  30. data/ext/farce/io.c +338 -0
  31. data/ext/farce/lock.c +510 -0
  32. data/ext/farce/map.c +2240 -0
  33. data/ext/farce/priority_queue.c +2056 -0
  34. data/ext/farce/queue.c +1059 -0
  35. data/ext/farce/reactor.c +820 -0
  36. data/ext/farce/reactor.h +103 -0
  37. data/ext/farce/shareable.h +31 -0
  38. data/ext/farce/signal.c +350 -0
  39. data/ext/farce/transaction.c +354 -0
  40. data/ext/farce/transaction.h +40 -0
  41. data/ext/farce/tree_map.c +1953 -0
  42. data/ext/farce/trie.c +2020 -0
  43. data/ext/farce/unshareable.c +155 -0
  44. data/ext/farce/unshared_io_pool.h +234 -0
  45. data/ext/farce/unshared_signal.c +263 -0
  46. data/ext/farce/unshared_wait.h +193 -0
  47. data/ext/farce/unsupported.c +6 -0
  48. data/ext/farce/vector.c +1195 -0
  49. data/ext/farce/weak_map.c +1714 -0
  50. data/ext/java/org/farce/BoundedMap.java +394 -0
  51. data/ext/java/org/farce/FiberScheduler.java +141 -0
  52. data/ext/java/org/farce/PriorityKey.java +45 -0
  53. data/ext/java/org/farce/PriorityQueue.java +373 -0
  54. data/ext/java/org/farce/QueueSignal.java +28 -0
  55. data/ext/rebind/README.md +14 -0
  56. data/ext/rebind/extconf.rb +10 -0
  57. data/ext/rebind/rebind.c +186 -0
  58. data/lib/farce/_yard/internal.rb +13 -0
  59. data/lib/farce/_yard/macros.rb +61 -0
  60. data/lib/farce/_yard/ractor.rb +46 -0
  61. data/lib/farce/abstract/atom.rb +186 -0
  62. data/lib/farce/abstract/bounded_map.rb +232 -0
  63. data/lib/farce/abstract/collection.rb +151 -0
  64. data/lib/farce/abstract/concurrent_map.rb +381 -0
  65. data/lib/farce/abstract/counter.rb +193 -0
  66. data/lib/farce/abstract/duplicable_map.rb +229 -0
  67. data/lib/farce/abstract/exchanger.rb +26 -0
  68. data/lib/farce/abstract/flag.rb +71 -0
  69. data/lib/farce/abstract/lazy.rb +115 -0
  70. data/lib/farce/abstract/lease.rb +104 -0
  71. data/lib/farce/abstract/lease_map.rb +261 -0
  72. data/lib/farce/abstract/lease_pool.rb +91 -0
  73. data/lib/farce/abstract/lfu_map.rb +20 -0
  74. data/lib/farce/abstract/lru_map.rb +25 -0
  75. data/lib/farce/abstract/map.rb +345 -0
  76. data/lib/farce/abstract/molecule.rb +245 -0
  77. data/lib/farce/abstract/port.rb +74 -0
  78. data/lib/farce/abstract/priority_queue.rb +117 -0
  79. data/lib/farce/abstract/queue.rb +269 -0
  80. data/lib/farce/abstract/scheduler.rb +111 -0
  81. data/lib/farce/abstract/set.rb +910 -0
  82. data/lib/farce/abstract/sorted_set.rb +172 -0
  83. data/lib/farce/abstract/timer_queue.rb +136 -0
  84. data/lib/farce/abstract/tree_map.rb +269 -0
  85. data/lib/farce/abstract/value.rb +68 -0
  86. data/lib/farce/abstract/vector.rb +1126 -0
  87. data/lib/farce/abstract/weak_atom.rb +32 -0
  88. data/lib/farce/abstract/weak_key_map.rb +12 -0
  89. data/lib/farce/abstract/weak_map.rb +13 -0
  90. data/lib/farce/abstract/weak_set.rb +12 -0
  91. data/lib/farce/abstract/weak_value_map.rb +12 -0
  92. data/lib/farce/abstract.rb +17 -0
  93. data/lib/farce/atom.rb +293 -0
  94. data/lib/farce/class_mirror.rb +87 -0
  95. data/lib/farce/clock.rb +121 -0
  96. data/lib/farce/config.rb +229 -0
  97. data/lib/farce/counter.rb +71 -0
  98. data/lib/farce/deduper.rb +122 -0
  99. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  101. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  102. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  103. data/lib/farce/engine/jruby/map.rb +505 -0
  104. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  105. data/lib/farce/engine/jruby/signal.rb +147 -0
  106. data/lib/farce/engine/jruby.rb +63 -0
  107. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  108. data/lib/farce/engine/jvm/counter.rb +102 -0
  109. data/lib/farce/engine/jvm/extension.rb +32 -0
  110. data/lib/farce/engine/jvm/farce.jar +0 -0
  111. data/lib/farce/engine/jvm/flag.rb +79 -0
  112. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  113. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  114. data/lib/farce/engine/jvm/types.rb +180 -0
  115. data/lib/farce/engine/jvm.rb +19 -0
  116. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  117. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  118. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  119. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  120. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  121. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  122. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  123. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  124. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  125. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  126. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  127. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  128. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  129. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  130. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  131. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  132. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  133. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  134. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  135. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  136. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  137. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  138. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  139. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  140. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  141. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  142. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  143. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  144. data/lib/farce/engine/ruby.rb +130 -0
  145. data/lib/farce/engine/shared/atom.rb +10 -0
  146. data/lib/farce/engine/shared/exchanger.rb +130 -0
  147. data/lib/farce/engine/shared/identity_key.rb +22 -0
  148. data/lib/farce/engine/shared/lease.rb +10 -0
  149. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  150. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  151. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  152. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  153. data/lib/farce/engine/shared/port.rb +44 -0
  154. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  155. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  156. data/lib/farce/engine/shared/queue.rb +233 -0
  157. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  158. data/lib/farce/engine/shared/rebindable.rb +15 -0
  159. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  160. data/lib/farce/engine/shared/strict_map.rb +117 -0
  161. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  162. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  163. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  164. data/lib/farce/engine/shared/trie.rb +317 -0
  165. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  166. data/lib/farce/engine/shared/unshareable.rb +14 -0
  167. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  168. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  169. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  170. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  171. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  172. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  173. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  174. data/lib/farce/engine/shared/vault.rb +31 -0
  175. data/lib/farce/engine/shared/vector.rb +83 -0
  176. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  177. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  178. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  179. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  180. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  181. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  182. data/lib/farce/engine/shared.rb +63 -0
  183. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  184. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  185. data/lib/farce/engine/truffleruby/map.rb +656 -0
  186. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  187. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  188. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  189. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  190. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  191. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  192. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  193. data/lib/farce/engine/truffleruby.rb +148 -0
  194. data/lib/farce/envelope.rb +335 -0
  195. data/lib/farce/error.rb +35 -0
  196. data/lib/farce/exchanger.rb +41 -0
  197. data/lib/farce/flag.rb +27 -0
  198. data/lib/farce/integrations/active_support/blank.rb +68 -0
  199. data/lib/farce/integrations/active_support/clock.rb +17 -0
  200. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  201. data/lib/farce/integrations/active_support/map.rb +175 -0
  202. data/lib/farce/integrations/active_support/set.rb +60 -0
  203. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  204. data/lib/farce/integrations/active_support/vector.rb +231 -0
  205. data/lib/farce/integrations/active_support.rb +9 -0
  206. data/lib/farce/integrations/activesupport.rb +5 -0
  207. data/lib/farce/integrations/bson.rb +108 -0
  208. data/lib/farce/integrations/cbor.rb +51 -0
  209. data/lib/farce/integrations/concurrent.rb +112 -0
  210. data/lib/farce/integrations/dry-types.rb +5 -0
  211. data/lib/farce/integrations/dry_types.rb +694 -0
  212. data/lib/farce/integrations/json.rb +7 -0
  213. data/lib/farce/integrations/msgpack.rb +112 -0
  214. data/lib/farce/integrations/oj.rb +69 -0
  215. data/lib/farce/integrations/psych.rb +191 -0
  216. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  217. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  218. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  219. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  220. data/lib/farce/integrations/shared/to_json.rb +42 -0
  221. data/lib/farce/integrations/sorted_set.rb +11 -0
  222. data/lib/farce/integrations/weakref.rb +38 -0
  223. data/lib/farce/integrations/yajl.rb +10 -0
  224. data/lib/farce/integrations.rb +156 -0
  225. data/lib/farce/internal/_frozen_config.rb +11 -0
  226. data/lib/farce/internal/autoloads.rb +47 -0
  227. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  228. data/lib/farce/internal/converter.rb +106 -0
  229. data/lib/farce/internal/copyable.rb +31 -0
  230. data/lib/farce/internal/delegation.rb +20 -0
  231. data/lib/farce/internal/external_transaction.rb +59 -0
  232. data/lib/farce/internal/fake_ractor.rb +179 -0
  233. data/lib/farce/internal/freeze.rb +118 -0
  234. data/lib/farce/internal/inspect.rb +157 -0
  235. data/lib/farce/internal/key_lock_map.rb +29 -0
  236. data/lib/farce/internal/key_normalizer.rb +289 -0
  237. data/lib/farce/internal/lease_initialization.rb +115 -0
  238. data/lib/farce/internal/lease_map.rb +441 -0
  239. data/lib/farce/internal/lease_pool_state.rb +228 -0
  240. data/lib/farce/internal/lease_state.rb +342 -0
  241. data/lib/farce/internal/lease_waiting.rb +13 -0
  242. data/lib/farce/internal/managed_queue.rb +26 -0
  243. data/lib/farce/internal/map_value_modes.rb +227 -0
  244. data/lib/farce/internal/marshal_support.rb +227 -0
  245. data/lib/farce/internal/mixin.rb +20 -0
  246. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  247. data/lib/farce/internal/noncopyable.rb +17 -0
  248. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  249. data/lib/farce/internal/pool_supervisor.rb +41 -0
  250. data/lib/farce/internal/pool_worker.rb +61 -0
  251. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  252. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  253. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  254. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  255. data/lib/farce/internal/portable_transaction.rb +164 -0
  256. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  257. data/lib/farce/internal/reservation_waiting.rb +24 -0
  258. data/lib/farce/internal/scheduled_task.rb +48 -0
  259. data/lib/farce/internal/scheduler_io.rb +171 -0
  260. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  261. data/lib/farce/internal/select_scheduler.rb +235 -0
  262. data/lib/farce/internal/storage.rb +162 -0
  263. data/lib/farce/internal/strict_lease.rb +30 -0
  264. data/lib/farce/internal/strict_lease_map.rb +20 -0
  265. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  266. data/lib/farce/internal/thread_pool.rb +166 -0
  267. data/lib/farce/internal/transaction_conflict.rb +9 -0
  268. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  269. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  270. data/lib/farce/internal/undefined.rb +22 -0
  271. data/lib/farce/internal/unshared_lease.rb +29 -0
  272. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  273. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  274. data/lib/farce/internal/value_serialization.rb +13 -0
  275. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  276. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  277. data/lib/farce/internal.rb +129 -0
  278. data/lib/farce/lazy.rb +100 -0
  279. data/lib/farce/lazy_ref.rb +40 -0
  280. data/lib/farce/lease.rb +28 -0
  281. data/lib/farce/lease_map.rb +34 -0
  282. data/lib/farce/lease_pool.rb +29 -0
  283. data/lib/farce/lfu_map.rb +53 -0
  284. data/lib/farce/local/atom.rb +23 -0
  285. data/lib/farce/local/counter.rb +88 -0
  286. data/lib/farce/local/flag.rb +65 -0
  287. data/lib/farce/local/lazy.rb +38 -0
  288. data/lib/farce/local/lazy_ref.rb +36 -0
  289. data/lib/farce/local/lease.rb +77 -0
  290. data/lib/farce/local/lease_map.rb +80 -0
  291. data/lib/farce/local/lease_pool.rb +38 -0
  292. data/lib/farce/local/lfu_map.rb +55 -0
  293. data/lib/farce/local/lru_map.rb +62 -0
  294. data/lib/farce/local/map.rb +47 -0
  295. data/lib/farce/local/molecule.rb +45 -0
  296. data/lib/farce/local/priority_queue.rb +53 -0
  297. data/lib/farce/local/queue.rb +32 -0
  298. data/lib/farce/local/scoped.rb +166 -0
  299. data/lib/farce/local/set.rb +18 -0
  300. data/lib/farce/local/sorted_set.rb +50 -0
  301. data/lib/farce/local/timer_queue.rb +41 -0
  302. data/lib/farce/local/tree_map.rb +47 -0
  303. data/lib/farce/local/vector.rb +30 -0
  304. data/lib/farce/local/weak_atom.rb +23 -0
  305. data/lib/farce/local/weak_key_map.rb +39 -0
  306. data/lib/farce/local/weak_map.rb +39 -0
  307. data/lib/farce/local/weak_set.rb +18 -0
  308. data/lib/farce/local/weak_value_map.rb +39 -0
  309. data/lib/farce/local.rb +35 -0
  310. data/lib/farce/lock.rb +54 -0
  311. data/lib/farce/lru_map.rb +63 -0
  312. data/lib/farce/map.rb +58 -0
  313. data/lib/farce/mode_manager.rb +142 -0
  314. data/lib/farce/molecule.rb +60 -0
  315. data/lib/farce/mutable.rb +171 -0
  316. data/lib/farce/pool.rb +332 -0
  317. data/lib/farce/port.rb +134 -0
  318. data/lib/farce/priority_queue.rb +70 -0
  319. data/lib/farce/proxy/register.rb +101 -0
  320. data/lib/farce/proxy/supervisor.rb +137 -0
  321. data/lib/farce/proxy/wrapper.rb +49 -0
  322. data/lib/farce/proxy.rb +291 -0
  323. data/lib/farce/queue.rb +60 -0
  324. data/lib/farce/ractor.rb +269 -0
  325. data/lib/farce/read_write_lock.rb +256 -0
  326. data/lib/farce/reference.rb +158 -0
  327. data/lib/farce/resolv/dns.rb +42 -0
  328. data/lib/farce/resolv.rb +85 -0
  329. data/lib/farce/scheduler.rb +536 -0
  330. data/lib/farce/set.rb +39 -0
  331. data/lib/farce/shareable.rb +150 -0
  332. data/lib/farce/signal.rb +97 -0
  333. data/lib/farce/sorted_set.rb +36 -0
  334. data/lib/farce/strict/atom.rb +34 -0
  335. data/lib/farce/strict/counter.rb +10 -0
  336. data/lib/farce/strict/exchanger.rb +25 -0
  337. data/lib/farce/strict/flag.rb +10 -0
  338. data/lib/farce/strict/lazy.rb +26 -0
  339. data/lib/farce/strict/lazy_ref.rb +26 -0
  340. data/lib/farce/strict/lease.rb +27 -0
  341. data/lib/farce/strict/lease_map.rb +33 -0
  342. data/lib/farce/strict/lease_pool.rb +28 -0
  343. data/lib/farce/strict/lfu_map.rb +27 -0
  344. data/lib/farce/strict/lru_map.rb +28 -0
  345. data/lib/farce/strict/map.rb +54 -0
  346. data/lib/farce/strict/molecule.rb +16 -0
  347. data/lib/farce/strict/port.rb +40 -0
  348. data/lib/farce/strict/priority_queue.rb +20 -0
  349. data/lib/farce/strict/queue.rb +17 -0
  350. data/lib/farce/strict/set.rb +14 -0
  351. data/lib/farce/strict/sorted_set.rb +19 -0
  352. data/lib/farce/strict/timer_queue.rb +13 -0
  353. data/lib/farce/strict/tree_map.rb +27 -0
  354. data/lib/farce/strict/vector.rb +24 -0
  355. data/lib/farce/strict/weak_atom.rb +31 -0
  356. data/lib/farce/strict/weak_key_map.rb +49 -0
  357. data/lib/farce/strict/weak_map.rb +49 -0
  358. data/lib/farce/strict/weak_set.rb +14 -0
  359. data/lib/farce/strict/weak_value_map.rb +48 -0
  360. data/lib/farce/strict.rb +28 -0
  361. data/lib/farce/system.rb +40 -0
  362. data/lib/farce/thread_scheduler.rb +70 -0
  363. data/lib/farce/timer_queue.rb +66 -0
  364. data/lib/farce/transaction/atom.rb +73 -0
  365. data/lib/farce/transaction/map.rb +25 -0
  366. data/lib/farce/transaction/map_operations.rb +143 -0
  367. data/lib/farce/transaction/molecule.rb +90 -0
  368. data/lib/farce/transaction/mutable.rb +61 -0
  369. data/lib/farce/transaction/set.rb +17 -0
  370. data/lib/farce/transaction/set_operations.rb +48 -0
  371. data/lib/farce/transaction/sorted_set.rb +18 -0
  372. data/lib/farce/transaction/tree_map.rb +78 -0
  373. data/lib/farce/transaction/vector.rb +139 -0
  374. data/lib/farce/transaction/wrapper.rb +202 -0
  375. data/lib/farce/transaction.rb +343 -0
  376. data/lib/farce/tree_map.rb +56 -0
  377. data/lib/farce/unsafe/lfu_map.rb +36 -0
  378. data/lib/farce/unsafe/lru_map.rb +36 -0
  379. data/lib/farce/unsafe/tree_map.rb +21 -0
  380. data/lib/farce/unsafe.rb +29 -0
  381. data/lib/farce/unshareable.rb +67 -0
  382. data/lib/farce/unshared/atom.rb +24 -0
  383. data/lib/farce/unshared/counter.rb +10 -0
  384. data/lib/farce/unshared/flag.rb +10 -0
  385. data/lib/farce/unshared/lazy.rb +38 -0
  386. data/lib/farce/unshared/lazy_ref.rb +26 -0
  387. data/lib/farce/unshared/lease.rb +27 -0
  388. data/lib/farce/unshared/lease_map.rb +26 -0
  389. data/lib/farce/unshared/lease_pool.rb +25 -0
  390. data/lib/farce/unshared/lfu_map.rb +20 -0
  391. data/lib/farce/unshared/lru_map.rb +20 -0
  392. data/lib/farce/unshared/map.rb +49 -0
  393. data/lib/farce/unshared/molecule.rb +16 -0
  394. data/lib/farce/unshared/priority_queue.rb +16 -0
  395. data/lib/farce/unshared/queue.rb +27 -0
  396. data/lib/farce/unshared/set.rb +14 -0
  397. data/lib/farce/unshared/sorted_set.rb +28 -0
  398. data/lib/farce/unshared/timer_queue.rb +16 -0
  399. data/lib/farce/unshared/tree_map.rb +21 -0
  400. data/lib/farce/unshared/vector.rb +19 -0
  401. data/lib/farce/unshared/weak_atom.rb +31 -0
  402. data/lib/farce/unshared/weak_key_map.rb +44 -0
  403. data/lib/farce/unshared/weak_map.rb +44 -0
  404. data/lib/farce/unshared/weak_set.rb +14 -0
  405. data/lib/farce/unshared/weak_value_map.rb +43 -0
  406. data/lib/farce/unshared.rb +28 -0
  407. data/lib/farce/vector.rb +228 -0
  408. data/lib/farce/version.rb +8 -0
  409. data/lib/farce/walker/definitions.rb +186 -0
  410. data/lib/farce/walker/modification.rb +355 -0
  411. data/lib/farce/walker.rb +319 -0
  412. data/lib/farce/weak_atom.rb +121 -0
  413. data/lib/farce/weak_key_map.rb +31 -0
  414. data/lib/farce/weak_map.rb +33 -0
  415. data/lib/farce/weak_ref.rb +67 -0
  416. data/lib/farce/weak_set.rb +82 -0
  417. data/lib/farce/weak_value.rb +195 -0
  418. data/lib/farce/weak_value_map.rb +32 -0
  419. data/lib/farce.rb +519 -0
  420. metadata +435 -8
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # Implements the staged reads and writes shared by Map and TreeMap wrappers.
8
+ #
9
+ # The participant supplies key normalization and value transfer rules.
10
+ # Operations use the backend snapshot enrolled in the transaction, so they
11
+ # see earlier staged writes without modifying the participant before commit.
12
+ #
13
+ # @!visibility private
14
+ module MapOperations # :nodoc: all
15
+ include Wrapper
16
+
17
+ READ_HELPERS = %i[
18
+ assoc compare_by_identity? dig length value? has_value? key rassoc has_key? member? include?
19
+ fetch_values to_a to_h to_hash deconstruct_keys values_at weak_keys? weak_values? inspect to_s
20
+ pretty_print values flatten to_proc
21
+ ].freeze
22
+
23
+ def [](key) = access { unwrap_stored(@working[prepare(key)]) }
24
+
25
+ def []=(key, value)
26
+ store(key, value)
27
+ end
28
+
29
+ def fetch(key, *defaults)
30
+ access do
31
+ raise ArgumentError, "expected at most one default" if defaults.size > 1
32
+ canonical = prepare(key)
33
+ next unwrap_stored(@working[canonical]) if @working.key?(canonical)
34
+ next yield(key) if block_given?
35
+ next defaults.first unless defaults.empty?
36
+ raise KeyError.new("key not found: #{key.inspect}", receiver: @object, key:)
37
+ end
38
+ end
39
+
40
+ def compare_keys_by_identity? = access { @object.compare_keys_by_identity? }
41
+ def compare_values_by_identity? = access { @object.compare_values_by_identity? }
42
+ def delete(key) = write { unwrap_stored(@working.delete(prepare(key))) }
43
+ def empty? = size.zero?
44
+ def get(key) = self[key]
45
+ def getkey(key) = access { @working.getkey(prepare(key)) }
46
+ def key?(key) = access { @working.key?(prepare(key)) }
47
+ def keys = access { @working.keys }
48
+ def shareable_keys? = access { @object.shareable_keys? }
49
+ def shareable_values? = access { @object.shareable_values? }
50
+ def size = access { @working.size }
51
+ def store(key, value, mode: nil) = write { unwrap_stored(store_value(prepare(key), wrap(value, mode:))) }
52
+ def swap(key, value, mode: nil) = write { unwrap_stored(@working.swap(prepare(key), wrap(value, mode:))) }
53
+
54
+ def each
55
+ return enum_for(__method__) unless block_given?
56
+ access { @working.each { |key, value| yield key, unwrap_stored(value) } }
57
+ self
58
+ end
59
+ alias each_pair each
60
+ alias each_live each
61
+
62
+ def clear
63
+ write { @working.clear }
64
+ self
65
+ end
66
+
67
+ def update(key, mode: nil)
68
+ require_block!(block_given?)
69
+ write do
70
+ canonical = prepare(key)
71
+ unwrap_stored(store_value(canonical, wrap(yield(unwrap_stored(@working[canonical])), mode:)))
72
+ end
73
+ end
74
+
75
+ def store_if_absent(key, mode: nil)
76
+ require_block!(block_given?)
77
+ write do
78
+ canonical = prepare(key)
79
+ next unwrap_stored(@working[canonical]) if @working.key?(canonical)
80
+ unwrap_stored(store_value(canonical, wrap(yield, mode:)))
81
+ end
82
+ end
83
+
84
+ def upsert(key, initial, mode: nil)
85
+ require_block!(block_given?)
86
+ write do
87
+ canonical = prepare(key)
88
+ value = @working.key?(canonical) ? yield(unwrap_stored(@working[canonical])) : initial
89
+ unwrap_stored(store_value(canonical, wrap(value, mode:)))
90
+ end
91
+ end
92
+
93
+ def compare_and_set(key, expected, replacement, mode: nil)
94
+ write do
95
+ canonical = prepare(key)
96
+ next compared(@working.compare_and_set(canonical, expected, replacement)) unless @manager
97
+ next compared(false) unless @working.key?(canonical) &&
98
+ matches?(@working[canonical], expected, identity: @object.compare_values_by_identity?)
99
+ store_value(canonical, wrap(replacement, mode:))
100
+ true
101
+ end
102
+ end
103
+
104
+ def each_key
105
+ return enum_for(__method__) { size } unless block_given?
106
+ each { |key, _| yield key }
107
+ self
108
+ end
109
+
110
+ def each_value
111
+ return enum_for(__method__) { size } unless block_given?
112
+ each { |_, value| yield value }
113
+ self
114
+ end
115
+
116
+ private
117
+
118
+ def store_value(key, value) = @working.store(key, value)
119
+
120
+ def modify_entry(key, canonical: false)
121
+ write do
122
+ key = prepare(key) unless canonical
123
+ present = @working.key?(key)
124
+ replacement = yield(present, present ? unwrap_stored(@working[key]) : nil)
125
+ next false if Internal::MAP_KEEP.equal?(replacement)
126
+ if Internal::MAP_DELETE.equal?(replacement)
127
+ @working.delete(key)
128
+ present
129
+ else
130
+ store_value(key, wrap(replacement))
131
+ end
132
+ end
133
+ end
134
+
135
+ def prepare(key)
136
+ return @backend.transaction_key(key) if @backend.respond_to?(:transaction_key)
137
+ @backend.respond_to?(:normalize_external_key) ? @backend.normalize_external_key(key) : key
138
+ end
139
+ end
140
+
141
+ private_constant :MapOperations
142
+ end
143
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # A {Abstract::Molecule Molecule} that is part of a transaction.
8
+ class Molecule < Abstract::Molecule
9
+ include Wrapper
10
+
11
+ # @api private
12
+ def initialize(transaction, object)
13
+ super
14
+ @members = object.members
15
+ @atoms = object.each_atom.to_h.transform_values { transaction[it] }
16
+ @fields = @members.to_h { [it, @atoms.fetch(:"#{it}_atom")] }
17
+ @writers = @members.to_h { [:"#{it}=", @atoms.fetch(:"#{it}_atom")] }
18
+ # A field named map or count must read its atom, not call the inherited
19
+ # Enumerable method. Define those readers before method_missing is needed.
20
+ @members.each do |field|
21
+ next unless Enumerable.method_defined?(field)
22
+ atom = @fields.fetch(field)
23
+ define_singleton_method(field) { access { atom.value } }
24
+ end
25
+ end
26
+
27
+ # (see Abstract::Molecule#compare_by_identity?)
28
+ # @see Abstract::Molecule#compare_by_identity?
29
+ def compare_by_identity? = access { @object.compare_by_identity? }
30
+
31
+ # (see Abstract::Molecule#members)
32
+ # @see Abstract::Molecule#members
33
+ def members = access { @members }
34
+
35
+ # (see Abstract::Molecule#atoms)
36
+ # @see Abstract::Molecule#atoms
37
+ def atoms = access { @atoms.keys.freeze }
38
+
39
+ # (see Abstract::Molecule#each)
40
+ # @see Abstract::Molecule#each
41
+ def each
42
+ return enum_for(__method__) unless block_given?
43
+ access { @members.each { yield it, @atoms.fetch(:"#{it}_atom").value } }
44
+ self
45
+ end
46
+ alias each_pair each
47
+
48
+ # (see Abstract::Molecule#each_atom)
49
+ # @see Abstract::Molecule#each_atom
50
+ def each_atom
51
+ return enum_for(__method__) unless block_given?
52
+ access { @atoms.each { yield _1, _2 } }
53
+ self
54
+ end
55
+
56
+ # (see Abstract::Molecule#each_member)
57
+ # @see Abstract::Molecule#each_member
58
+ def each_member
59
+ return enum_for(__method__) unless block_given?
60
+ access { @members.each { yield it } }
61
+ self
62
+ end
63
+ alias each_key each_member
64
+
65
+ # (see Abstract::Molecule#each_value)
66
+ # @see Abstract::Molecule#each_value
67
+ def each_value
68
+ return enum_for(__method__) unless block_given?
69
+ each { |_, value| yield value }
70
+ self
71
+ end
72
+
73
+ private
74
+
75
+ def method_missing(name, *arguments, **options, &block)
76
+ return access { @atoms.fetch(name) } if @atoms.key?(name) && arguments.empty? && options.empty? && !block
77
+ return super unless options.empty? && !block
78
+ return access { @fields.fetch(name).value } if @fields.key?(name) && arguments.empty?
79
+ return write { @writers.fetch(name).value = arguments.first } if @writers.key?(name) && arguments.size == 1
80
+ super
81
+ end
82
+
83
+ def respond_to_missing?(name, include_private = false)
84
+ @atoms.key?(name) || @fields.key?(name) || @writers.key?(name) || super
85
+ end
86
+
87
+ Wrapper.inherit(self, :compare_by_identity?)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # A {Farce::Mutable} that stages method calls within a transaction.
8
+ #
9
+ # Reads use the attempt's current snapshot. Mutations replace only its staged
10
+ # value and are published with the other participants when the attempt commits.
11
+ # Snapshots must be frozen. Use a dedicated transaction participant for a
12
+ # shareable object whose state can change while it remains unfrozen.
13
+ class Mutable < Farce::Mutable
14
+ include Wrapper
15
+
16
+ # @api private
17
+ def initialize(transaction, object, backend)
18
+ super
19
+ @atom = Atom.new(transaction, object, backend)
20
+ return if @atom.value.frozen?
21
+ ::Kernel.raise(::TypeError, "mutable transactions require a frozen snapshot")
22
+ end
23
+
24
+ # @api private
25
+ def marshal_dump = ::Kernel.raise(::TypeError, "transaction wrappers cannot be marshaled")
26
+
27
+ # @api private
28
+ def respond_to?(name, include_private = false) # rubocop:disable Style/OptionalBooleanParameter
29
+ access { name != :freeze && super }
30
+ end
31
+
32
+ # @api private
33
+ def frozen? = access { @object.frozen? }
34
+
35
+ private
36
+
37
+ # Wrapper's error guards must raise locally rather than delegate to the value.
38
+ def raise(...) = ::Kernel.raise(...)
39
+
40
+ def method_missing(name, ...) # rubocop:disable Style/MissingRespondToMissing
41
+ access do
42
+ ::Kernel.raise(::NoMethodError, "transaction wrappers cannot be frozen") if name == :freeze
43
+ begin
44
+ @atom.value.__send__(name, ...)
45
+ rescue ::FrozenError
46
+ result = nil
47
+ @atom.update do |current|
48
+ copy = current.dup
49
+ result = copy.__send__(name, ...)
50
+ result = self if result.equal?(copy)
51
+ copy.freeze
52
+ end
53
+ result
54
+ end
55
+ end
56
+ end
57
+
58
+ Wrapper.inherit(self, :is_a?, :pretty_print_cycle)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # A {Abstract::Set Set} that is part of a transaction.
8
+ #
9
+ # Membership reads and changes validate the members they access.
10
+ # Size reads validate cardinality. Enumeration captures the full set.
11
+ class Set < Abstract::Set
12
+ include SetOperations
13
+
14
+ Wrapper.inherit(self, *SetOperations::READ_HELPERS, writes: SetOperations::WRITE_HELPERS)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # Initializes Set and SortedSet wrappers with a transactional backing map.
8
+ # Abstract::Set's methods operate directly on this wrapper's @map. The map
9
+ # owns the snapshot and commit logic. Only membership settings and transfer
10
+ # checks belong here, because some transfers change values before insertion.
11
+ # @!visibility private
12
+ module SetOperations # :nodoc: all
13
+ include Wrapper
14
+
15
+ READ_HELPERS = %i[
16
+ each size length empty? count include? member? === compare_by_identity? weak?
17
+ == eql? hash subset? proper_subset? superset? proper_superset? intersect? disjoint? <=>
18
+ <= < >= > join inspect to_s to_set each_stored equality_index ordered? public_stored
19
+ ].freeze
20
+ WRITE_HELPERS = %i[add << add? delete delete? clear merge subtract].freeze
21
+
22
+ def initialize(transaction, object, map)
23
+ super(transaction, object)
24
+ compose(:normalizer, :compare_by_identity, :manager, map:)
25
+ @value_modes = object.method(:value_modes?).call
26
+ end
27
+
28
+ def value_modes? = access { @value_modes }
29
+
30
+ private
31
+
32
+ def add_mode_value?(element, mode:)
33
+ selected = UNDEFINED.equal?(mode) || mode.nil? ? @manager.mode : mode
34
+ if %i[move make_shareable dedup proxy].include?(selected)
35
+ raise TypeError, "#{selected} transfers do not support transactions"
36
+ end
37
+ super
38
+ end
39
+
40
+ def unwrap_entry(key, entry)
41
+ raise TypeError, "move envelopes do not support transactions" if Envelope::Move === entry.payload
42
+ super
43
+ end
44
+ end
45
+
46
+ private_constant :SetOperations
47
+ end
48
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # A {Abstract::SortedSet SortedSet} that is part of a transaction.
8
+ class SortedSet < Abstract::SortedSet
9
+ include SetOperations
10
+
11
+ Wrapper.inherit(self, *SetOperations::READ_HELPERS, :ordered_keys, writes: SetOperations::WRITE_HELPERS)
12
+
13
+ # SortedSet builds temporary membership indexes for comparisons. Use the
14
+ # participant's map factory to retain support for mutable Local keys.
15
+ private def new_map(...) = @object.method(:new_map).call(...)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # A {Abstract::TreeMap TreeMap} that is part of a transaction.
8
+ class TreeMap < Abstract::TreeMap
9
+ include MapOperations
10
+
11
+ # (see Abstract::TreeMap#first_key)
12
+ # @see Abstract::TreeMap#first_key
13
+ def first_key = access { @working.first_key }
14
+
15
+ # (see Abstract::TreeMap#last_key)
16
+ # @see Abstract::TreeMap#last_key
17
+ def last_key = access { @working.last_key }
18
+
19
+ # (see Abstract::TreeMap#getkey)
20
+ # @see Abstract::TreeMap#getkey
21
+ def getkey(key) = access { @working.getkey(prepare(key)) }
22
+
23
+ # (see Abstract::TreeMap#keys)
24
+ # @see Abstract::TreeMap#keys
25
+ def keys = access { @working.each.map { |key, _| key }.freeze }
26
+
27
+ # (see Abstract::TreeMap#pop)
28
+ # @see Abstract::TreeMap#pop
29
+ def pop = write { public_pair(@working.pop) }
30
+
31
+ # (see Abstract::TreeMap#shift)
32
+ # @see Abstract::TreeMap#shift
33
+ def shift = write { public_pair(@working.shift) }
34
+
35
+ # (see Abstract::TreeMap#swap)
36
+ # @see Abstract::TreeMap#swap
37
+ def swap(key, value, mode: nil)
38
+ write do
39
+ canonical = prepare(key)
40
+ previous = unwrap_stored(@working[canonical])
41
+ store_value(canonical, wrap(value, mode:))
42
+ previous
43
+ end
44
+ end
45
+
46
+ # (see Abstract::TreeMap#compare_and_set)
47
+ # @see Abstract::TreeMap#compare_and_set
48
+ def compare_and_set(key, expected, replacement, mode: nil)
49
+ write do
50
+ canonical = prepare(key)
51
+ next compared(false) unless @working.key?(canonical)
52
+ current = @working[canonical]
53
+ matches = @manager ? matches?(current, expected, identity: false) : current == expected
54
+ next compared(false) unless matches
55
+ store_value(canonical, wrap(replacement, mode:))
56
+ true
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def store_value(key, value)
63
+ @working[key] = value
64
+ end
65
+
66
+ def prepare(key)
67
+ normalizer = @object.instance_variable_get(:@key_normalizer)
68
+ @working.prepare_key(normalizer ? normalizer.call(key) : key)
69
+ end
70
+
71
+ def public_pair(pair)
72
+ [pair.first, unwrap_stored(pair.last)] if pair
73
+ end
74
+
75
+ Wrapper.inherit(self, *MapOperations::READ_HELPERS)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ class Transaction
7
+ # A {Abstract::Vector Vector} that is part of a transaction.
8
+ class Vector < Abstract::Vector
9
+ include Wrapper
10
+
11
+ # (see Abstract::Vector#compare_by_identity?)
12
+ # @see Abstract::Vector#compare_by_identity?
13
+ def compare_by_identity? = access { @object.compare_by_identity? }
14
+
15
+ # (see Abstract::Vector#shareable_values?)
16
+ # @see Abstract::Vector#shareable_values?
17
+ def shareable_values? = access { @object.shareable_values? }
18
+
19
+ # (see Abstract::Vector#[])
20
+ # @see Abstract::Vector#[]
21
+ def [](index) = access { unwrap_stored(@working[index]) }
22
+
23
+ # (see Abstract::Vector#get)
24
+ # @see Abstract::Vector#get
25
+ def get(index) = self[index]
26
+
27
+ # (see Abstract::Vector#size)
28
+ # @see Abstract::Vector#size
29
+ def size = access { @working.size }
30
+
31
+ # (see Abstract::Vector#empty?)
32
+ # @see Abstract::Vector#empty?
33
+ def empty? = size.zero?
34
+
35
+ # (see Abstract::Vector#[]=)
36
+ # @see Abstract::Vector#[]=
37
+ def []=(index, value)
38
+ store(index, value)
39
+ end
40
+
41
+ # (see Abstract::Vector#store)
42
+ # @see Abstract::Vector#store
43
+ def store(index, value, mode: nil)
44
+ write { unwrap_stored(@working.store(index, wrap(value, mode:))) }
45
+ end
46
+
47
+ # (see Abstract::Vector#swap)
48
+ # @see Abstract::Vector#swap
49
+ def swap(index, value, mode: nil)
50
+ write { unwrap_stored(@working.swap(index, wrap(value, mode:))) }
51
+ end
52
+
53
+ # (see Abstract::Vector#push)
54
+ # @see Abstract::Vector#push
55
+ def push(value, mode: nil)
56
+ write { @working.push(wrap(value, mode:)) }
57
+ self
58
+ end
59
+ alias << push
60
+
61
+ # (see Abstract::Vector#pop)
62
+ # @see Abstract::Vector#pop
63
+ def pop = write { unwrap_stored(@working.pop) }
64
+
65
+ # (see Abstract::Vector#clear)
66
+ # @see Abstract::Vector#clear
67
+ def clear
68
+ write { @working.clear }
69
+ self
70
+ end
71
+
72
+ # (see Abstract::Vector#each)
73
+ # @see Abstract::Vector#each
74
+ def each
75
+ return enum_for(__method__) unless block_given?
76
+ access { @working.snapshot.each { |value| yield unwrap_stored(value) } }
77
+ self
78
+ end
79
+
80
+ # (see Abstract::Vector#update)
81
+ # @see Abstract::Vector#update
82
+ def update(index, mode: nil)
83
+ require_block!(block_given?)
84
+ write { unwrap_stored(@working.update(index) { |value| wrap(yield(unwrap_stored(value)), mode:) }) }
85
+ end
86
+
87
+ # (see Abstract::Vector#store_if_absent)
88
+ # @see Abstract::Vector#store_if_absent
89
+ def store_if_absent(index, mode: nil)
90
+ require_block!(block_given?)
91
+ write { unwrap_stored(@working.store_if_absent(index) { wrap(yield, mode:) }) }
92
+ end
93
+
94
+ # (see Abstract::Vector#upsert)
95
+ # @see Abstract::Vector#upsert
96
+ def upsert(index, initial, mode: nil)
97
+ require_block!(block_given?)
98
+ write do
99
+ unwrap_stored(@working.upsert(index, wrap(initial, mode:)) do |value|
100
+ wrap(yield(unwrap_stored(value)), mode:)
101
+ end)
102
+ end
103
+ end
104
+
105
+ # (see Abstract::Vector#compare_and_set)
106
+ # @see Abstract::Vector#compare_and_set
107
+ def compare_and_set(index, expected, replacement, mode: nil)
108
+ write do
109
+ next compared(@working.compare_and_set(index, expected, replacement)) unless @manager
110
+ index = Integer(index)
111
+ next compared(false) unless index >= -@working.size && index < @working.size &&
112
+ matches?(@working[index], expected, identity: @object.compare_by_identity?)
113
+ @working.store(index, wrap(replacement, mode:))
114
+ true
115
+ end
116
+ end
117
+
118
+ protected
119
+
120
+ def internal_vector = @working
121
+ def logical_value(value) = unwrap_stored(value)
122
+
123
+ # Slice helpers return independent data rather than another participant.
124
+ # Use an ordinary vector that remains usable after the attempt ends.
125
+ def build_derived_vector(values)
126
+ Unshared::Vector.new(values.map { unwrap_stored(it) }, compare_by_identity: compare_by_identity?)
127
+ end
128
+
129
+ private
130
+
131
+ def inspect_value(inspector, value) = super(inspector, value, @manager)
132
+ def derived_storage(value) = wrap(value)
133
+
134
+ Wrapper.inherit(self, :each_index, :reverse_each, :to_a, :deconstruct, :to_h, :join, :dig, :assoc,
135
+ :rassoc, :at, :fetch, :fetch_values, :values_at, :slice, :rfind, :bsearch, :bsearch_index, :pack,
136
+ :length, :count, :compare_by_identity?, :shareable_values?)
137
+ end
138
+ end
139
+ end