farce 0.0.1.alpha2-x86-linux-gnu

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 (423) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +26 -0
  3. data/CONTRIBUTING.md +71 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1524 -0
  6. data/SECURITY.md +10 -0
  7. data/docs/benchmarks.md +185 -0
  8. data/docs/gems/dry-types.md +290 -0
  9. data/docs/gems/msgpack.md +70 -0
  10. data/docs/gems/ractor-shim.md +63 -0
  11. data/docs/modes.md +628 -0
  12. data/docs/scopes.md +649 -0
  13. data/docs/variants.md +346 -0
  14. data/ext/ext_helper.rb +20 -0
  15. data/ext/farce/README.md +21 -0
  16. data/ext/farce/atom.c +1023 -0
  17. data/ext/farce/bounded_map.c +1683 -0
  18. data/ext/farce/containers.h +77 -0
  19. data/ext/farce/counter.c +399 -0
  20. data/ext/farce/darwin.c +100 -0
  21. data/ext/farce/depend +12 -0
  22. data/ext/farce/dict.c +1523 -0
  23. data/ext/farce/dict.h +152 -0
  24. data/ext/farce/drivers.c +237 -0
  25. data/ext/farce/exchanger.c +299 -0
  26. data/ext/farce/extconf.rb +99 -0
  27. data/ext/farce/farce.c +359 -0
  28. data/ext/farce/flag.c +288 -0
  29. data/ext/farce/io.c +338 -0
  30. data/ext/farce/lock.c +510 -0
  31. data/ext/farce/map.c +2240 -0
  32. data/ext/farce/priority_queue.c +2056 -0
  33. data/ext/farce/queue.c +1059 -0
  34. data/ext/farce/reactor.c +820 -0
  35. data/ext/farce/reactor.h +103 -0
  36. data/ext/farce/shareable.h +31 -0
  37. data/ext/farce/signal.c +350 -0
  38. data/ext/farce/transaction.c +354 -0
  39. data/ext/farce/transaction.h +40 -0
  40. data/ext/farce/tree_map.c +1953 -0
  41. data/ext/farce/trie.c +2020 -0
  42. data/ext/farce/unshareable.c +155 -0
  43. data/ext/farce/unshared_io_pool.h +234 -0
  44. data/ext/farce/unshared_signal.c +263 -0
  45. data/ext/farce/unshared_wait.h +193 -0
  46. data/ext/farce/unsupported.c +6 -0
  47. data/ext/farce/vector.c +1195 -0
  48. data/ext/farce/weak_map.c +1714 -0
  49. data/ext/java/org/farce/BoundedMap.java +394 -0
  50. data/ext/java/org/farce/FiberScheduler.java +141 -0
  51. data/ext/java/org/farce/PriorityKey.java +45 -0
  52. data/ext/java/org/farce/PriorityQueue.java +373 -0
  53. data/ext/java/org/farce/QueueSignal.java +28 -0
  54. data/ext/rebind/README.md +14 -0
  55. data/ext/rebind/extconf.rb +10 -0
  56. data/ext/rebind/rebind.c +186 -0
  57. data/lib/farce/_yard/internal.rb +13 -0
  58. data/lib/farce/_yard/macros.rb +61 -0
  59. data/lib/farce/_yard/ractor.rb +46 -0
  60. data/lib/farce/abstract/atom.rb +186 -0
  61. data/lib/farce/abstract/bounded_map.rb +232 -0
  62. data/lib/farce/abstract/collection.rb +151 -0
  63. data/lib/farce/abstract/concurrent_map.rb +381 -0
  64. data/lib/farce/abstract/counter.rb +193 -0
  65. data/lib/farce/abstract/duplicable_map.rb +229 -0
  66. data/lib/farce/abstract/exchanger.rb +26 -0
  67. data/lib/farce/abstract/flag.rb +71 -0
  68. data/lib/farce/abstract/lazy.rb +115 -0
  69. data/lib/farce/abstract/lease.rb +104 -0
  70. data/lib/farce/abstract/lease_map.rb +261 -0
  71. data/lib/farce/abstract/lease_pool.rb +91 -0
  72. data/lib/farce/abstract/lfu_map.rb +20 -0
  73. data/lib/farce/abstract/lru_map.rb +25 -0
  74. data/lib/farce/abstract/map.rb +345 -0
  75. data/lib/farce/abstract/molecule.rb +245 -0
  76. data/lib/farce/abstract/port.rb +74 -0
  77. data/lib/farce/abstract/priority_queue.rb +117 -0
  78. data/lib/farce/abstract/queue.rb +269 -0
  79. data/lib/farce/abstract/scheduler.rb +111 -0
  80. data/lib/farce/abstract/set.rb +910 -0
  81. data/lib/farce/abstract/sorted_set.rb +172 -0
  82. data/lib/farce/abstract/timer_queue.rb +136 -0
  83. data/lib/farce/abstract/tree_map.rb +269 -0
  84. data/lib/farce/abstract/value.rb +68 -0
  85. data/lib/farce/abstract/vector.rb +1126 -0
  86. data/lib/farce/abstract/weak_atom.rb +32 -0
  87. data/lib/farce/abstract/weak_key_map.rb +12 -0
  88. data/lib/farce/abstract/weak_map.rb +13 -0
  89. data/lib/farce/abstract/weak_set.rb +12 -0
  90. data/lib/farce/abstract/weak_value_map.rb +12 -0
  91. data/lib/farce/abstract.rb +17 -0
  92. data/lib/farce/atom.rb +293 -0
  93. data/lib/farce/class_mirror.rb +87 -0
  94. data/lib/farce/clock.rb +121 -0
  95. data/lib/farce/config.rb +229 -0
  96. data/lib/farce/counter.rb +71 -0
  97. data/lib/farce/deduper.rb +122 -0
  98. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  99. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  101. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  102. data/lib/farce/engine/jruby/map.rb +505 -0
  103. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  104. data/lib/farce/engine/jruby/signal.rb +147 -0
  105. data/lib/farce/engine/jruby.rb +63 -0
  106. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  107. data/lib/farce/engine/jvm/counter.rb +102 -0
  108. data/lib/farce/engine/jvm/extension.rb +32 -0
  109. data/lib/farce/engine/jvm/farce.jar +0 -0
  110. data/lib/farce/engine/jvm/flag.rb +79 -0
  111. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  112. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  113. data/lib/farce/engine/jvm/types.rb +180 -0
  114. data/lib/farce/engine/jvm.rb +19 -0
  115. data/lib/farce/engine/ruby/3.4/farce.so +0 -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/rebind.so +0 -0
  121. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  122. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  123. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  124. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  125. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  126. data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
  127. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  128. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  129. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  130. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  131. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  132. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  133. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  134. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  135. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  136. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  137. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  138. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  139. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  140. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  141. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  142. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  143. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  144. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  145. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  146. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  147. data/lib/farce/engine/ruby.rb +130 -0
  148. data/lib/farce/engine/shared/atom.rb +10 -0
  149. data/lib/farce/engine/shared/exchanger.rb +130 -0
  150. data/lib/farce/engine/shared/identity_key.rb +22 -0
  151. data/lib/farce/engine/shared/lease.rb +10 -0
  152. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  153. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  154. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  155. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  156. data/lib/farce/engine/shared/port.rb +44 -0
  157. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  158. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  159. data/lib/farce/engine/shared/queue.rb +233 -0
  160. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  161. data/lib/farce/engine/shared/rebindable.rb +15 -0
  162. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  163. data/lib/farce/engine/shared/strict_map.rb +117 -0
  164. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  165. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  166. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  167. data/lib/farce/engine/shared/trie.rb +317 -0
  168. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  169. data/lib/farce/engine/shared/unshareable.rb +14 -0
  170. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  171. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  172. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  173. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  174. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  175. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  176. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  177. data/lib/farce/engine/shared/vault.rb +31 -0
  178. data/lib/farce/engine/shared/vector.rb +83 -0
  179. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  180. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  181. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  182. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  183. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  184. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  185. data/lib/farce/engine/shared.rb +63 -0
  186. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  187. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  188. data/lib/farce/engine/truffleruby/map.rb +656 -0
  189. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  190. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  191. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  192. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  193. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  194. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  195. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  196. data/lib/farce/engine/truffleruby.rb +148 -0
  197. data/lib/farce/envelope.rb +335 -0
  198. data/lib/farce/error.rb +35 -0
  199. data/lib/farce/exchanger.rb +41 -0
  200. data/lib/farce/flag.rb +27 -0
  201. data/lib/farce/integrations/active_support/blank.rb +68 -0
  202. data/lib/farce/integrations/active_support/clock.rb +17 -0
  203. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  204. data/lib/farce/integrations/active_support/map.rb +175 -0
  205. data/lib/farce/integrations/active_support/set.rb +60 -0
  206. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  207. data/lib/farce/integrations/active_support/vector.rb +231 -0
  208. data/lib/farce/integrations/active_support.rb +9 -0
  209. data/lib/farce/integrations/activesupport.rb +5 -0
  210. data/lib/farce/integrations/bson.rb +108 -0
  211. data/lib/farce/integrations/cbor.rb +51 -0
  212. data/lib/farce/integrations/concurrent.rb +112 -0
  213. data/lib/farce/integrations/dry-types.rb +5 -0
  214. data/lib/farce/integrations/dry_types.rb +694 -0
  215. data/lib/farce/integrations/json.rb +7 -0
  216. data/lib/farce/integrations/msgpack.rb +112 -0
  217. data/lib/farce/integrations/oj.rb +69 -0
  218. data/lib/farce/integrations/psych.rb +191 -0
  219. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  220. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  221. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  222. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  223. data/lib/farce/integrations/shared/to_json.rb +42 -0
  224. data/lib/farce/integrations/sorted_set.rb +11 -0
  225. data/lib/farce/integrations/weakref.rb +38 -0
  226. data/lib/farce/integrations/yajl.rb +10 -0
  227. data/lib/farce/integrations.rb +156 -0
  228. data/lib/farce/internal/_frozen_config.rb +11 -0
  229. data/lib/farce/internal/autoloads.rb +47 -0
  230. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  231. data/lib/farce/internal/converter.rb +106 -0
  232. data/lib/farce/internal/copyable.rb +31 -0
  233. data/lib/farce/internal/delegation.rb +20 -0
  234. data/lib/farce/internal/external_transaction.rb +59 -0
  235. data/lib/farce/internal/fake_ractor.rb +179 -0
  236. data/lib/farce/internal/freeze.rb +118 -0
  237. data/lib/farce/internal/inspect.rb +157 -0
  238. data/lib/farce/internal/key_lock_map.rb +29 -0
  239. data/lib/farce/internal/key_normalizer.rb +289 -0
  240. data/lib/farce/internal/lease_initialization.rb +115 -0
  241. data/lib/farce/internal/lease_map.rb +441 -0
  242. data/lib/farce/internal/lease_pool_state.rb +228 -0
  243. data/lib/farce/internal/lease_state.rb +342 -0
  244. data/lib/farce/internal/lease_waiting.rb +13 -0
  245. data/lib/farce/internal/managed_queue.rb +26 -0
  246. data/lib/farce/internal/map_value_modes.rb +227 -0
  247. data/lib/farce/internal/marshal_support.rb +227 -0
  248. data/lib/farce/internal/mixin.rb +20 -0
  249. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  250. data/lib/farce/internal/noncopyable.rb +17 -0
  251. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  252. data/lib/farce/internal/pool_supervisor.rb +41 -0
  253. data/lib/farce/internal/pool_worker.rb +61 -0
  254. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  255. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  256. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  257. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  258. data/lib/farce/internal/portable_transaction.rb +164 -0
  259. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  260. data/lib/farce/internal/reservation_waiting.rb +24 -0
  261. data/lib/farce/internal/scheduled_task.rb +48 -0
  262. data/lib/farce/internal/scheduler_io.rb +171 -0
  263. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  264. data/lib/farce/internal/select_scheduler.rb +235 -0
  265. data/lib/farce/internal/storage.rb +162 -0
  266. data/lib/farce/internal/strict_lease.rb +30 -0
  267. data/lib/farce/internal/strict_lease_map.rb +20 -0
  268. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  269. data/lib/farce/internal/thread_pool.rb +166 -0
  270. data/lib/farce/internal/transaction_conflict.rb +9 -0
  271. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  272. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  273. data/lib/farce/internal/undefined.rb +22 -0
  274. data/lib/farce/internal/unshared_lease.rb +29 -0
  275. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  276. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  277. data/lib/farce/internal/value_serialization.rb +13 -0
  278. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  279. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  280. data/lib/farce/internal.rb +129 -0
  281. data/lib/farce/lazy.rb +100 -0
  282. data/lib/farce/lazy_ref.rb +40 -0
  283. data/lib/farce/lease.rb +28 -0
  284. data/lib/farce/lease_map.rb +34 -0
  285. data/lib/farce/lease_pool.rb +29 -0
  286. data/lib/farce/lfu_map.rb +53 -0
  287. data/lib/farce/local/atom.rb +23 -0
  288. data/lib/farce/local/counter.rb +88 -0
  289. data/lib/farce/local/flag.rb +65 -0
  290. data/lib/farce/local/lazy.rb +38 -0
  291. data/lib/farce/local/lazy_ref.rb +36 -0
  292. data/lib/farce/local/lease.rb +77 -0
  293. data/lib/farce/local/lease_map.rb +80 -0
  294. data/lib/farce/local/lease_pool.rb +38 -0
  295. data/lib/farce/local/lfu_map.rb +55 -0
  296. data/lib/farce/local/lru_map.rb +62 -0
  297. data/lib/farce/local/map.rb +47 -0
  298. data/lib/farce/local/molecule.rb +45 -0
  299. data/lib/farce/local/priority_queue.rb +53 -0
  300. data/lib/farce/local/queue.rb +32 -0
  301. data/lib/farce/local/scoped.rb +166 -0
  302. data/lib/farce/local/set.rb +18 -0
  303. data/lib/farce/local/sorted_set.rb +50 -0
  304. data/lib/farce/local/timer_queue.rb +41 -0
  305. data/lib/farce/local/tree_map.rb +47 -0
  306. data/lib/farce/local/vector.rb +30 -0
  307. data/lib/farce/local/weak_atom.rb +23 -0
  308. data/lib/farce/local/weak_key_map.rb +39 -0
  309. data/lib/farce/local/weak_map.rb +39 -0
  310. data/lib/farce/local/weak_set.rb +18 -0
  311. data/lib/farce/local/weak_value_map.rb +39 -0
  312. data/lib/farce/local.rb +35 -0
  313. data/lib/farce/lock.rb +54 -0
  314. data/lib/farce/lru_map.rb +63 -0
  315. data/lib/farce/map.rb +58 -0
  316. data/lib/farce/mode_manager.rb +142 -0
  317. data/lib/farce/molecule.rb +60 -0
  318. data/lib/farce/mutable.rb +171 -0
  319. data/lib/farce/pool.rb +332 -0
  320. data/lib/farce/port.rb +134 -0
  321. data/lib/farce/priority_queue.rb +70 -0
  322. data/lib/farce/proxy/register.rb +101 -0
  323. data/lib/farce/proxy/supervisor.rb +137 -0
  324. data/lib/farce/proxy/wrapper.rb +49 -0
  325. data/lib/farce/proxy.rb +291 -0
  326. data/lib/farce/queue.rb +60 -0
  327. data/lib/farce/ractor.rb +269 -0
  328. data/lib/farce/read_write_lock.rb +256 -0
  329. data/lib/farce/reference.rb +158 -0
  330. data/lib/farce/resolv/dns.rb +42 -0
  331. data/lib/farce/resolv.rb +85 -0
  332. data/lib/farce/scheduler.rb +536 -0
  333. data/lib/farce/set.rb +39 -0
  334. data/lib/farce/shareable.rb +150 -0
  335. data/lib/farce/signal.rb +97 -0
  336. data/lib/farce/sorted_set.rb +36 -0
  337. data/lib/farce/strict/atom.rb +34 -0
  338. data/lib/farce/strict/counter.rb +10 -0
  339. data/lib/farce/strict/exchanger.rb +25 -0
  340. data/lib/farce/strict/flag.rb +10 -0
  341. data/lib/farce/strict/lazy.rb +26 -0
  342. data/lib/farce/strict/lazy_ref.rb +26 -0
  343. data/lib/farce/strict/lease.rb +27 -0
  344. data/lib/farce/strict/lease_map.rb +33 -0
  345. data/lib/farce/strict/lease_pool.rb +28 -0
  346. data/lib/farce/strict/lfu_map.rb +27 -0
  347. data/lib/farce/strict/lru_map.rb +28 -0
  348. data/lib/farce/strict/map.rb +54 -0
  349. data/lib/farce/strict/molecule.rb +16 -0
  350. data/lib/farce/strict/port.rb +40 -0
  351. data/lib/farce/strict/priority_queue.rb +20 -0
  352. data/lib/farce/strict/queue.rb +17 -0
  353. data/lib/farce/strict/set.rb +14 -0
  354. data/lib/farce/strict/sorted_set.rb +19 -0
  355. data/lib/farce/strict/timer_queue.rb +13 -0
  356. data/lib/farce/strict/tree_map.rb +27 -0
  357. data/lib/farce/strict/vector.rb +24 -0
  358. data/lib/farce/strict/weak_atom.rb +31 -0
  359. data/lib/farce/strict/weak_key_map.rb +49 -0
  360. data/lib/farce/strict/weak_map.rb +49 -0
  361. data/lib/farce/strict/weak_set.rb +14 -0
  362. data/lib/farce/strict/weak_value_map.rb +48 -0
  363. data/lib/farce/strict.rb +28 -0
  364. data/lib/farce/system.rb +40 -0
  365. data/lib/farce/thread_scheduler.rb +70 -0
  366. data/lib/farce/timer_queue.rb +66 -0
  367. data/lib/farce/transaction/atom.rb +73 -0
  368. data/lib/farce/transaction/map.rb +25 -0
  369. data/lib/farce/transaction/map_operations.rb +143 -0
  370. data/lib/farce/transaction/molecule.rb +90 -0
  371. data/lib/farce/transaction/mutable.rb +61 -0
  372. data/lib/farce/transaction/set.rb +17 -0
  373. data/lib/farce/transaction/set_operations.rb +48 -0
  374. data/lib/farce/transaction/sorted_set.rb +18 -0
  375. data/lib/farce/transaction/tree_map.rb +78 -0
  376. data/lib/farce/transaction/vector.rb +139 -0
  377. data/lib/farce/transaction/wrapper.rb +202 -0
  378. data/lib/farce/transaction.rb +343 -0
  379. data/lib/farce/tree_map.rb +56 -0
  380. data/lib/farce/unsafe/lfu_map.rb +36 -0
  381. data/lib/farce/unsafe/lru_map.rb +36 -0
  382. data/lib/farce/unsafe/tree_map.rb +21 -0
  383. data/lib/farce/unsafe.rb +29 -0
  384. data/lib/farce/unshareable.rb +67 -0
  385. data/lib/farce/unshared/atom.rb +24 -0
  386. data/lib/farce/unshared/counter.rb +10 -0
  387. data/lib/farce/unshared/flag.rb +10 -0
  388. data/lib/farce/unshared/lazy.rb +38 -0
  389. data/lib/farce/unshared/lazy_ref.rb +26 -0
  390. data/lib/farce/unshared/lease.rb +27 -0
  391. data/lib/farce/unshared/lease_map.rb +26 -0
  392. data/lib/farce/unshared/lease_pool.rb +25 -0
  393. data/lib/farce/unshared/lfu_map.rb +20 -0
  394. data/lib/farce/unshared/lru_map.rb +20 -0
  395. data/lib/farce/unshared/map.rb +49 -0
  396. data/lib/farce/unshared/molecule.rb +16 -0
  397. data/lib/farce/unshared/priority_queue.rb +16 -0
  398. data/lib/farce/unshared/queue.rb +27 -0
  399. data/lib/farce/unshared/set.rb +14 -0
  400. data/lib/farce/unshared/sorted_set.rb +28 -0
  401. data/lib/farce/unshared/timer_queue.rb +16 -0
  402. data/lib/farce/unshared/tree_map.rb +21 -0
  403. data/lib/farce/unshared/vector.rb +19 -0
  404. data/lib/farce/unshared/weak_atom.rb +31 -0
  405. data/lib/farce/unshared/weak_key_map.rb +44 -0
  406. data/lib/farce/unshared/weak_map.rb +44 -0
  407. data/lib/farce/unshared/weak_set.rb +14 -0
  408. data/lib/farce/unshared/weak_value_map.rb +43 -0
  409. data/lib/farce/unshared.rb +28 -0
  410. data/lib/farce/vector.rb +228 -0
  411. data/lib/farce/version.rb +8 -0
  412. data/lib/farce/walker/definitions.rb +186 -0
  413. data/lib/farce/walker/modification.rb +355 -0
  414. data/lib/farce/walker.rb +319 -0
  415. data/lib/farce/weak_atom.rb +121 -0
  416. data/lib/farce/weak_key_map.rb +31 -0
  417. data/lib/farce/weak_map.rb +33 -0
  418. data/lib/farce/weak_ref.rb +67 -0
  419. data/lib/farce/weak_set.rb +82 -0
  420. data/lib/farce/weak_value.rb +195 -0
  421. data/lib/farce/weak_value_map.rb +32 -0
  422. data/lib/farce.rb +519 -0
  423. metadata +468 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce"
