farce 0.0.1.alpha2-x86_64-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,150 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # Mixin that makes sure instances are shareable between Ractors.
7
+ #
8
+ # @example
9
+ # class MyClass
10
+ # include Farce::Shareable
11
+ # end
12
+ #
13
+ # object = MyClass.new
14
+ # Ractor.shareable?(object) # => true
15
+ module Shareable
16
+ # A structurally frozen wrapper whose logical frozen state is owned by its backend.
17
+ # The including class must implement a private `freeze_backend` method.
18
+ #
19
+ # @example Delegate freezing to a counter
20
+ # class Tally
21
+ # include Farce::Shareable::Delegated
22
+ #
23
+ # def initialize
24
+ # @counter = Farce::Counter.new
25
+ # super
26
+ # end
27
+ #
28
+ # def increment = @counter.increment
29
+ # private def freeze_backend = @counter
30
+ # end
31
+ #
32
+ # tally = Tally.new
33
+ # tally.frozen? # => false
34
+ # tally.freeze
35
+ # tally.increment # raises FrozenError in the counter
36
+ module Delegated
37
+ include Shareable
38
+ include Internal::Freeze::Delegated
39
+ end
40
+
41
+ # A structurally frozen wrapper with one shared logical freeze-state flag.
42
+ # Mutating methods must call `check_frozen!` before changing state.
43
+ #
44
+ # @example Track freezing separately from storage
45
+ # class Tally
46
+ # include Farce::Shareable::Tracked
47
+ #
48
+ # def initialize
49
+ # @counter = Farce::Counter.new
50
+ # super
51
+ # end
52
+ #
53
+ # def increment
54
+ # check_frozen!
55
+ # @counter.increment
56
+ # end
57
+ # end
58
+ #
59
+ # tally = Tally.new
60
+ # tally.frozen? # => false
61
+ # tally.freeze
62
+ # tally.increment # raises FrozenError for the tally
63
+ module Tracked
64
+ include Shareable
65
+ include Internal::Freeze::Tracked
66
+ end
67
+
68
+ # A structurally frozen service object that does not support logical freezing.
69
+ #
70
+ # @example Publish a service that must remain mutable
71
+ # class Inbox
72
+ # include Farce::Shareable::Unfreezable
73
+ #
74
+ # def initialize
75
+ # @queue = Farce::Queue.new
76
+ # super
77
+ # end
78
+ #
79
+ # def push(value) = @queue.push(value)
80
+ # end
81
+ #
82
+ # inbox = Inbox.new
83
+ # inbox.frozen? # => false
84
+ # inbox.freeze # raises TypeError
85
+ module Unfreezable
86
+ include Shareable
87
+ include Internal::Freeze::Unfreezable
88
+ end
89
+
90
+ # A native object that publishes its initialized payload without structural freezing.
91
+ # Requires a backend that already implements safe publication and frozen checks.
92
+ # Including this module alone cannot make an ordinary Ruby object shareable.
93
+ # Native subclasses must not add Ruby instance variables on CRuby.
94
+ #
95
+ # @example Extend a counter while preserving native publication
96
+ # class Tally < Farce::Counter
97
+ # include Farce::Shareable::Native
98
+ #
99
+ # def increment_twice = increment(2)
100
+ # end
101
+ #
102
+ # tally = Tally.new
103
+ # tally.frozen? # => false
104
+ # Ractor.shareable?(tally) # => true
105
+ # tally.freeze
106
+ # tally.increment_twice # raises FrozenError
107
+ module Native
108
+ include Shareable
109
+ include Internal::Freeze::Native
110
+ end
111
+
112
+ # An immutable object whose structural and logical frozen states are the same.
113
+ # Set instance variables before calling `super` from `initialize`.
114
+ #
115
+ # @example Publish an immutable value
116
+ # class Point
117
+ # include Farce::Shareable::Immutable
118
+ # attr_reader :x, :y
119
+ #
120
+ # def initialize(x, y)
121
+ # @x, @y = x, y
122
+ # super()
123
+ # end
124
+ # end
125
+ #
126
+ # point = Point.new(1, 2)
127
+ # point.frozen? # => true
128
+ # Ractor.shareable?(point) # => true
129
+ module Immutable
130
+ include Shareable
131
+ include Internal::Freeze::Immutable
132
+ end
133
+
134
+ # Make sure to call `super` if you include this module.
135
+ # Accepts any arguments and passes them on to the superclass initializer.
136
+ def initialize(...)
137
+ super
138
+ publish_shareable
139
+ end
140
+
141
+ # @return [Boolean] true
142
+ # @see Unshareable#ractor_shareable?
143
+ def ractor_shareable? = true
144
+
145
+ private
146
+
147
+ # Publish a Ruby facade without dispatching its logical `freeze` method.
148
+ def publish_shareable = Internal::Freeze.publish(self)
149
+ end
150
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # A Ractor-shareable notification signal for changes to separately synchronized state.
7
+ # Broadcast after updating the state. Waiters check that state again after each notification.
8
+ # A broadcast wakes all current waiters and advances the signal's generation.
9
+ #
10
+ # @example Waiting for a resource
11
+ # signal = Farce::Signal.new
12
+ # resources = Farce::Strict::Queue.new
13
+ # producer = Thread.new do
14
+ # resources.push(:resource)
15
+ # signal.broadcast
16
+ # end
17
+ # resource = signal.wait_until(timeout: 1.0) { resources.try_pop }
18
+ # producer.join
19
+ # resource # => :resource, or nil if the timeout expires
20
+ #
21
+ class Signal
22
+ include Internal::Noncopyable
23
+ include Internal::Inspect
24
+ include Shareable::Unfreezable
25
+
26
+ def initialize
27
+ @signal = Internal::Signal.new
28
+ super
29
+ end
30
+
31
+ # Read the current generation. Take this snapshot before checking external state.
32
+ # @return [Integer] the current generation, initially zero
33
+ def generation = @signal.generation
34
+
35
+ # Advance the generation and wake all current waiters.
36
+ # @return [Integer] the new generation
37
+ def broadcast = @signal.broadcast
38
+
39
+ # @return [Integer] the number of callers currently waiting
40
+ def num_waiting = @signal.num_waiting
41
+
42
+ # Wait for the generation to change. Without a snapshot, wait for the next broadcast.
43
+ # Return immediately if the supplied generation has already changed.
44
+ # @param observed [Integer, nil] a generation snapshot, or nil to take a snapshot now
45
+ # @param timeout [Numeric, nil] the maximum seconds to wait, or nil to wait indefinitely
46
+ # @yield called without arguments when the timeout expires
47
+ # @return [Integer, BasicObject, nil] the changed generation, or the fallback result or nil on timeout
48
+ def wait(observed = nil, timeout: nil, &) = @signal.wait(observed, timeout:, &)
49
+
50
+ # Check a condition immediately, then after broadcasts while it remains truthy.
51
+ # Uses the same timeout budget and notification handling as {#wait_until}.
52
+ # @param timeout [Numeric, nil] the total seconds available, or nil to wait indefinitely
53
+ # @yield checks the condition
54
+ # @yieldreturn [BasicObject] a truthy value to keep waiting, or nil or false to stop
55
+ # @return [true, nil] true when the condition becomes false, or nil on timeout
56
+ # @raise [LocalJumpError] if no block is given
57
+ def wait_while(timeout: nil)
58
+ raise LocalJumpError, "no block given" unless block_given?
59
+ wait_until(timeout:) { !yield }
60
+ end
61
+
62
+ # Check a condition immediately, then check again after broadcasts until it succeeds.
63
+ # Take a generation snapshot before every check so a broadcast during the check is not missed.
64
+ # The block runs in the caller without holding a signal lock. Synchronize access to shared state
65
+ # inside the block, and claim the resource there if another waiter could consume it.
66
+ #
67
+ # One timeout budget covers all checks and waits. The block is not interrupted when time expires.
68
+ # A timeout of zero checks once without waiting. Exceptions from the block propagate to the caller.
69
+ #
70
+ # @param timeout [Numeric, nil] the total seconds available, or nil to wait indefinitely
71
+ # @yield checks or claims the resource
72
+ # @yieldreturn [BasicObject, nil, false] a truthy result on success, or nil or false to keep waiting
73
+ # @return [BasicObject, nil] the first truthy block result, or nil on timeout
74
+ # @raise [LocalJumpError] if no block is given
75
+ # @raise [ArgumentError] if the timeout is negative or not finite
76
+ def wait_until(timeout: nil)
77
+ raise LocalJumpError, "no block given" unless block_given?
78
+ Internal.with_timeout(timeout) do |_, deadline|
79
+ observed = generation
80
+ result = yield
81
+ return result if result
82
+
83
+ remaining = deadline - Clock.now if deadline
84
+ return if remaining && !remaining.positive?
85
+ return unless wait(observed, timeout: remaining)
86
+ end
87
+ end
88
+
89
+ # @api private
90
+ def inspect_with(inspector)
91
+ super do
92
+ inspector.attributes({ generation:, num_waiting: })
93
+ yield if block_given?
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ # A Ractor-shareable concurrent set maintained in ascending order.
7
+ # Membership uses `<=>`. Comparator-equivalent elements occupy one slot.
8
+ # Transfer modes have the same behavior and restrictions as Farce::Set.
9
+ #
10
+ # @example Traverse priorities in order
11
+ # priorities = Farce::SortedSet[30, 10, 20]
12
+ # priorities.to_a # => [10, 20, 30]
13
+ class SortedSet < Farce::Abstract::SortedSet
14
+ include Shareable::Delegated
15
+
16
+ # The default transfer mode for elements.
17
+ # @return [Symbol] The configured transfer mode.
18
+ def mode = @manager.mode
19
+
20
+ protected
21
+
22
+ def value_modes? = true
23
+
24
+ private
25
+
26
+ def initialize_value_mode(mode)
27
+ mode = :copy if UNDEFINED.equal?(mode)
28
+ @manager = ModeManager.new(mode:)
29
+ end
30
+
31
+ def new_map(entries = nil, compare_keys_by_identity: false, **)
32
+ raise ArgumentError, "sorted sets do not support identity comparison" if compare_keys_by_identity
33
+ Farce::Strict::TreeMap.new(entries)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable atomic reference that strongly retains shareable values directly.
8
+ # Values are stored without envelope wrapping or transfer modes.
9
+ #
10
+ # @example Updating a counter atomically
11
+ # counter = Farce::Strict::Atom.new(0)
12
+ # counter.update { |count| count + 1 } # => 1
13
+ # counter.compare_and_set(1, 2) # => true
14
+ # counter.value # => 2
15
+ #
16
+ # @example Keeping an immutable snapshot
17
+ # snapshot = [1, 2, 3].freeze
18
+ # atom = Farce::Strict::Atom.new(snapshot)
19
+ # atom.value.equal?(snapshot) # => true
20
+ # atom.update { |items| (items + [4]).freeze } # => [1, 2, 3, 4]
21
+ class Atom < Abstract::Atom
22
+ include Shareable::Delegated
23
+
24
+ # @param value [BasicObject, nil] the initial shareable value
25
+ # @param compare_by_identity [Boolean] whether comparisons use object identity instead of equality
26
+ def initialize(value = nil, compare_by_identity: false)
27
+ @atom = Internal::StrictAtom.new(value, compare_by_identity:)
28
+ super()
29
+ end
30
+
31
+ private def freeze_backend = @atom
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # Alias for {Farce::Counter} so {Strict} can be more easily used as a namespace.
8
+ Counter = Farce::Counter
9
+ end
10
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable rendezvous that exchanges shareable values directly.
8
+ # Values retain their identity and envelopes are returned unopened.
9
+ class Exchanger < Abstract::Exchanger
10
+ include Shareable::Unfreezable
11
+
12
+ def initialize
13
+ @exchanger = Internal::Exchanger.new
14
+ super
15
+ end
16
+
17
+ # (see Abstract::Exchanger#exchange)
18
+ # @raise [Ractor::IsolationError] if the offered value is not Ractor-shareable
19
+ def exchange(offered, timeout: nil, &)
20
+ raise Ractor::IsolationError, "value must be Ractor-shareable" unless Ractor.shareable?(offered)
21
+ super
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # Alias for {Farce::Flag} so {Strict} can be more easily used as a namespace.
8
+ Flag = Farce::Flag
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A shareable lazy value that retains its shareable result directly.
8
+ # The factory runs once, even when threads or Ractors access it concurrently.
9
+ # A failed factory or an unshareable result can be retried on the next access.
10
+ #
11
+ # @example Compute one shared snapshot
12
+ # lazy = Farce::Strict::Lazy.new { [:ready].freeze }
13
+ # lazy.value # => [:ready]
14
+ class Lazy < Abstract::Lazy
15
+ include Shareable::Tracked
16
+
17
+ # Resolve and freeze the slot without freezing the result.
18
+ # @return [self]
19
+ def freeze
20
+ value
21
+ internal_atom.freeze
22
+ super
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # @!parse
8
+ # # A {Reference} for a {Strict::Lazy} value.
9
+ # # Delegates to the result after computing it on first access.
10
+ # # Calling `freeze` resolves and freezes the target.
11
+ # #
12
+ # # @example
13
+ # # reference = Farce::Strict::LazyRef.new { [:ready].freeze }
14
+ # # reference.first # => :ready
15
+ # class LazyRef < Farce::Reference
16
+ # # @overload initialize(factory)
17
+ # # @param factory [Class, Proc, #call] the factory for the lazy value, which must be shareable
18
+ # # @overload initialize(self: nil)
19
+ # # @param self [BasicObject] the receiver to bind to the block, which must be shareable
20
+ # # @yield computes the value on first access
21
+ # # @yieldreturn [BasicObject] the computed result
22
+ # def initialize(...) = nil
23
+ # end
24
+ LazyRef = Reference[Farce::Strict::Lazy]
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable lease that stores a shareable resource directly.
8
+ # Construction and checkin reject non-shareable resources without freezing them.
9
+ # Checkout coordinates callers. Other references remain usable, so callers
10
+ # must honor the checkout when accessing a mutable resource.
11
+ #
12
+ # @example Coordinating several changes to shareable state
13
+ # lease = Farce::Strict::Lease.new { Farce::Strict::Map.new }
14
+ # lease.checkout do |state|
15
+ # state[:status] = :ready
16
+ # state[:generation] = 1
17
+ # end
18
+ # lease.checkout { |state| state[:status] } # => :ready
19
+ class Lease < Abstract::Lease
20
+ include Shareable::Unfreezable
21
+
22
+ private
23
+
24
+ def new_internal_lease(resource) = Internal::StrictLease.new(resource)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable map that stores independently leased shareable resources directly.
8
+ # Initial resources, insertions, and replacements must be shareable. They are
9
+ # not automatically frozen. Other references remain usable, so callers must
10
+ # honor the checkout when accessing mutable resources.
11
+ #
12
+ # @example Updating shareable resources in an automatic lease scope
13
+ # leases = Farce::Strict::LeaseMap.new do
14
+ # { primary: Farce::Strict::Map.new, replica: Farce::Strict::Map.new }
15
+ # end
16
+ # leases.auto_lease do
17
+ # leases[:primary][:status] = :ready
18
+ # leases[:replica][:status] = :ready
19
+ # end
20
+ # leases.checkout(:primary) { |state| state[:status] } # => :ready
21
+ class LeaseMap < Abstract::LeaseMap
22
+ include Shareable::Unfreezable
23
+
24
+ def shareable_values? = true
25
+
26
+ private
27
+
28
+ def new_internal_lease_map(mapping)
29
+ Internal::StrictLeaseMap.new(mapping, lease_class: Farce::Strict::Lease, registry_class: Farce::Strict::Map)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable pool that stores shareable resources directly.
8
+ # Factory results and checkin replacements must be shareable. They are not
9
+ # automatically frozen. Other references remain usable during checkout,
10
+ # so callers must honor the checkout when accessing mutable resources.
11
+ #
12
+ # @example Reusing shareable resources with bounded concurrency
13
+ # pool = Farce::Strict::LeasePool.new(max_size: 2) { Farce::Strict::Map.new }
14
+ # pool.checkout { |state| state[:uses] = (state[:uses] || 0) + 1 }
15
+ # pool.checkout { |state| state[:uses] } # => 1
16
+ class LeasePool < Abstract::LeasePool
17
+ include Shareable::Unfreezable
18
+
19
+ private
20
+
21
+ def prepare_factory(factory)
22
+ Ractor.shareable?(factory) ? factory : Ractor.shareable_proc(&factory)
23
+ end
24
+
25
+ def new_internal_pool(max_size) = Internal::StrictLeasePool.new(max_size)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable LFU map that stores shareable values directly.
8
+ class LFUMap < Abstract::LFUMap
9
+ include Shareable::Delegated
10
+
11
+ # (see Abstract::Map#shareable_keys?)
12
+ def shareable_keys? = true
13
+
14
+ # (see Abstract::Map#shareable_values?)
15
+ def shareable_values? = true
16
+
17
+ private
18
+
19
+ def new_bounded_map(...) = Internal::StrictLFUMap.new(...)
20
+ def freeze_backend = internal_map
21
+
22
+ def new_key_locks(compare_keys_by_identity:)
23
+ Internal::KeyLockMap.new(registry_class: Farce::Strict::Map, compare_keys_by_identity:)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable LRU map that stores shareable values directly.
8
+ # Keys must be shareable, except equality-mode mutable strings that can be snapshotted.
9
+ class LRUMap < Abstract::LRUMap
10
+ include Shareable::Delegated
11
+
12
+ # (see Abstract::Map#shareable_keys?)
13
+ def shareable_keys? = true
14
+
15
+ # (see Abstract::Map#shareable_values?)
16
+ def shareable_values? = true
17
+
18
+ private
19
+
20
+ def new_bounded_map(...) = Internal::StrictLRUMap.new(...)
21
+ def freeze_backend = internal_map
22
+
23
+ def new_key_locks(compare_keys_by_identity:)
24
+ Internal::KeyLockMap.new(registry_class: Farce::Strict::Map, compare_keys_by_identity:)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable concurrent map that stores shareable keys and values directly.
8
+ # Updates on different keys can run concurrently.
9
+ #
10
+ # Clearing the map invalidates unfinished updates so they cannot restore removed entries.
11
+ #
12
+ # `dup` and `clone` copy entries into independent storage while sharing stored values.
13
+ # `dup` and ordinary `clone` remain Ractor-shareable.
14
+ #
15
+ # @example Atomically counting occurrences
16
+ # counts = Farce::Strict::Map.new
17
+ # counts.upsert(:ruby, 1) { |count| count + 1 } # => 1
18
+ # counts.upsert(:ruby, 1) { |count| count + 1 } # => 2
19
+ class Map < Abstract::ConcurrentMap
20
+ include Shareable::Delegated
21
+
22
+ # @!macro map_initialization
23
+ def initialize(
24
+ initial_mapping = nil,
25
+ normalize_keys: nil,
26
+ compare_by_identity: false,
27
+ compare_keys_by_identity: compare_by_identity,
28
+ compare_values_by_identity: compare_by_identity
29
+ )
30
+ initial_mapping = convert_entries(initial_mapping)
31
+ restoring = Internal::KeyNormalizer.restoration?(normalize_keys)
32
+ normalizer = Internal::KeyNormalizer.build(normalize_keys, shareable: true)
33
+ populate = initial_mapping && ((normalizer && !restoring) || !initial_mapping.is_a?(Hash))
34
+ @map = Internal::StrictMap.new(
35
+ populate ? nil : initial_mapping,
36
+ compare_by_identity:,
37
+ compare_keys_by_identity:,
38
+ compare_values_by_identity:,
39
+ )
40
+ Internal::KeyNormalizer.install_concurrent(self, normalizer) unless restoring
41
+ initial_mapping.each { |key, value| self[key] = value } if populate
42
+ Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
43
+ super()
44
+ end
45
+
46
+ def shareable_keys? = true
47
+ def shareable_values? = true
48
+
49
+ private def freeze_backend = internal_map
50
+
51
+ Internal.prepare_map_access(self, :strict)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable record whose atoms retain only shareable values.
8
+ # Use {Abstract::Molecule.define} to declare named fields.
9
+ # Explicitly supplied atoms keep their own storage and comparison policies.
10
+ class Molecule < Abstract::Molecule
11
+ include Shareable
12
+
13
+ private def create_atom(_, value) = Atom.new(value, compare_by_identity: compare_by_identity?)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Strict
7
+ # A Ractor-shareable port that accepts shareable messages directly.
8
+ # Messages retain their identity and envelopes are returned unopened.
9
+ # Only the creating Ractor can receive messages or close the port.
10
+ #
11
+ # @example Receive an already prepared message
12
+ # port = Farce::Strict::Port.new
13
+ # message = [:ready, 42].freeze
14
+ # port << message
15
+ # port.receive.equal?(message) # => true
16
+ # port.close
17
+ #
18
+ # @!method initialize
19
+ # Creates a port without transfer modes.
20
+ class Port < Internal::Port
21
+ include Abstract::Port
22
+
23
+ # @!visibility private
24
+ # (see #initialize)
25
+ # CRuby 3.4's backend also accepts an existing port or Ractor.
26
+ # Keep construction argument-free on every runtime.
27
+ def self.new = super # rubocop:disable Lint/UselessMethodDefinition
28
+
29
+ # (see Abstract::Port#send)
30
+ # @raise [Farce::Ractor::IsolationError] if the message is not Ractor-shareable
31
+ def send(message)
32
+ raise Ractor::IsolationError, "value must be Ractor-shareable" unless Ractor.shareable?(message)
33
+ super
34
+ end
35
+
36
+ # @return [String] a string representation of the port
37
+ def inspect = super.sub(/\A#<.+? (?=(?:to|id):#?\d+)/, "#<Farce::Strict::Port ")
38
+ end
39
+ end
40
+ end