farce 0.0.1.alpha2-x86-linux-musl

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,186 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ # Fallback for Ruby implementations supporting Ractor but not Ractor::Port (CRuby 3.x)
9
+ class Port
10
+ include MarshalSupport::Reject
11
+ include Freeze::Unfreezable
12
+
13
+ class QueueReader
14
+ include Freeze::Unfreezable
15
+
16
+ FROM_RACTOR = Object.new.freeze
17
+
18
+ def initialize
19
+ @queue = Queue.new(capacity: nil)
20
+ @atom = Atom.new
21
+ @selector = Atom.new
22
+ Freeze.publish(self)
23
+ end
24
+
25
+ def send(message, move: false)
26
+ return @queue.push(message) if ::Ractor.shareable?(message)
27
+ ractor = @atom.store_if_absent { ::Ractor.new { loop { ::Ractor.yield(::Ractor.receive) } } }
28
+ ractor.send(message, move:)
29
+ @queue.push(FROM_RACTOR)
30
+ rescue ClosedQueueError
31
+ raise ::Ractor::ClosedError, "The port was already closed"
32
+ ensure
33
+ wake_selector
34
+ end
35
+
36
+ def closed? = @queue.closed?
37
+
38
+ def close
39
+ @queue.close
40
+ wake_selector
41
+ end
42
+
43
+ # Senders may be in another Ractor. Publish only the selectable control
44
+ # endpoint and shared wake flag, leaving requests and replies local.
45
+ def selector_watch(control, wakeup) = @selector.value = [control, wakeup].freeze
46
+
47
+ def selector_poll
48
+ # The empty-queue callback distinguishes no message from a nil payload.
49
+ result = @queue.try_pop { return }
50
+ result = @atom.value.take if FROM_RACTOR.equal?(result)
51
+ yield result
52
+ rescue ClosedQueueError
53
+ raise ::Ractor::ClosedError, "The port was already closed"
54
+ end
55
+
56
+ def wake_selector
57
+ return unless target = @selector.value
58
+ control, wakeup = target
59
+ Thread.handle_interrupt(INTERRUPT_MASK) do
60
+ control.send(nil) if wakeup.compare_and_set(false, true)
61
+ end
62
+ rescue ::Ractor::ClosedError
63
+ nil
64
+ end
65
+
66
+ def receive(timeout: nil)
67
+ result = @queue.pop(timeout:)
68
+ return result unless FROM_RACTOR.equal?(result)
69
+ @atom.value.take
70
+ rescue ClosedQueueError
71
+ raise ::Ractor::ClosedError, "The port was already closed"
72
+ end
73
+ end
74
+
75
+ class RactorReader
76
+ include Freeze::Unfreezable
77
+
78
+ PATTERN = /\A#<Ractor:#(?<id>\d+) (?:.+ )?(?<status>\w+)>\z/
79
+
80
+ def self.info(ractor, key)
81
+ raise "unexpected Ractor#inspect format: #{ractor.inspect}" unless match = PATTERN.match(ractor.inspect)
82
+ match[key]
83
+ end
84
+
85
+ def self.status(ractor) = info(ractor, :status)
86
+ def self.id(ractor) = info(ractor, :id)
87
+
88
+ def initialize(ractor)
89
+ @closed = Atom.new(false)
90
+ @ractor = ractor
91
+ Freeze.publish(self)
92
+ end
93
+
94
+ def receive(timeout: nil)
95
+ return ::Ractor.receive if timeout.nil?
96
+ RactorSelector.current.ractor_receive(::Ractor.current, timeout:)
97
+ end
98
+
99
+ def selector_source = ::Ractor.current
100
+
101
+ def closed? = @closed.value
102
+ def close = @closed.value = true
103
+ def send(...) = @ractor.send(...)
104
+ end
105
+
106
+ private_constant :QueueReader, :RactorReader
107
+
108
+ def self.new(source = UNDEFINED)
109
+ case source
110
+ when UNDEFINED then super(QueueReader.new)
111
+ when ::Ractor then super(RactorReader.new(source))
112
+ when Port then source
113
+ else raise ArgumentError, "wrong number of arguments (given 1, expected 0)"
114
+ end
115
+ end
116
+
117
+ def initialize(reader)
118
+ @owner = ::Ractor.current
119
+ @reader = reader
120
+ Freeze.publish(self)
121
+ end
122
+
123
+ def ==(other) = other.is_a?(Port) && @reader == other.reader
124
+
125
+ def closed? = @reader.closed? || RactorReader.status(@owner) == "terminated"
126
+
127
+ def close
128
+ check_owner!
129
+ @reader.close
130
+ self
131
+ end
132
+
133
+ def send(message, move: false)
134
+ raise ::Ractor::ClosedError, "The port was already closed" if closed?
135
+ @reader.send(message, move:)
136
+ self
137
+ end
138
+
139
+ alias << send
140
+
141
+ def receive(timeout: nil)
142
+ check_owner!
143
+ raise ::Ractor::ClosedError, "The port was already closed" if @reader.closed?
144
+ if selector = RactorSelector.for_call(self)
145
+ selector.ractor_receive(self, timeout:)
146
+ else
147
+ @reader.receive(timeout:)
148
+ end
149
+ end
150
+
151
+ def selector_source
152
+ check_owner!
153
+ @reader.selector_source if @reader.is_a?(RactorReader)
154
+ end
155
+
156
+ def selector_watch(...) = @reader.selector_watch(...)
157
+ def selector_poll(&) = @reader.selector_poll(&)
158
+
159
+ def inspect
160
+ class_name = instance_of?(Port) ? "Farce::Ractor::Port" : self.class.name
161
+ "#<#{class_name} to:##{RactorReader.id(@owner)} id:#{object_id}>"
162
+ rescue StandardError
163
+ super
164
+ end
165
+
166
+ alias receive! receive
167
+ private :receive!
168
+
169
+ undef dup
170
+ undef clone
171
+
172
+ protected
173
+
174
+ attr_reader :reader
175
+
176
+ private
177
+
178
+ def check_owner!
179
+ return true if @owner.nil? || ::Ractor.current == @owner
180
+ raise ::Ractor::Error, "only allowed from the creator ::Ractor of this port"
181
+ end
182
+ end
183
+
184
+ BasePort = Port
185
+ end
186
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/ractor_methods"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ module RactorMethods
11
+ def shareable_proc(**, &) = ::Ractor.make_shareable(Farce.rebind(**, &))
12
+ def shareable_lambda(**, &) = ::Ractor.make_shareable(Farce.rebind(**, lambda: true, &))
13
+
14
+ def select(*sources, timeout: nil, **)
15
+ selector = RactorSelector.for_call(sources)
16
+ selector ||= RactorSelector.current unless timeout.nil? && sources.all?(::Ractor)
17
+ selector ? selector.ractor_select(*sources, timeout:, **) : ::Ractor.select(*sources, **)
18
+ end
19
+
20
+ # TODO: Wrapper/Extension to add #default_port, etc.
21
+ def new(...) = ::Ractor.new(...)
22
+ def current = ::Ractor.current
23
+ def main = ::Ractor.main
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/ractor_selector"
6
+
7
+ module Farce
8
+ module Internal
9
+ class RactorSelector
10
+ # Ruby 3.4's M:N scheduler can strand the helper during Ractor teardown.
11
+ # Keep this helper on a dedicated native thread.
12
+ module DedicatedNativeThread
13
+ private
14
+
15
+ def run
16
+ Internal.lock_native_thread
17
+ super
18
+ end
19
+ end
20
+ private_constant :DedicatedNativeThread
21
+ prepend DedicatedNativeThread
22
+
23
+ # Native timeout: must retain Ruby's own error even with a scheduler hook.
24
+ # Only Farce's APIs backport that keyword.
25
+ def self.install_hooks(patch)
26
+ patch[::Ractor.singleton_class, :select, signature: "*sources, **options",
27
+ schedule: "*sources, **options", before: "return select!(*sources, **options) if options.key?(:timeout)"]
28
+ patch[::Ractor.singleton_class, :receive, signature: "",
29
+ schedule: "::Ractor.current"]
30
+ patch[::Ractor, :receive, :take, signature: "", schedule: "self"]
31
+ end
32
+
33
+ def ractor_receive(source, timeout: nil) = wait([source], timeout)&.at(1)
34
+ alias ractor_take ractor_receive
35
+
36
+ def ractor_select(*sources, timeout: nil, yield_value: UNDEFINED, move: false)
37
+ options = { yield_value: yield_value, move: move } unless yield_value.equal?(UNDEFINED)
38
+ raise ArgumentError, "specify at least one Ractor or port" if sources.empty? && !options
39
+ result = wait(sources, timeout, options)
40
+ result[0] = :receive if result && result[0].equal?(@owner)
41
+ result
42
+ end
43
+ alias select ractor_select
44
+
45
+ private
46
+
47
+ def receive_source(source) = source
48
+
49
+ def fallback_port?(source)
50
+ !source.is_a?(::Ractor) && !source.is_a?(Request) && source.is_a?(Internal::Port)
51
+ end
52
+
53
+ def receive_control = @control.take
54
+
55
+ def close_control
56
+ @control.close_outgoing
57
+ @control.close_incoming
58
+ end
59
+ alias cleanup_control close_control
60
+
61
+ def check_closed(_source); end
62
+
63
+ def validate_source(source)
64
+ return if source.is_a?(::Ractor) || source.is_a?(Internal::Port)
65
+ raise ArgumentError, "expected a Ractor or port"
66
+ end
67
+
68
+ # A private yielding Ractor makes wakeups selectable on Ruby 3.4.
69
+ # Control traffic stays out of the receiving Ractor's application inbox.
70
+ def build_control
71
+ Fiber.blocking do
72
+ control = ::Ractor.new do
73
+ ::Ractor.yield(nil)
74
+ loop do
75
+ ::Ractor.receive
76
+ ::Ractor.yield(nil)
77
+ end
78
+ rescue ::Ractor::ClosedError
79
+ nil
80
+ ensure
81
+ # No final value is consumed. Close before Ruby publishes it so
82
+ # publication cannot race with the selector closing this port.
83
+ ::Ractor.current.close_outgoing
84
+ end
85
+ # Complete startup before the first command can send a wakeup.
86
+ control.take
87
+ control
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
Binary file
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/vault"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ class Vault
11
+ class Manager
12
+ private
13
+
14
+ def receive_request
15
+ message = ::Ractor.receive
16
+ return message if message.first.is_a?(Symbol)
17
+
18
+ ticket, action, arguments = message
19
+ [action, *arguments, ticket]
20
+ end
21
+
22
+ def respond(port, message, move: false)
23
+ return port.store(::Ractor.make_shareable(message)) if port.is_a?(Atom)
24
+ ::Ractor.yield([port, message].freeze, move:)
25
+ end
26
+ end
27
+
28
+ def initialize
29
+ @lock = Lock.new
30
+ @sequence = Counter.new
31
+ @ractor = ::Ractor.new { Manager.new.run }
32
+ Freeze.publish(self)
33
+ end
34
+
35
+ private
36
+
37
+ def execute(action, key, value = nil, move: false)
38
+ raise Ractor::IsolationError, "key must be shareable" unless ::Ractor.shareable?(key)
39
+ raise ThreadError, "deadlock; recursive access from the Vault Ractor" if ::Ractor.current.equal?(@ractor)
40
+ ticket = @sequence.add
41
+ @lock.synchronize do
42
+ # Short nested arrays avoid the 3.4 move bug affecting later array elements.
43
+ @ractor.send([ticket, action, [key, value].freeze].freeze, move:)
44
+ loop do
45
+ reply_ticket, response = @ractor.take
46
+ # A canceled request can leave an older reply in the outgoing queue.
47
+ next unless reply_ticket == ticket
48
+
49
+ success, payload = response
50
+ return success ? payload : raise(payload)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
Binary file
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ BasePort = ::Ractor::Port
9
+ class Port < BasePort
10
+ include Freeze::Unfreezable
11
+
12
+ def receive(timeout: nil)
13
+ selector = RactorSelector.for_call(self)
14
+ selector ||= RactorSelector.current unless timeout.nil?
15
+ selector ? selector.ractor_receive(self, timeout:) : super()
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/ractor_methods"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ module RactorMethods
11
+ def select(*sources, timeout: nil)
12
+ selector = RactorSelector.for_call(sources)
13
+ selector ||= RactorSelector.current unless timeout.nil?
14
+ selector ? selector.ractor_select(*sources, timeout:) : ::Ractor.select(*sources)
15
+ end
16
+
17
+ Internal.delegate(self, ::Ractor, :shareable_proc, :shareable_lambda, :current, :main, :new)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/ractor_selector"
6
+
7
+ module Farce
8
+ module Internal
9
+ class RactorSelector
10
+ def self.install_hooks(patch)
11
+ if ::Ractor::Port.instance_method(:receive).parameters.include?(%i[key timeout])
12
+ patch[::Ractor.singleton_class, :select, signature: "*sources, **options", schedule: "*sources, **options"]
13
+ patch[::Ractor.singleton_class, :receive, schedule: "::Ractor.current, ..."]
14
+ patch[::Ractor, :receive]
15
+ patch[::Ractor::Port, :receive]
16
+ else
17
+ # Ruby 4.0 treats unsupported keywords as a positional Hash. Preserve
18
+ # its native argument error before consulting a cooperative scheduler.
19
+ patch[::Ractor.singleton_class, :select, signature: "*sources", schedule: "*sources",
20
+ before: "return select!(*sources) if sources.last.is_a?(Hash)"]
21
+ patch[::Ractor.singleton_class, :receive, signature: "", schedule: "::Ractor.current"]
22
+ patch[::Ractor, :receive, signature: "", schedule: "self"]
23
+ patch[::Ractor::Port, :receive, signature: "", schedule: "self"]
24
+ end
25
+ patch[::Ractor, :join, :value, signature: "", schedule: "self"]
26
+ end
27
+
28
+ def ractor_receive(source, timeout: nil) = wait([receive_source(source)], timeout)&.at(1)
29
+
30
+ def ractor_select(*sources, timeout: nil)
31
+ raise ArgumentError, "specify at least one Ractor or port" if sources.empty?
32
+ # Monitor termination without consuming the Ractor's result. Only the
33
+ # selected caller retrieves that result, so a timeout leaves it available.
34
+ monitors = {}.compare_by_identity
35
+ ports = sources.map do |source|
36
+ if source.is_a?(::Ractor)
37
+ port = ::Ractor::Port.new
38
+ monitors[port] = source
39
+ source.monitor(port)
40
+ port
41
+ else
42
+ source
43
+ end
44
+ end
45
+ return unless result = wait(ports, timeout)
46
+ source, value = result
47
+ ractor = monitors[source]
48
+ ractor ? [ractor, native { ractor.value }] : [source, value]
49
+ ensure
50
+ monitors&.each do |port, ractor|
51
+ ractor.unmonitor(port)
52
+ port.close
53
+ forget(port)
54
+ end
55
+ end
56
+ alias select ractor_select
57
+
58
+ def ractor_join(ractor, timeout: nil)
59
+ terminated(ractor, timeout) { native { ractor.join } }
60
+ end
61
+
62
+ def ractor_value(ractor, timeout: nil)
63
+ terminated(ractor, timeout) { native { ractor.value } }
64
+ end
65
+
66
+ private
67
+
68
+ def receive_source(source) = source.is_a?(::Ractor) ? source.default_port : source
69
+ def fallback_port?(_source) = false
70
+ def build_control = ::Ractor::Port.new
71
+ def receive_control = @control.receive
72
+ def close_control = @control.close
73
+
74
+ # Native ports are closed by CRuby during Ractor teardown. Closing them
75
+ # again from the dying helper can crash the VM.
76
+ def cleanup_control; end
77
+
78
+ def check_closed(source)
79
+ raise ::Ractor::ClosedError, "The port was already closed" if source.closed?
80
+ end
81
+
82
+ def validate_source(source)
83
+ return if source.is_a?(::Ractor)
84
+ raise ArgumentError, "expected a Ractor or port" unless source.is_a?(::Ractor::Port)
85
+ inspect_port = ::Ractor::Port.instance_method(:inspect)
86
+ # Native ports expose their owner only through the built-in inspect.
87
+ owner = inspect_port.bind_call(@owner.default_port)[/to:#\d+/]
88
+ return if inspect_port.bind_call(source)[/to:#\d+/] == owner
89
+ raise ::Ractor::Error, "only allowed from the creator Ractor of this port"
90
+ end
91
+
92
+ # Readiness is separate from result retrieval. In particular, join must
93
+ # wait for termination without taking the value another caller may need.
94
+ def terminated(ractor, timeout)
95
+ port = ::Ractor::Port.new
96
+ ractor.monitor(port)
97
+ return unless wait([port], timeout)
98
+ yield
99
+ ensure
100
+ if port
101
+ ractor.unmonitor(port)
102
+ port.close
103
+ forget(port)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
Binary file
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/vault"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ class Vault
11
+ if System.windows?
12
+ # A Windows Port receiver can remain asleep after its reply was sent.
13
+ # Wait for a native Atom notification before consuming the queued reply.
14
+ class ReplyPort
15
+ include Freeze::Unfreezable
16
+
17
+ def initialize
18
+ @port = ::Ractor::Port.new
19
+ @ready = Atom.new
20
+ Freeze.publish(self)
21
+ end
22
+
23
+ def send(message, move: false)
24
+ @port.send(message, move:)
25
+ @ready.store(true)
26
+ end
27
+
28
+ def receive
29
+ @ready.wait_until_non_nil
30
+ @port.receive
31
+ end
32
+
33
+ def close = @port.close
34
+ def closed? = @port.closed?
35
+ end
36
+ else
37
+ ReplyPort = ::Ractor::Port
38
+ end
39
+ private_constant :ReplyPort
40
+
41
+ class Manager
42
+ private
43
+
44
+ def receive_request = ::Ractor.receive
45
+
46
+ def respond(port, message, move: false)
47
+ return port.store(::Ractor.make_shareable(message)) if port.is_a?(Atom)
48
+ port.send(message, move:)
49
+ rescue ::Ractor::ClosedError
50
+ # An interrupted caller closes its private reply port.
51
+ raise unless port.is_a?(ReplyPort) && port.closed?
52
+ end
53
+ end
54
+
55
+ def initialize
56
+ @ractor = ::Ractor.new { Manager.new.run }
57
+ Freeze.publish(self)
58
+ end
59
+
60
+ private
61
+
62
+ def execute(action, key, value = nil, move: false)
63
+ raise Ractor::IsolationError, "key must be shareable" unless ::Ractor.shareable?(key)
64
+ raise ThreadError, "deadlock; recursive access from the Vault Ractor" if ::Ractor.current.equal?(@ractor)
65
+ port = ReplyPort.new
66
+ @ractor.send([action, key, value, port].freeze, move:)
67
+ success, payload = port.receive
68
+ success ? payload : raise(payload)
69
+ ensure
70
+ port&.close
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # @!visibility private
7
+ module Internal # :nodoc: all
8
+ BasePort = ::Ractor::Port
9
+ class Port < BasePort
10
+ include Freeze::Unfreezable
11
+
12
+ def receive(timeout: nil)
13
+ if selector = RactorSelector.for_call(self)
14
+ selector.ractor_receive(self, timeout:)
15
+ else
16
+ timeout.nil? ? super() : super
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/shared/ractor_methods"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ module RactorMethods
11
+ def select(*sources, timeout: nil)
12
+ if selector = RactorSelector.for_call(sources)
13
+ selector.ractor_select(*sources, timeout:)
14
+ else
15
+ timeout.nil? ? ::Ractor.select(*sources) : ::Ractor.select(*sources, timeout:)
16
+ end
17
+ end
18
+
19
+ Internal.delegate(self, ::Ractor, :shareable_proc, :shareable_lambda, :current, :main, :new)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/4.0/ractor_selector"
6
+
7
+ module Farce
8
+ module Internal
9
+ class RactorSelector
10
+ # Ruby 4.1 can crash while formatting a dying helper's exception after
11
+ # Ractor teardown has freed its ports. Callers and close observe failures.
12
+ # See https://bugs.ruby-lang.org/issues/22386
13
+ module ExplicitFailureReporting
14
+ private
15
+
16
+ def run
17
+ Thread.current.report_on_exception = false
18
+ super
19
+ end
20
+ end
21
+ private_constant :ExplicitFailureReporting
22
+ prepend ExplicitFailureReporting
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/ruby/4.0/vault"