6
+ require "json" unless defined?(JSON::State)
7
+ require_relative "shared/to_json"
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group ActiveSupport Integration
6
+ require "farce"
7
+ require "msgpack"
8
+
9
+ module Farce
10
+ class Abstract::Vector
11
+ # Serialize a snapshot as a MessagePack array.
12
+ # @note This method is only available if MessagePack has been loaded.
13
+ # @overload to_msgpack(*arguments)
14
+ # @param arguments [Array<Object>] Arguments forwarded to Array#to_msgpack.
15
+ # @return [String, ::MessagePack::Packer] The encoded bytes or supplied packer.
16
+ def to_msgpack(...) = to_a.to_msgpack(...)
17
+ end
18
+
19
+ class Abstract::Map
20
+ # Serialize current entries as a MessagePack map.
21
+ # @note This method is only available if MessagePack has been loaded.
22
+ # @overload to_msgpack(*arguments)
23
+ # @param arguments [Array<Object>] Arguments forwarded to Hash#to_msgpack.
24
+ # @return [String, ::MessagePack::Packer] The encoded bytes or supplied packer.
25
+ def to_msgpack(...) = to_h.to_msgpack(...)
26
+ end
27
+
28
+ class Abstract::Set
29
+ # Serialize current members as a MessagePack array.
30
+ # @note This method is only available if MessagePack has been loaded.
31
+ # @overload to_msgpack(*arguments)
32
+ # @param arguments [Array<Object>] Arguments forwarded to Array#to_msgpack.
33
+ # @return [String, ::MessagePack::Packer] The encoded bytes or supplied packer.
34
+ def to_msgpack(...) = to_a.to_msgpack(...)
35
+ end
36
+
37
+ module Internal::ValueSerialization
38
+ # Serialize the current value as its primitive MessagePack equivalent.
39
+ # @note This method is only available if MessagePack has been loaded.
40
+ # @overload to_msgpack(*arguments)
41
+ # @param arguments [Array<Object>] Arguments forwarded to the value's to_msgpack.
42
+ # @return [String, ::MessagePack::Packer] The encoded bytes or supplied packer.
43
+ def to_msgpack(...) = value.to_msgpack(...)
44
+ end
45
+
46
+ # @note This module is only available if MessagePack has been loaded.
47
+ module MessagePack
48
+ # Default mapping used by {.factory}.
49
+ DEFAULT_TYPES = { Vector => 0, Map => 1, Counter => 2, Flag => 3, Atom => 4, Set => 5 }.freeze
50
+
51
+ extend self
52
+
53
+ # Build a factory that restores registered Farce classes.
54
+ # Use the same type IDs when writing and reading data.
55
+ # @note This method is only available if MessagePack has been loaded.
56
+ # @param types [Hash{Class => Integer}] Classes and their application extension IDs.
57
+ # @return [::MessagePack::Factory] An independent factory.
58
+ # @!scope class
59
+ def factory(types: DEFAULT_TYPES)
60
+ result = ::MessagePack::Factory.new
61
+ types.each { |klass, type| register_type(result, type, klass) }
62
+ result
63
+ end
64
+
65
+ # Register a Farce class on an application-owned factory.
66
+ # Values use the same factory recursively, including nested custom types.
67
+ # Source configuration is replaced by the supplied constructor options.
68
+ # Counters also retain their initial value for reset.
69
+ # @note This method is only available if MessagePack has been loaded.
70
+ # @param factory [::MessagePack::Factory] The factory to configure.
71
+ # @param type [Integer] An unused application extension ID from 0 through 127.
72
+ # @param klass [Class] A concrete Farce vector, map, set, counter, flag, or atom class.
73
+ # @param options [Hash{Symbol => Object}] Constructor options for restored objects.
74
+ # @return [::MessagePack::Factory] The supplied factory.
75
+ # @raise [ArgumentError] If the class is unsupported or the ID or class is already registered.
76
+ # @!scope class
77
+ def register_type(factory, type, klass, **)
78
+ reader = primitive_reader(klass)
79
+ unless type.is_a?(Integer) && (0..127).cover?(type)
80
+ raise ArgumentError, "MessagePack extension IDs must be integers from 0 through 127"
81
+ end
82
+ if factory.registered_types.any? { it[:type] == type || it[:class] == klass }
83
+ raise ArgumentError, "MessagePack extension ID or class is already registered"
84
+ end
85
+
86
+ counter = klass <= Abstract::Counter
87
+ factory.register_type(type, klass,
88
+ packer: lambda { |object, packer|
89
+ packer.write(object.initial) if counter
90
+ packer.write(object.public_send(reader))
91
+ },
92
+ unpacker: lambda { |unpacker|
93
+ object = klass.new(unpacker.read, **)
94
+ object.value = unpacker.read if counter
95
+ object
96
+ },
97
+ recursive: true)
98
+ factory
99
+ end
100
+
101
+ private
102
+
103
+ def primitive_reader(klass)
104
+ raise ArgumentError, "expected a concrete Farce class" unless klass.is_a?(Class)
105
+ return :to_a if klass <= Abstract::Vector || klass <= Abstract::Set
106
+ return :to_h if klass <= Abstract::Map
107
+ return :value if klass <= Abstract::Counter || klass <= Abstract::Flag || klass <= Abstract::Atom
108
+
109
+ raise ArgumentError, "unsupported Farce class: #{klass}"
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group Oj Integration
6
+ require "farce"
7
+ require "oj" unless defined?(Oj::VERSION)
8
+
9
+ require "json" unless [].respond_to?(:to_json)
10
+ require_relative "shared/to_json"
11
+
12
+ module Farce
13
+ # Object-mode reconstruction for Oj.
14
+ # @api private
15
+ module Oj
16
+ # @api private
17
+ Constructor = Data.define(:klass, :options, :counter) do
18
+ def call(value, current = nil)
19
+ object = klass.new(value, **options)
20
+ object.value = current if counter
21
+ object
22
+ end
23
+ end
24
+ private_constant :Constructor
25
+
26
+ extend self
27
+
28
+ # Register a concrete class for Oj object-mode round trips.
29
+ # Registrations are process-global. Configure them before starting concurrent serialization.
30
+ # Repeated registration replaces the previous reconstruction settings for the class.
31
+ # Source settings are replaced by the supplied options. Counters retain their initial value.
32
+ # Constructor options are copied and made Ractor-shareable.
33
+ # Reading move-backed contents can transfer ownership to the serializing Ractor.
34
+ # @param klass [Class] A named Farce vector, map, set, counter, flag, or atom class.
35
+ # @param options [Hash{Symbol => Object}] Constructor options for restored objects.
36
+ # @return [Class] The registered class.
37
+ # @raise [ArgumentError] If the class is unsupported or anonymous.
38
+ # @raise [Ractor::IsolationError] If registration is attempted outside the main native Ractor.
39
+ # @!scope class
40
+ def register_type(klass, **options)
41
+ if Internal.native_ractors? && !Ractor.main?
42
+ raise Ractor::IsolationError, "register Oj types in the main Ractor before concurrent use"
43
+ end
44
+ unless klass.is_a?(Class) && klass.name && !klass.name.start_with?("Farce::Abstract::")
45
+ raise ArgumentError, "expected a named concrete Farce class"
46
+ end
47
+
48
+ reader = if klass <= Abstract::Vector || klass <= Abstract::Set
49
+ :to_a
50
+ elsif klass <= Abstract::Map
51
+ :to_h
52
+ elsif klass <= Abstract::Counter || klass <= Abstract::Flag || klass <= Abstract::Atom
53
+ :value
54
+ else
55
+ raise ArgumentError, "unsupported Farce class: #{klass}"
56
+ end
57
+ counter = klass <= Abstract::Counter
58
+ constructor = Constructor.new(klass, Ractor.make_shareable(options, copy: true), counter)
59
+ Ractor.make_shareable(constructor)
60
+ members = counter ? [:initial, reader] : [reader]
61
+ ::Oj.register_odd(klass, constructor, :call, *members)
62
+ klass
63
+ end
64
+ end
65
+ end
66
+
67
+ [Farce::Vector, Farce::Map, Farce::Set, Farce::Counter, Farce::Flag, Farce::Atom].each do |klass|
68
+ Farce::Oj.register_type(klass)
69
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group Psych Integration
6
+ require "farce"
7
+ require "psych" unless defined?(Psych::Coder)
8
+
9
+ module Farce
10
+ class Abstract::Map
11
+ # @api private
12
+ # Called by Psych for generating YAML.
13
+ # @param coder [Psych::Coder] The YAML representation.
14
+ # @return [Psych::Coder] The coder containing the serialized fields.
15
+ def encode_with(coder)
16
+ coder["entries"] = to_h
17
+ coder["compare_values_by_identity"] = compare_values_by_identity?
18
+ coder["compare_keys_by_identity"] = compare_keys_by_identity?
19
+ normalizer = instance_variable_get(:@key_normalizer)
20
+ coder["normalize_keys"] = Internal::KeyNormalizer.dump(normalizer) if normalizer
21
+ coder["scope"] = scope if respond_to?(:scope)
22
+ coder
23
+ end
24
+
25
+ # @api private
26
+ # Called by Psych when parsing YAML.
27
+ # @param coder [Psych::Coder] The YAML representation.
28
+ # @return [void]
29
+ def init_with(coder)
30
+ options = coder.map.except("entries").transform_keys(&:to_sym)
31
+ if options.key?(:normalize_keys)
32
+ options[:normalize_keys] =
33
+ Internal::KeyNormalizer.restore(options[:normalize_keys])
34
+ end
35
+ initialize(coder["entries"], **options)
36
+ end
37
+ end
38
+
39
+ class Abstract::BoundedMap
40
+ # @api private
41
+ # Called by Psych for generating YAML.
42
+ # @param coder [Psych::Coder] The YAML representation.
43
+ # @return [Psych::Coder] The coder containing the serialized fields.
44
+ def encode_with(coder) = super.tap { it["max_size"] = max_size }
45
+ end
46
+
47
+ module Internal::ValueSerialization
48
+ # @api private
49
+ # Called by Psych for generating YAML.
50
+ # @param coder [Psych::Coder] The YAML representation.
51
+ # @return [Psych::Coder] The coder containing the serialized fields.
52
+ def encode_with(coder)
53
+ coder["value"] = value
54
+ coder["scope"] = scope if respond_to?(:scope)
55
+ coder
56
+ end
57
+
58
+ # @api private
59
+ # Called by Psych when parsing YAML.
60
+ # @param coder [Psych::Coder] The YAML representation.
61
+ # @return [void]
62
+ def init_with(coder)
63
+ options = coder.map.except("value").transform_keys(&:to_sym)
64
+ initialize(coder["value"], **options)
65
+ end
66
+ end
67
+
68
+ class Abstract::Atom
69
+ # @api private
70
+ # Called by Psych for generating YAML.
71
+ # @param coder [Psych::Coder] The YAML representation.
72
+ # @return [Psych::Coder] The coder containing the serialized fields.
73
+ def encode_with(coder)
74
+ super
75
+ coder["compare_by_identity"] = compare_by_identity?
76
+ coder["shareable"] = Ractor.shareable?(coder["value"])
77
+ coder
78
+ end
79
+
80
+ # @api private
81
+ # Restore the value and its shareability when parsing YAML.
82
+ # @param coder [Psych::Coder] The YAML representation.
83
+ # @return [void]
84
+ def init_with(coder)
85
+ value = coder["value"]
86
+ value = Ractor.make_shareable(value) if coder["shareable"]
87
+ options = coder.map.except("value", "shareable").transform_keys(&:to_sym)
88
+ initialize(value, **options)
89
+ end
90
+ end
91
+
92
+ module Abstract::Counter
93
+ # @api private
94
+ # Called by Psych for generating YAML.
95
+ # @param coder [Psych::Coder] The YAML representation.
96
+ # @return [Psych::Coder] The coder containing the serialized fields.
97
+ def encode_with(coder)
98
+ super
99
+ coder["initial"] = initial
100
+ coder
101
+ end
102
+
103
+ # @api private
104
+ # Called by Psych when parsing YAML.
105
+ # @param coder [Psych::Coder] The YAML representation.
106
+ # @return [void]
107
+ def init_with(coder)
108
+ options = coder.map.except("value", "initial").transform_keys(&:to_sym)
109
+ initialize(coder["initial"], **options)
110
+ self.value = coder["value"]
111
+ end
112
+ end
113
+
114
+ class Atom
115
+ # @api private
116
+ # Called by Psych for generating YAML.
117
+ # @param coder [Psych::Coder] The YAML representation.
118
+ # @return [Psych::Coder] The coder containing the serialized fields.
119
+ def encode_with(coder)
120
+ super
121
+ coder["mode"] = mode
122
+ coder
123
+ end
124
+ end
125
+
126
+ class Abstract::Set
127
+ # @api private
128
+ # Called by Psych for generating YAML.
129
+ # @param coder [Psych::Coder] The YAML representation.
130
+ # @return [Psych::Coder] The coder containing the set representation.
131
+ def encode_with(coder)
132
+ coder["entries"] = each_stored.map do |key, stored|
133
+ element = public_stored(key, stored)
134
+ entry = {
135
+ "value" => element,
136
+ "shareable" => Ractor.shareable?(element),
137
+ }
138
+ if value_modes?
139
+ entry["identity"] = identity_storage_key?(key)
140
+ entry["snapshot"] = key unless entry["identity"]
141
+ entry["mode"] = stored_mode(stored)
142
+ end
143
+ entry
144
+ end
145
+ coder["compare_by_identity"] = compare_by_identity?
146
+ coder["frozen"] = frozen?
147
+ coder["mode"] = mode if respond_to?(:mode)
148
+ coder["scope"] = scope if respond_to?(:scope)
149
+ coder["normalize"] = Internal::KeyNormalizer.dump(@normalizer) if @normalizer
150
+ coder
151
+ end
152
+
153
+ # @api private
154
+ # Called by Psych when parsing YAML.
155
+ # @param coder [Psych::Coder] The YAML representation.
156
+ # @return [self] The restored set.
157
+ def init_with(coder)
158
+ options = { compare_by_identity: coder["compare_by_identity"] }
159
+ options[:mode] = coder["mode"].to_sym if coder["mode"]
160
+ options[:scope] = coder["scope"].to_sym if coder["scope"]
161
+ options[:normalize] = Internal::KeyNormalizer.restore(coder["normalize"]) if coder.map.key?("normalize")
162
+ entries = coder["entries"]
163
+
164
+ if coder["mode"] && value_modes?
165
+ initialize(nil, **options)
166
+ entries.each { restore_yaml_entry(it) }
167
+ else
168
+ values = entries.map { restore_yaml_value(it) }
169
+ initialize(values, **options)
170
+ end
171
+
172
+ freeze if coder["frozen"]
173
+ self
174
+ end
175
+
176
+ private
177
+
178
+ def restore_yaml_entry(entry)
179
+ value = restore_yaml_value(entry)
180
+ key = entry["identity"] ? comparison_key_for_canonical(value) : Ractor.make_shareable(entry["snapshot"])
181
+ mode = entry["mode"]&.to_sym
182
+ payload = @manager.wrap(value, mode:)
183
+ add_stored(key, StoredEntry.new(@manager, payload))
184
+ end
185
+
186
+ def restore_yaml_value(entry)
187
+ value = entry["value"]
188
+ entry["shareable"] ? Ractor.make_shareable(value) : value
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require_relative "ractor_sharing"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require_relative "ractor_tmvar"
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group ractor-sharing Integration
6
+ require "farce"
7
+ require "ractor/tvar"
8
+ require "ractor/lockvar"
9
+ require "ractor/lockhash"
10
+ require "ractor/keylockhash"
11
+ require "ractor/active_object"
12
+ require "ractor/actor_hash"
13
+
14
+ module Farce
15
+ module Integrations
16
+ # @api private
17
+ module RactorSharing
18
+ # The private marker is published in the same STM commit as all TVars.
19
+ # It distinguishes a failed STM attempt from a post-publication exception.
20
+ class Commit
21
+ def initialize(entries)
22
+ @entries = entries
23
+ @marker = ::Ractor::TVar.new(false)
24
+ end
25
+
26
+ def committed? = @marker.value
27
+
28
+ def commit
29
+ ::Ractor.atomically do
30
+ @entries.each do |entry|
31
+ unless Internal::PortableTransaction.same?(entry.source.value, entry.baseline)
32
+ raise Internal::TransactionConflict, "TVar changed"
33
+ end
34
+ end
35
+ # Validate the complete read set before staging any writes.
36
+ @entries.each { it.source.value = it.value if it.dirty? } # rubocop:disable Style/CombinableLoops
37
+ @marker.value = true
38
+ end
39
+ end
40
+ end
41
+
42
+ class Entry
43
+ attr_reader :source, :baseline
44
+ attr_accessor :value
45
+
46
+ def initialize(source)
47
+ # atomically is nestable, so it could return before actual publication.
48
+ # Test a private slot before taking a snapshot or any Farce reservations.
49
+ probe = ::Ractor::TVar.new(false)
50
+ begin
51
+ probe.value = false
52
+ rescue ::Ractor::TransactionError
53
+ # Expected outside STM. All publication belongs to our commit step.
54
+ else
55
+ raise ArgumentError, "Farce transactions with TVars cannot run inside Ractor.atomically"
56
+ end
57
+ @source = source
58
+ @value = @baseline = ::Ractor.atomically { source.value }
59
+ @dirty = false
60
+ end
61
+
62
+ def working = self
63
+ def write! = @dirty = true
64
+ def dirty? = @dirty
65
+ def commit_group = Commit
66
+ end
67
+ end
68
+ end
69
+
70
+ class Transaction
71
+ # A Ractor::TVar staged alongside ordinary Farce participants.
72
+ #
73
+ # Only the commit step enters Ractor.atomically. Conflicts retry the Farce
74
+ # attempt. Values are made shareable when assigned, matching TVar's setter.
75
+ # Mutating a contained object directly is a side effect of the attempt.
76
+ #
77
+ # Run the Farce transaction outside an enclosing Ractor.atomically block.
78
+ # Writable Concurrent::TVar participants cannot join this commit step.
79
+ #
80
+ # @example Transfer between a TVar and an Atom
81
+ # available = Ractor::TVar.new(10)
82
+ # received = Farce::Strict::Atom.new(0)
83
+ # Farce.transaction do |tx|
84
+ # tx[available].value -= 3
85
+ # tx[received].value += 3
86
+ # end
87
+ class RactorTVar
88
+ include Wrapper
89
+
90
+ # @return [Object] the value staged in this attempt
91
+ def value = access { @working.value }
92
+
93
+ # Stage a shareable replacement.
94
+ # @param value [Object] the replacement value
95
+ # @return [Object] the shareable replacement
96
+ def value=(value)
97
+ # Can't use #write, as a TVar's Ruby facade is always frozen
98
+ access do
99
+ @entry.write!
100
+ @working.value = ::Ractor.make_shareable(value)
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def enlist(backend) = @transaction.enlist(backend) { Integrations::RactorSharing::Entry.new(it) }
107
+ end
108
+ end
109
+
110
+ Transaction.define(::Ractor::TVar) do |object, transaction|
111
+ Farce::Transaction::RactorTVar.new(transaction, object, object)
112
+ end
113
+
114
+ [::Ractor::TVar, ::Ractor::LockVar, ::Ractor::LockHash, ::Ractor::KeyLockHash].each do |klass|
115
+ klass.include(Internal::Noncopyable) unless klass < Internal::Noncopyable
116
+ end
117
+
118
+ [::Ractor::LockHash, ::Ractor::KeyLockHash].each do |klass|
119
+ Internal::Converter.define(klass, :Map) do |instance, hash|
120
+ hash.keys.each do |key| # rubocop:disable Style/HashEachMethods
121
+ value = hash.fetch(key, UNDEFINED)
122
+ instance[key] = convert(value) unless UNDEFINED.equal?(value)
123
+ end
124
+ end
125
+ end
126
+
127
+ Walker.define(::Ractor::TVar) do |object, walker|
128
+ walker.update(object, [object.value]) do |target, results|
129
+ ::Ractor.atomically { target.value = results.first unless target.value.equal?(results.first) }
130
+ target
131
+ end
132
+ end
133
+
134
+ Walker.define(::Ractor::LockVar) do |object, walker|
135
+ walker.update(object, [object.value]) do |target, results|
136
+ target.update { |value| value.equal?(results.first) ? value : results.first }
137
+ target
138
+ end
139
+ end
140
+
141
+ Walker.define(::Ractor::LockHash) do |object, walker|
142
+ values = object.to_h.flat_map { |key, value| [key, value] }
143
+ walker.update(object, values, hash_keys: true, key_stride: 2) do |target, results|
144
+ results.each_slice(2) { |key, _| walker.check_hash_key(key) }
145
+ target.synchronize do
146
+ values.each_slice(2).with_index do |(key, _), index|
147
+ key_result = results[index * 2]
148
+ target.delete(key) unless key.equal?(key_result)
149
+ end
150
+ results.each_slice(2) { |key, value| target[key] = value }
151
+ end
152
+ target
153
+ end
154
+ end
155
+
156
+ Walker.define(::Ractor::KeyLockHash) do |object, walker|
157
+ values = object.to_h.flat_map { |key, value| [key, value] }
158
+ walker.update(object, values, hash_keys: true, key_stride: 2) do |target, results|
159
+ results.each_slice(2) { |key, _| walker.check_hash_key(key) }
160
+ values.each_slice(2).with_index do |(key, _), index|
161
+ key_result = results[index * 2]
162
+ target.delete(key) unless key.equal?(key_result)
163
+ end
164
+ results.each_slice(2) { |key, value| target[key] = value }
165
+ target
166
+ end
167
+ end
168
+
169
+ Walker.define(::Ractor::ActiveObject::Proxy) do |object, _walker|
170
+ object
171
+ end
172
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group ractor-tmvar Integration
6
+ require "farce/integrations/ractor_sharing"
7
+ require "ractor/tmvar"
8
+
9
+ module Farce
10
+ class Transaction
11
+ # A Ractor::TMVar staged alongside TVars and Farce participants.
12
+ #
13
+ # Take, put, and swap operate on the value staged in this attempt.
14
+ # An empty read, take, or swap, or a put into a full TMVar fails the
15
+ # attempt. Farce.transaction retries these conditions within its retry limit.
16
+ # The try_* methods return nil or false without failing the attempt.
17
+ # Assigned values are made shareable, matching Ractor::TVar's setter.
18
+ #
19
+ # Run outside Ractor.atomically, as required by {RactorTVar}.
20
+ # Calls from other Ractors require Ractor-safe TVar methods from ractor-sharing.
21
+ #
22
+ # @example Transfer from a TMVar to an Atom
23
+ # pending = Ractor::TMVar.new(10)
24
+ # received = Farce::Strict::Atom.new(0)
25
+ # Farce.transaction do |tx|
26
+ # tx[received].value += tx[pending].take
27
+ # end
28
+ class RactorTMVar < ::Ractor::TMVar
29
+ include Wrapper
30
+
31
+ # Bind the TMVar's underlying TVar to this attempt's shared snapshot.
32
+ # @param transaction [Transaction] the current attempt
33
+ # @param object [Ractor::TMVar] the participant
34
+ def initialize(transaction, object)
35
+ super
36
+ # TMVar exposes no accessor for its storage. Reuse the TVar wrapper
37
+ # so explicit enrollment of that same TVar shares all staged changes.
38
+ compose(tvar: object.instance_variable_get(:@tvar))
39
+ end
40
+
41
+ Wrapper.inherit(self, :take, :try_take, :read, :try_read, :put, :try_put, :empty?, :swap)
42
+
43
+ private
44
+
45
+ # Translate STM retry conditions before Wrapper marks other exceptions
46
+ # as non-retryable. No upstream STM block runs during staged operations.
47
+ def access
48
+ super do
49
+ yield
50
+ rescue ::Ractor::RetryTransaction
51
+ raise Internal::TransactionConflict, "TMVar is empty or full"
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ Transaction.define(Transaction::RactorTMVar) do |object, transaction|
58
+ object.transaction_wrapper(transaction)
59
+ end
60
+
61
+ Transaction.define(::Ractor::TMVar) do |object, transaction|
62
+ Farce::Transaction::RactorTMVar.new(transaction, object)
63
+ end
64
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group JSON Integration
6
+ module Farce
7
+ class Abstract::Vector
8
+ # Serialize a logical snapshot as a JSON Array.
9
+ # @note This method is only available if a supported JSON library has been loaded.
10
+ # @overload to_json(*arguments)
11
+ # @param arguments [Array<Object>] Arguments forwarded to Array#to_json.
12
+ # @return [String] The generated JSON.
13
+ def to_json(...) = to_a.to_json(...)
14
+ end
15
+
16
+ class Abstract::Map
17
+ # Serialize current entries as a JSON object.
18
+ # @note This method is only available if a supported JSON library has been loaded.
19
+ # @overload to_json(*arguments)
20
+ # @param arguments [Array<Object>] Arguments forwarded to Hash#to_json.
21
+ # @return [String] The generated JSON.
22
+ def to_json(...) = to_h.to_json(...)
23
+ end
24
+
25
+ class Abstract::Set
26
+ # Serialize current members as a JSON Array.
27
+ # @note This method is only available if a supported JSON library has been loaded.
28
+ # @overload to_json(*arguments)
29
+ # @param arguments [Array<Object>] Arguments forwarded to Array#to_json.
30
+ # @return [String] The generated JSON.
31
+ def to_json(...) = to_a.to_json(...)
32
+ end
33
+
34
+ module Internal::ValueSerialization
35
+ # Serialize the current value as its primitive JSON equivalent.
36
+ # @note This method is only available if a supported JSON library has been loaded.
37
+ # @overload to_json(*arguments)
38
+ # @param arguments [Array<Object>] Arguments forwarded to the current value's to_json.
39
+ # @return [String] The generated JSON.
40
+ def to_json(...) = value.to_json(...)
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group SortedSet Integration
6
+ require "farce"
7
+ require "sorted_set"
8
+
9
+ module Farce
10
+ Internal::Converter.define(::SortedSet, :SortedSet)
11
+ end