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,32 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal
7
+ case FROZEN_CONFIG.fiber_scheduler_implementation
8
+ when :native
9
+ load_native_fiber_scheduler
10
+ when :select
11
+ class FiberScheduler
12
+ include SelectScheduler
13
+ end
14
+ when :jvm
15
+ raise LoadError, "the JVM fiber scheduler requires JRuby"
16
+ end
17
+
18
+ unless FiberScheduler.private_method_defined?(:scheduler_ready_count)
19
+ class FiberScheduler
20
+ private def scheduler_ready_count = ready? ? 1 : 0
21
+ end
22
+ end
23
+
24
+ class FiberScheduler
25
+ # Opt into native wait hooks when a Ractor operation needs the shared selector.
26
+ def ractor_selector = RactorSelector.current
27
+ end
28
+
29
+ FiberScheduler.prepend(SchedulerLifecycle)
30
+ require "farce/engine/ruby/3.4/fiber_scheduler" unless Internal.native_ports?
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/unshareable"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ class UnsharedKeyLockMap
11
+ include Farce::Unshareable
12
+ end
13
+
14
+ class KeyLockMap
15
+ def self.new(registry_class:, **comparison_options)
16
+ return super unless equal?(KeyLockMap)
17
+
18
+ if registry_class.equal?(Farce::Unshared::Map)
19
+ UnsharedKeyLockMap.new(**comparison_options)
20
+ elsif registry_class.equal?(Farce::Strict::Map) || registry_class.equal?(Farce::Map)
21
+ SharedKeyLockMap.new(**comparison_options)
22
+ else
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
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
+ # Lease storage that moves its resource through the engine Vault.
9
+ class Lease < LeaseState
10
+ include Freeze::Unfreezable
11
+
12
+ VAULT = Vault.new
13
+ private_constant :VAULT
14
+
15
+ private
16
+
17
+ def initialize_resource(resource)
18
+ Freeze.publish(self)
19
+ VAULT.move_in(self, resource)
20
+ end
21
+
22
+ def take_resource = VAULT.move_out(self)
23
+ def return_resource(resource) = VAULT.move_in(self, resource)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
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
+ # Lease pool storage that moves resources through the CRuby Vault.
9
+ class LeasePool < LeasePoolState
10
+ include Freeze::Unfreezable
11
+
12
+ VAULT = Vault.new
13
+ private_constant :VAULT
14
+
15
+ private
16
+
17
+ def finalize_initialization = Freeze.publish(self)
18
+ def store_resource(token, resource) = VAULT.move_in(token, resource)
19
+ def take_resource(token) = VAULT.move_out(token)
20
+ def return_resource(token, resource) = VAULT.move_in(token, resource)
21
+ def discard_resource(token) = VAULT.delete(token)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ MainScheduler = Scheduler.create(Thread)
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal # :nodoc: all
7
+ ParallelScheduler = Pool.new(max_size: System.cpu_count)
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal
7
+ # Observe termination without consuming the Ractor's return value.
8
+ class ProxyOwner
9
+ include ProxyOwnerNotifications
10
+
11
+ def self.current = Storage.store_if_absent(self) { new }
12
+
13
+ def self.create_scheduler
14
+ scheduler = Farce::Scheduler.new
15
+ Fiber.set_scheduler(scheduler)
16
+ scheduler
17
+ end
18
+
19
+ def self.drain_scheduler(scheduler) = scheduler.close
20
+
21
+ def initialize
22
+ super
23
+ TracePoint.new(:thread_end) do |trace|
24
+ stop
25
+ trace.disable
26
+ end.enable(target_thread: Ractor.main_thread)
27
+ freeze
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
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
+ module RactorMethods
9
+ Internal.delegate(self, ::Ractor, :[], :[]=, :count, :main?, :make_shareable, :shareable?,
10
+ :store_if_absent)
11
+
12
+ if ::Ractor.method(:receive!).parameters.include?(%i[key timeout])
13
+ def receive(timeout: nil)
14
+ if selector = RactorSelector.for_call(::Ractor.current)
15
+ selector.ractor_receive(::Ractor.current, timeout:)
16
+ else
17
+ timeout.nil? ? ::Ractor.receive : ::Ractor.receive(timeout:)
18
+ end
19
+ end
20
+ else
21
+ def receive(timeout: nil)
22
+ selector = RactorSelector.for_call(::Ractor.current)
23
+ selector ||= RactorSelector.current unless timeout.nil?
24
+ selector ? selector.ractor_receive(::Ractor.current, timeout:) : ::Ractor.receive
25
+ end
26
+ end
27
+
28
+ def builtin? = true
29
+ def main_thread = Thread.main
30
+ def shim? = false
31
+ def threads = Thread.list
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/clock"
6
+
7
+ module Farce
8
+ module Internal
9
+ # Multiplex native Ractor waits on one thread in the receiving Ractor.
10
+ # Native ports must be received in their owning Ractor. A helper thread can
11
+ # block there while the calling fiber waits on a local reply queue. Results
12
+ # stay in the same Ractor, without another copy or ownership transfer.
13
+ # Cancelled deliveries are retained for the next receiver.
14
+ class RactorSelector
15
+ Request = Struct.new(:sources, :ready, :reply, :delivery, :yield_options)
16
+ private_constant :Request
17
+
18
+ # Storage owns one selector per Ractor and serializes its first construction.
19
+ def self.current = Storage.store_if_absent(self) { new }
20
+
21
+ # Farce APIs opt into cooperative waits even on third-party schedulers.
22
+ # Native hooks never call this method. They only use the scheduler's opt-in getter.
23
+ def self.for_call(source)
24
+ return current if Fiber.scheduler && !Fiber.blocking?
25
+ # Synchronous Farce calls only reuse the helper for sources it still handles.
26
+ # Cancellation may have left a message here after removing it from the
27
+ # native port. Receiving directly from that port would miss the message.
28
+ existing = Storage[self]
29
+ existing if existing&.routes?(source)
30
+ end
31
+
32
+ def initialize
33
+ @commands = Thread::Queue.new
34
+ @wakeup = Atom.new(false)
35
+ @pending = []
36
+ @buffer = {}.compare_by_identity
37
+ @routing_lock = Thread::Mutex.new
38
+ @routed = {}.compare_by_identity
39
+ @sequence = 0
40
+ @failure = nil
41
+ @closed = @selecting = false
42
+ @owner = ::Ractor.current
43
+ @control = build_control
44
+ @thread = Thread.new { run }
45
+ @thread.name = "farce-ractor-selector"
46
+ end
47
+
48
+ # An idle selector does not change synchronous receive/select dispatch.
49
+ # Active registrations keep concurrent waits on the same source coordinated.
50
+ def routes?(source)
51
+ return false if @routed.empty? && @buffer.empty?
52
+ return source.any? { |entry| routes?(entry) } if source.is_a?(Array)
53
+ source = receive_source(source)
54
+ @routing_lock.synchronize { @routed.key?(source) || @buffer.key?(source) }
55
+ end
56
+
57
+ def closed? = @closed
58
+
59
+ def close
60
+ return if @closed && !@failure
61
+ @closed = true
62
+ begin
63
+ acknowledge(:close) unless @failure
64
+ @thread.join
65
+ ensure
66
+ close_control
67
+ end
68
+ nil
69
+ end
70
+
71
+ private
72
+
73
+ # Retrieve an already-ready native result without re-entering the scheduler hook.
74
+ def native(&)
75
+ Fiber.blocking(&)
76
+ end
77
+
78
+ def duration(value)
79
+ return if value.nil?
80
+ raise TypeError, "cannot convert String into time interval" if value.is_a?(String)
81
+ value = Float(value)
82
+ raise RangeError, "timeout out of range" unless value.finite?
83
+ raise ArgumentError, "time interval must not be negative" if value.negative?
84
+ value
85
+ end
86
+
87
+ def wait(sources, timeout, options = nil)
88
+ raise ::Ractor::IsolationError, "selector belongs to another Ractor" unless @owner == ::Ractor.current
89
+ raise @failure if @failure
90
+ raise IOError, "Ractor selector is closed" if @closed
91
+
92
+ timeout = duration(timeout)
93
+ deadline = Clock.now + timeout if timeout
94
+ sources = sources.uniq
95
+
96
+ sources.each { |source| validate_source(source) }
97
+
98
+ originals = {}.compare_by_identity
99
+ registered = false
100
+ sources = sources.map do |source|
101
+ actual = source.selector_source if fallback_port?(source)
102
+ actual ||= source
103
+ originals[actual] = source
104
+ actual
105
+ end
106
+
107
+ # Register before sending the request so concurrent receivers use the
108
+ # same helper. Counts cover overlapping select calls and multiple threads.
109
+ Thread.handle_interrupt(INTERRUPT_MASK) do
110
+ @routing_lock.synchronize do
111
+ sources.each { |source| @routed[source] = @routed.fetch(source, 0) + 1 }
112
+ registered = true
113
+ end
114
+ end
115
+ # A zero timeout still needs one readiness poll. Positive deadlines
116
+ # include time spent waiting for the helper to accept the request.
117
+ request = Request.new(sources, timeout&.zero? ? Thread::Queue.new : nil, Thread::Queue.new)
118
+ if options&.key?(:yield_value)
119
+ # Ruby 3.4's outgoing yield competes with incoming sources. The request
120
+ # itself identifies that outcome without colliding with a real source.
121
+ request.yield_options = options
122
+ sources << request
123
+ originals[request] = :yield
124
+ end
125
+ command(:add, request)
126
+ request.ready&.pop
127
+
128
+ if deadline
129
+ remaining = deadline - Clock.now
130
+ remaining = 0 if remaining.negative?
131
+ end
132
+
133
+ delivery = request.reply.pop(timeout: remaining)
134
+ if delivery
135
+ _, source, value, error = delivery
136
+ # A delivered error is accepted too, even though it unwinds this wait.
137
+ accepted = true
138
+ raise error if error
139
+ [originals.fetch(source, source), value]
140
+ end
141
+ ensure
142
+ # Finish cancellation before dropping routing ownership. The helper may
143
+ # already have consumed a message that must be retained for another call.
144
+ acknowledge(:cancel, request) if request && !accepted
145
+ if registered
146
+ @routing_lock.synchronize do
147
+ sources.each do |source|
148
+ next unless count = @routed[source]
149
+ count == 1 ? @routed.delete(source) : @routed[source] = count - 1
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ def command(action, payload = nil, ack = nil)
156
+ Thread.handle_interrupt(INTERRUPT_MASK) do
157
+ @commands << [action, payload, ack]
158
+ wake if @selecting
159
+ end
160
+ rescue ::ClosedQueueError
161
+ # A caller may have passed the closed check before the helper stopped.
162
+ fail_request(payload, @failure || IOError.new("Ractor selector is closed")) if action == :add
163
+ ack << true if ack
164
+ end
165
+
166
+ # Coalesce command and shim-port notifications into one control message.
167
+ # Mask interruption so setting the flag cannot leave an unsent wakeup.
168
+ def wake
169
+ Thread.handle_interrupt(INTERRUPT_MASK) do
170
+ @control.send(nil) if @wakeup.compare_and_set(false, true)
171
+ end
172
+ end
173
+
174
+ def acknowledge(action, payload = nil)
175
+ return if @closed && action != :close
176
+ ack = Thread::Queue.new
177
+ Thread.handle_interrupt(INTERRUPT_MASK) do
178
+ command(action, payload, ack)
179
+ # Cleanup must finish even while the scheduler is unwinding a cancelled
180
+ # fiber or shutting down. The helper acknowledges independently of it.
181
+ Fiber.blocking { ack.pop }
182
+ end
183
+ end
184
+
185
+ def forget(port)
186
+ acknowledge(:forget, port) unless @closed
187
+ end
188
+
189
+ def run
190
+ Internal.prepare_thread if defined?(Internal.prepare_thread)
191
+ loop do
192
+ # A data source may win select while a control notification is pending.
193
+ # Consume that notification before parking or starting another select.
194
+ if @wakeup.value
195
+ receive_control
196
+ @wakeup.value = false
197
+ end
198
+ # Park on the command queue when idle. Native select is only needed
199
+ # while there are application sources to watch.
200
+ first = @pending.empty? ? @commands.pop : nil
201
+ break unless process_commands(first)
202
+ dispatch_buffer
203
+ sources = @pending.flat_map(&:sources).uniq
204
+ sources.each { |source| poll(source) if fallback_port?(source) }
205
+ dispatch_buffer
206
+ next if @pending.empty? || !@commands.empty?
207
+ native_sources = @pending.flat_map(&:sources).uniq.reject do |source|
208
+ source.is_a?(Request) || fallback_port?(source)
209
+ end
210
+ yielding = @pending.find(&:yield_options)
211
+ begin
212
+ # Publish the selecting state before rechecking commands. A concurrent
213
+ # sender then either reaches this check or wakes the native select.
214
+ @selecting = true
215
+ next unless @commands.empty?
216
+ source, value = ::Ractor.select(*native_sources, @control, **(yielding&.yield_options || {}))
217
+ ensure
218
+ @selecting = false
219
+ end
220
+ source = yielding if source == :yield
221
+ if source.equal?(@control)
222
+ @wakeup.value = false
223
+ else
224
+ record(source == :receive ? @owner : source, value)
225
+ end
226
+ rescue ::Ractor::ClosedError
227
+ # Isolate a closed or foreign port instead of failing unrelated waits.
228
+ sources.each { |source| poll(source) }
229
+ end
230
+ rescue Exception => e # rubocop:disable Lint/RescueException -- Preserve helper failures for callers and close.
231
+ @failure = e
232
+ raise
233
+ ensure
234
+ # Stop accepting commands before draining them, including late registrations.
235
+ @commands.close
236
+ @closed = true
237
+ error = @failure || IOError.new("Ractor selector stopped")
238
+ @pending.each { |request| fail_request(request, error) }
239
+ until @commands.empty?
240
+ action, payload, ack = @commands.pop(true)
241
+ fail_request(payload, error) if action == :add
242
+ ack << true if ack
243
+ end
244
+ cleanup_control
245
+ end
246
+
247
+ def process_commands(first = nil) # rubocop:disable Naming/PredicateMethod
248
+ while first || !@commands.empty?
249
+ action, payload, ack = first || @commands.pop(true)
250
+ first = nil
251
+ case action
252
+ when :add
253
+ @pending << payload
254
+ payload.sources.each do |source|
255
+ source.selector_watch(@control, @wakeup) if fallback_port?(source)
256
+ poll(source) if payload.ready && !@buffer.key?(source)
257
+ end
258
+ dispatch_buffer
259
+ payload.ready&.push(true)
260
+ when :cancel
261
+ @pending.delete(payload)
262
+ if payload.delivery && !payload.delivery[3] && !payload.delivery[1].is_a?(Request)
263
+ # Queuing a reply does not mean the caller accepted it. Restore
264
+ # unclaimed messages in receive order, even if cancellations arrive
265
+ # out of order. Errors and completed outgoing yields cannot be replayed.
266
+ source = payload.delivery[1]
267
+ (@buffer[source] ||= []) << payload.delivery
268
+ @buffer[source].sort_by!(&:first)
269
+ end
270
+ when :forget
271
+ # Temporary monitor ports may have retained readiness notifications.
272
+ @buffer.delete(payload)
273
+ when :close
274
+ @pending.each { |request| fail_request(request, IOError.new("Ractor selector is closed")) }
275
+ @pending.clear
276
+ ack << true
277
+ return false
278
+ end
279
+ ack << true if ack
280
+ end
281
+ true
282
+ end
283
+
284
+ def poll(source)
285
+ return if source.is_a?(Request)
286
+ if fallback_port?(source)
287
+ source.selector_poll { |value| record(source, value) }
288
+ else
289
+ # A ready control message lets select return when the source has no
290
+ # value, providing a readiness poll on Rubies without native timeouts.
291
+ wake
292
+ selected, value = ::Ractor.select(source, @control)
293
+ if selected.equal?(@control)
294
+ @wakeup.value = false
295
+ check_closed(source)
296
+ else
297
+ record(selected == :receive ? @owner : selected, value)
298
+ end
299
+ end
300
+ rescue StandardError => e
301
+ record(source, nil, e)
302
+ end
303
+
304
+ def record(source, value, error = nil)
305
+ @sequence += 1
306
+ (@buffer[source] ||= []) << [@sequence, source, value, error]
307
+ end
308
+
309
+ def dispatch_buffer
310
+ @pending.dup.each do |request|
311
+ source = request.sources.find { |candidate| @buffer.key?(candidate) }
312
+ next unless source
313
+ delivery = @buffer[source].shift
314
+ @buffer.delete(source) if @buffer[source].empty?
315
+ @pending.delete(request)
316
+ # Keep the delivery attached until the caller accepts it or cancels.
317
+ request.delivery = delivery
318
+ request.reply << delivery
319
+ end
320
+ end
321
+
322
+ def fail_request(request, error)
323
+ request.reply << [nil, nil, nil, error]
324
+ request.ready&.push(true)
325
+ end
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,13 @@
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
+ StrictMap = Map
9
+ StrictWeakKeyMap = WeakKeyMap
10
+ StrictWeakMap = WeakMap
11
+ StrictWeakValueMap = WeakValueMap
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/shared/unshared_vector"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ class UnsharedVector
11
+ prepend UnsharedVectorIteration
12
+ end
13
+ end
14
+ end