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,345 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Superclass for all maps defined by Farce.
8
+ # @note
9
+ # The supported methods are generally compatible with their Hash counterparts,
10
+ # with the notable exception of {ConcurrentMap#update}.
11
+ #
12
+ # A Hash-like collection with slightly reduced functionality to allow for better concurrency models.
13
+ #
14
+ # Constructors accept a Hash, another map, or an object whose #each yields key/value pairs.
15
+ # Arrays of pairs and enumerators are supported. Initial entries are inserted in source order.
16
+ # Local maps retain the initial entries for reuse in each scope.
17
+ #
18
+ # `dup` and `clone` create independent storage and coordination while sharing keys and stored values.
19
+ # Value modes and key normalization are preserved without transferring values again.
20
+ # Copies of shareable maps remain shareable unless explicitly cloned with `freeze: false`.
21
+ # Local copies retain the current scope's contents. Other scopes use the original constructor configuration.
22
+ # Lease maps reject copying because resources cannot safely be given independent ownership controls.
23
+ #
24
+ # Iteration order is implementation-dependent. In particular, insertion order is not guaranteed.
25
+ #
26
+ # Implementations can compare keys and values either by equality or by identity. Operations accepting a
27
+ # `timeout` wait at most that many seconds to acquire the access needed for the operation. A timeout must be a
28
+ # finite, non-negative number, `nil` waits indefinitely.
29
+ #
30
+ # @!method [](key)
31
+ # Look up a key without waiting for atomic-update access.
32
+ # @param key [BasicObject] The key to look up.
33
+ # @return [BasicObject, nil] The associated value, or nil if the key is absent.
34
+ # @abstract
35
+ #
36
+ # @!method []=(key, value)
37
+ # Associate a value with a key without a timeout.
38
+ # @param key [BasicObject] The key to store.
39
+ # @param value [BasicObject] The value to store.
40
+ # @return [BasicObject] `value`.
41
+ # @abstract
42
+ #
43
+ # @!method store_if_absent(key)
44
+ # Read an existing value or construct and store a value for an absent key.
45
+ # Existing nil and false values count as present when the implementation permits them.
46
+ # The block runs without holding a map-wide lock. Implementations document their
47
+ # coordination guarantees, ownership requirements, and optional timeout support.
48
+ # A later removal or eviction can cause another call to construct a new value.
49
+ # @param key [BasicObject] The key to look up or store.
50
+ # @yield Called without arguments when the key is absent.
51
+ # @yieldreturn [BasicObject] The value to store and return.
52
+ # @return [BasicObject] The existing or newly constructed value.
53
+ # @raise [LocalJumpError] If no block is given.
54
+ # @abstract
55
+ #
56
+ # @!method clear
57
+ # Remove all entries from the map.
58
+ # @return [self]
59
+ # @abstract
60
+ #
61
+ # @!method compare_keys_by_identity?
62
+ # @return [Boolean] Whether keys are compared by identity instead of `hash` and `eql?`.
63
+ # @abstract
64
+ #
65
+ # @!method compare_values_by_identity?
66
+ # @return [Boolean] Whether values are compared by identity instead of equality.
67
+ # @abstract
68
+ #
69
+ # @!method delete(key)
70
+ # Remove a key and its associated value.
71
+ # @param key [BasicObject] The key to remove.
72
+ # @return [BasicObject, nil] The removed value, or nil if the key was absent.
73
+ # @abstract
74
+ #
75
+ # @!method each
76
+ # Iterate over the map's key-value pairs.
77
+ # Entry consistency and access requirements depend on the implementation. Iteration order is not guaranteed
78
+ # to match insertion order.
79
+ # @overload each
80
+ # @yield [pair] Called once for each entry.
81
+ # @yieldparam pair [Array<BasicObject>] A two-element `[key, value]` pair.
82
+ # @return [self]
83
+ # @overload each
84
+ # @return [Enumerator] An enumerator over two-element `[key, value]` pairs.
85
+ # @abstract
86
+ #
87
+ # @!method each_key
88
+ # Iterate over the keys currently stored in the map.
89
+ # Keys are not guaranteed to be yielded in insertion order.
90
+ # @overload each_key
91
+ # @yield [key] Called once for each stored key.
92
+ # @yieldparam key [BasicObject] A stored key.
93
+ # @return [self]
94
+ # @overload each_key
95
+ # @return [Enumerator] An enumerator over the stored keys.
96
+ # @abstract
97
+ #
98
+ # @!method each_pair
99
+ # Iterate over key-value pairs in the same manner as {#each}.
100
+ # @see #each
101
+ # @abstract
102
+ #
103
+ # @!method each_value
104
+ # Iterate over the values currently stored in the map.
105
+ # Values are not guaranteed to be yielded in insertion order.
106
+ # @overload each_value
107
+ # @yield [value] Called once for each stored value.
108
+ # @yieldparam value [BasicObject] A stored value.
109
+ # @return [self]
110
+ # @overload each_value
111
+ # @return [Enumerator] An enumerator over the stored values.
112
+ # @abstract
113
+ #
114
+ # @!method fetch(key, *defaults)
115
+ # Fetch the value associated with a key, using the same missing-key behavior as Hash#fetch.
116
+ # If both a default and a block are provided, the block takes precedence and a warning is emitted.
117
+ # @overload fetch(key)
118
+ # @param key [BasicObject] The key to look up.
119
+ # @return [BasicObject] The associated value.
120
+ # @raise [KeyError] If the key is absent.
121
+ # @overload fetch(key, default)
122
+ # @param key [BasicObject] The key to look up.
123
+ # @param default [BasicObject] The value to return if the key is absent.
124
+ # @return [BasicObject] The associated value or `default`.
125
+ # @overload fetch(key)
126
+ # @param key [BasicObject] The key to look up.
127
+ # @yield [key] Called if the key is absent.
128
+ # @yieldparam key [BasicObject] The missing key.
129
+ # @yieldreturn [BasicObject] The value to return.
130
+ # @return [BasicObject] The associated value or the block result.
131
+ # @abstract
132
+ #
133
+ # @!method getkey(key)
134
+ # Return the stored key that matches a lookup key.
135
+ # @param key [BasicObject] The key to match.
136
+ # @return [BasicObject, nil] The matching stored key, or nil if no key matches.
137
+ # @abstract
138
+ #
139
+ # @!method key?(key)
140
+ # Test whether a key is present, including when its associated value is nil.
141
+ # @param key [BasicObject] The key to look up.
142
+ # @return [Boolean] Whether the key is present.
143
+ # @abstract
144
+ #
145
+ # @!method keys
146
+ # Return the keys currently stored in the map.
147
+ # The returned keys are not guaranteed to be in insertion order.
148
+ # @return [Array<BasicObject>] A new array containing the stored keys.
149
+ # @abstract
150
+ #
151
+ # @!method size
152
+ # Return the number of entries currently in the map.
153
+ # @return [Integer] The number of entries.
154
+ # @abstract
155
+ class Map
156
+ include Internal::MarshalSupport::Map
157
+ include Enumerable
158
+ include Internal::Inspect
159
+
160
+ # Store a value using the map's assignment operation.
161
+ # Concurrent maps override this method to support timeouts.
162
+ # @param key [BasicObject] the key to store
163
+ # @param value [BasicObject] the value to store
164
+ # @return [BasicObject] `value`
165
+ def store(key, value) = self[key] = value
166
+
167
+ # Return a two-element array containing a key and its associated value, if the key is present,
168
+ # or nil if the key is absent.
169
+ # @param key [BasicObject] The key to look up.
170
+ # @return [Array(BasicObject, BasicObject), nil] A two-element `[key, value]` array, or nil if the key is absent.
171
+ def assoc(key)
172
+ value = fetch(key) { return nil }
173
+ [key, value]
174
+ end
175
+
176
+ # (see #compare_keys_by_identity?)
177
+ def compare_by_identity? = compare_keys_by_identity?
178
+
179
+ # Implements Ruby's [dig interface](https://docs.ruby-lang.org/en/master/language/dig_methods_rdoc.html).
180
+ # @param key [BasicObject] The key to look up.
181
+ # @param rest [Array<BasicObject>] Additional keys to look up in nested maps.
182
+ # @return [BasicObject, nil] The value found at the nested location, or nil if any key is absent or nil.
183
+ def dig(key, *rest)
184
+ value = self[key]
185
+ return value if rest.empty? || value.nil?
186
+ value.dig(*rest)
187
+ end
188
+
189
+ # Returns whether the map contains no entries.
190
+ # @return [Boolean] Whether the map is empty.
191
+ def empty? = size.zero?
192
+
193
+ # Return the number of entries currently in the map.
194
+ # @return [Integer]
195
+ def length = size
196
+
197
+ # Return whether an observed value matches using this map's value comparison setting.
198
+ # Values are unwrapped before comparison. Concurrent changes may make the result stale.
199
+ # @param value [BasicObject] the value to find
200
+ # @return [Boolean]
201
+ def value?(value)
202
+ identity = compare_values_by_identity?
203
+ each_value.any? { |stored| identity ? stored.equal?(value) : stored == value }
204
+ end
205
+ alias has_value? value?
206
+
207
+ # Return a matching key using this map's value comparison setting, or nil.
208
+ # The first observed match is returned. No insertion order is guaranteed.
209
+ # @param value [BasicObject] the value to find
210
+ # @return [BasicObject, nil]
211
+ def key(value)
212
+ pair = rassoc(value)
213
+ pair&.first
214
+ end
215
+
216
+ # Return an observed key/value pair using this map's value comparison setting, or nil.
217
+ # Values are unwrapped before comparison. Concurrent changes may make the result stale.
218
+ # @param value [BasicObject] the value to find
219
+ # @return [Array, nil]
220
+ def rassoc(value)
221
+ identity = compare_values_by_identity?
222
+ each_pair do |key, stored|
223
+ return [key, stored] if identity ? stored.equal?(value) : stored == value
224
+ end
225
+ nil
226
+ end
227
+
228
+ # Alias for {#key?}
229
+ def has_key?(...) = key?(...) # rubocop:disable Naming/PredicatePrefix
230
+ alias member? has_key?
231
+ alias include? has_key?
232
+
233
+ # Fetches the values associated with multiple keys, using the same missing-key behavior as Hash#fetch.
234
+ # @yield [key] Called for each missing key.
235
+ # @yieldparam key [BasicObject] The missing key.
236
+ # @yieldreturn [BasicObject] The value to return for the missing key.
237
+ # @param keys [Array<BasicObject>] The keys to look up.
238
+ # @return [Array<BasicObject>] An array of the associated values.
239
+ def fetch_values(*keys, &) = keys.map { fetch(it, &) }
240
+
241
+ # @note
242
+ # Some maps may still accept non-shareable keys or values, but convert them into shareable representations.
243
+ # This method will still return `true` for such maps.
244
+ #
245
+ # @return [Boolean] Whether the map requires keys to be Ractor-shareable
246
+ def shareable_keys? = false
247
+
248
+ # @return [Boolean] Whether the map requires values to be Ractor-shareable
249
+ def shareable_values? = false
250
+
251
+ # Creates a new Array containing the map's key-value pairs as two-element arrays.
252
+ # @return [Array<Array(BasicObject, BasicObject)>>] A new Array of `[key, value]` arrays.
253
+ def to_a = each_pair.to_a
254
+
255
+ # Creates a new Hash containing the map's entries.
256
+ # Preserves identity comparison for keys, including when a block transforms entries.
257
+ # @yieldparam key [BasicObject] an existing key
258
+ # @yieldparam value [BasicObject] its value
259
+ # @yieldreturn [Array(BasicObject, BasicObject)] the key and value for the new Hash
260
+ # @return [Hash] A new Hash with the original entries, or the pairs returned by the block.
261
+ def to_h(&) = entries_to_hash(each_pair, &)
262
+
263
+ # Support implicit Hash conversion using this map's {#to_h} implementation.
264
+ # @return [Hash] A new Hash containing the map's entries.
265
+ def to_hash = to_h
266
+
267
+ # Support hash patterns using the same entries and key comparison as {#to_h}.
268
+ # Like Hash, this returns all entries regardless of the requested keys.
269
+ # @param keys [Array, nil] the optional key hint supplied by Ruby's pattern matcher
270
+ # @return [Hash] A new Hash containing the map's entries.
271
+ def deconstruct_keys(keys) = to_h # rubocop:disable Lint/UnusedMethodArgument
272
+
273
+ # Fetches the values associated with multiple keys, returning nil for any missing keys.
274
+ # @param keys [Array<BasicObject>] The keys to look up.
275
+ # @return [Array<BasicObject>] An array of the associated values, with nil for any missing keys.
276
+ def values_at(*keys) = keys.map { self[it] }
277
+
278
+ # Some maps reference their keys weakly, automatically dropping entries when a key gets garbage-collected.
279
+ # @return [Boolean] Whether the map uses weak references for keys.
280
+ def weak_keys? = false
281
+
282
+ # Some maps reference their values weakly, automatically dropping entries when a value gets garbage-collected.
283
+ # @return [Boolean] Whether the map uses weak references for values.
284
+ def weak_values? = false
285
+
286
+ # @return [String] String representation of the map, suitable for debugging.
287
+ def to_s = inspect
288
+
289
+ # @api private
290
+ def inspect_with(inspector)
291
+ super do
292
+ yield if block_given?
293
+ inspector.breakable
294
+ inspector.group("{", "}") do
295
+ inspector.breakable ""
296
+ inspector.seplist(self, nil, :each_for_inspect) do |key, value|
297
+ inspector.group { inspect_pair(inspector, key, value) }
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ protected
304
+
305
+ # Convert a public value to its stored representation.
306
+ # @api private
307
+ def wrap_value(value) = value
308
+
309
+ # Convert a stored representation to its public value.
310
+ # @api private
311
+ def unwrap_value(value) = value
312
+
313
+ private
314
+
315
+ def entries_to_hash(entries, &)
316
+ return entries.to_h(&) unless compare_keys_by_identity?
317
+ hash = {}.compare_by_identity
318
+ entries.each do |key, value|
319
+ if block_given?
320
+ pair = Array.try_convert(yield(key, value))
321
+ raise TypeError, "block must return an Array or respond to #to_ary" unless pair
322
+ raise ArgumentError, "block must return a two-element pair" unless pair.size == 2
323
+ key, value = pair
324
+ end
325
+ hash[key] = value
326
+ end
327
+ hash
328
+ end
329
+
330
+ def convert_entries(entries)
331
+ return entries if Map === entries
332
+ if entries.respond_to?(:to_hash)
333
+ entries = Hash.try_convert(entries)
334
+ raise TypeError, "entries must be a Hash or respond to #to_hash" unless entries
335
+ end
336
+ return entries if entries.nil? || entries.respond_to?(:each)
337
+ raise TypeError, "entries must yield key/value pairs with #each"
338
+ end
339
+
340
+ def each_for_inspect(&) = each(&)
341
+ def inspect_pair(inspector, key, value) = inspector.hash_pair(key, value) { inspect_value(inspector, value) }
342
+ def inspect_value(inspector, ...) = inspector.object(...)
343
+ end
344
+ end
345
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract A record whose fields are independently atomic references.
8
+ #
9
+ # Define a record class with {.define}, then read or assign its named fields.
10
+ # Use each field's `<name>_atom` for updates, comparisons, and waits.
11
+ # Operations on several fields are not a transaction or a consistent snapshot.
12
+ class Molecule
13
+ include Internal::MarshalSupport::Initialize
14
+ include Internal::Freeze::Tracked
15
+ include Internal::Inspect
16
+ include Enumerable
17
+
18
+ EMPTY_ARRAY = [].freeze
19
+ private_constant :EMPTY_ARRAY
20
+
21
+ ACCESSORS = Module.new do
22
+ def get = public_send(:"#{__callee__}_atom").value
23
+ def set(value) = public_send(:"#{__callee__.to_s.delete_suffix("=")}_atom").value = value
24
+ def atom = @molecule_atoms.fetch(__callee__, nil)
25
+
26
+ def atom=(value)
27
+ @molecule_atoms[__callee__.to_s.delete_suffix("=").to_sym] = value
28
+ end
29
+ end
30
+
31
+ private_constant :ACCESSORS
32
+
33
+ # Create a record class with readers, writers, and `<name>_atom` accessors.
34
+ # Missing initial values default to nil. Generated classes may be subclassed.
35
+ # @param fields [Array<Symbol, String>] unique field names
36
+ # @param compare_by_identity [Boolean, nil] the default comparison policy, or nil to inherit
37
+ # @return [Class<Molecule>] the record class
38
+ # @raise [ArgumentError] if names conflict with the record interface
39
+ def self.define(*fields, compare_by_identity: nil)
40
+ fields = fields.map(&:to_sym)
41
+ names = fields.flat_map { [it, :"#{it}=", :"#{it}_atom", :"#{it}_atom="] }
42
+
43
+ conflicts = names.any? do |name|
44
+ next true if name == :freeze
45
+ next false unless method_defined?(name) || private_method_defined?(name)
46
+ instance_method(name).owner != Enumerable
47
+ end
48
+
49
+ if names.uniq.length != names.length || conflicts
50
+ raise ArgumentError, "field names must be unique and must not override the molecule interface"
51
+ end
52
+
53
+ Class.new(self) do
54
+ singleton_class.class_eval { undef define }
55
+ unless nil.equal?(compare_by_identity)
56
+ class_eval "def self.compare_by_identity? = #{(!!compare_by_identity).inspect}", __FILE__, __LINE__ - 1
57
+ end
58
+
59
+ atoms = []
60
+ members = fields.map do |field|
61
+ define_member(field)
62
+ atoms << :"#{field}_atom"
63
+ field
64
+ end
65
+
66
+ @atoms = Ractor.make_shareable(atoms.freeze)
67
+ @members = Ractor.make_shareable(members.freeze)
68
+
69
+ set_temporary_name("#{superclass.name}#{@members.inspect}")
70
+ end
71
+ end
72
+
73
+ # @api private
74
+ def self.[](...) = define(...)
75
+
76
+ # @return [Boolean] the default comparison policy for new records
77
+ def self.compare_by_identity? = false
78
+
79
+ # @!visibility private
80
+ def self.define_member(field)
81
+ raise ArgumentError, "#{field.inspect} is not a valid field name" if field == :compare_by_identity
82
+ if field =~ /\A[a-z_]\w*\z/i
83
+ attr_accessor :"#{field}_atom"
84
+ private :"#{field}_atom="
85
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
86
+ def #{field} = self.#{field}_atom.value
87
+
88
+ def #{field}=(value)
89
+ self.#{field}_atom.value = value
90
+ end
91
+ RUBY
92
+ else
93
+ define_method(:"#{field}_atom", ACCESSORS.instance_method(:atom))
94
+ define_method(:"#{field}_atom=", ACCESSORS.instance_method(:atom=))
95
+ define_method(field, ACCESSORS.instance_method(:get))
96
+ define_method(:"#{field}=", ACCESSORS.instance_method(:set))
97
+ private :"#{field}_atom="
98
+ end
99
+ end
100
+ private_class_method :define_member
101
+
102
+ # @return [Array<Symbol>] the atom accessor names in declaration order
103
+ def self.atoms
104
+ return @atoms if defined?(@atoms) && @atoms
105
+ return superclass.atoms if superclass.respond_to?(:atoms)
106
+ EMPTY_ARRAY
107
+ end
108
+
109
+ # @return [Array<Symbol>] the field names in declaration order
110
+ def self.members
111
+ return @members if defined?(@members) && @members
112
+ return superclass.members if superclass.respond_to?(:members)
113
+ EMPTY_ARRAY
114
+ end
115
+
116
+ # Initialize fields by position or name. A field may only be supplied once.
117
+ # Existing {Atom} instances are retained directly, preserving their policy.
118
+ # @param input [Array<BasicObject>] values in declaration order
119
+ # @param attributes [Hash{Symbol => BasicObject}] values by field name
120
+ # @param compare_by_identity [Boolean, nil] the comparison policy, or nil for the class default
121
+ # @raise [ArgumentError] for unknown, repeated, or excess values
122
+ def initialize(*input, compare_by_identity: nil, **attributes)
123
+ raise ArgumentError, "too many positional values" if input.length > members.length
124
+ @compare_by_identity = compare_by_identity.nil? ? self.class.compare_by_identity? : !!compare_by_identity # rubocop:disable Style/DoubleNegation
125
+ @molecule_atoms = {}
126
+ input.each_with_index { initialize_atom(members[_2], _1) }
127
+ attributes.each { initialize_atom(_1, _2) }
128
+ members.each { initialize_atom(it, nil) unless public_send(:"#{it}_atom") }
129
+ @molecule_atoms.freeze
130
+ super()
131
+ end
132
+
133
+ # @api private
134
+ def marshal_dump
135
+ options = { compare_by_identity: compare_by_identity? }
136
+ options[:mode] = mode if respond_to?(:mode)
137
+ options[:scope] = scope if respond_to?(:scope)
138
+ fields = members.map { |member| [member, public_send(:"#{member}_atom")] }
139
+ [1, fields, options, frozen?]
140
+ end
141
+
142
+ # @api private
143
+ def marshal_load(data)
144
+ fields, options, frozen = Internal::MarshalSupport.payload(data, 3)
145
+ initialize(**fields.to_h, **options)
146
+ Internal::MarshalSupport.freeze(self, frozen)
147
+ end
148
+
149
+ # @api private
150
+ def transaction_wrapper(transaction) = Transaction::Molecule.new(transaction, self)
151
+
152
+ # Whether newly created atoms compare by identity instead of equality.
153
+ # Explicitly supplied atoms retain their own comparison policy.
154
+ # @return [Boolean]
155
+ def compare_by_identity? = @compare_by_identity
156
+
157
+ # (see .atoms)
158
+ def atoms = self.class.atoms
159
+
160
+ # (see .members)
161
+ def members = self.class.members
162
+
163
+ # Yield field names and current values in declaration order.
164
+ # @yieldparam member [Symbol] the field name
165
+ # @yieldparam value [BasicObject] its current value
166
+ # @return [Array<Symbol>, Enumerator]
167
+ def each
168
+ return enum_for(:each) unless block_given?
169
+ members.each { yield it, public_send(it) }
170
+ end
171
+ alias each_pair each
172
+
173
+ # Yield atom accessor names and atomic references in declaration order.
174
+ # @yieldparam name [Symbol] the atom accessor name
175
+ # @yieldparam atom [Atom] the field's atomic reference
176
+ # @return [Array<Symbol>, Enumerator]
177
+ def each_atom
178
+ return enum_for(:each_atom) unless block_given?
179
+ atoms.each { yield it, public_send(it) }
180
+ end
181
+
182
+ # Yield field names in declaration order.
183
+ # @return [Array<Symbol>, Enumerator]
184
+ def each_member
185
+ return enum_for(:each_member) unless block_given?
186
+ members.each { yield it }
187
+ end
188
+ alias each_key each_member
189
+
190
+ # Yield current field values in declaration order.
191
+ # @return [Array<Symbol>, Enumerator]
192
+ def each_value
193
+ return enum_for(:each_value) unless block_given?
194
+ members.each { yield public_send(it) }
195
+ end
196
+
197
+ # Prevent field replacement and atom updates without freezing stored values.
198
+ # Coordinate with writers before freezing. This is not a snapshot operation.
199
+ # @return [self]
200
+ def freeze
201
+ return self if frozen?
202
+ each_atom { |_, atom| atom.freeze }
203
+ super
204
+ end
205
+
206
+ # @api private
207
+ def inspect_with(inspector)
208
+ super do
209
+ yield if block_given?
210
+ each_member do |member|
211
+ inspector.breakable
212
+ inspector.text("#{member}=")
213
+ atom = public_send(:"#{member}_atom")
214
+ atom.__send__(:inspect_value, inspector, nil)
215
+ end
216
+ end
217
+ end
218
+
219
+ private
220
+
221
+ # @abstract Build the atomic reference for one field.
222
+ # @param key [Symbol] the field name
223
+ # @param value [BasicObject] its initial value
224
+ # @return [Atom]
225
+ def create_atom(_key, _value) = raise NoMethodError, "create_atom must be implemented in the subclass"
226
+
227
+ def initialize_atom(key, value)
228
+ getter = :"#{key}_atom"
229
+ setter = :"#{key}_atom="
230
+
231
+ raise ArgumentError, "#{key.inspect} is not a valid member" unless respond_to?(getter)
232
+ current = public_send(:"#{key}_atom")
233
+
234
+ if respond_to?(setter, true)
235
+ raise ArgumentError, "#{key} has already been initialized" if current
236
+ value = create_atom(key, value) unless Atom === value
237
+ __send__(:"#{key}_atom=", value)
238
+ else
239
+ raise TypeError, "expected #{getter.inspect} to return an Atom" unless current.is_a?(Atom)
240
+ current.value = value
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Abstract
7
+ # @abstract Common interface and ownership tracking for Farce ports.
8
+ # @note
9
+ # This is a module so both implementations can inherit directly from the runtime's port backend.
10
+ #
11
+ # @!method send(message)
12
+ # Sends a message through the port.
13
+ # @param message [BasicObject] the message to send
14
+ # @return [self]
15
+ # @raise [Farce::Ractor::ClosedError] if the port is closed
16
+ #
17
+ # @!method receive(timeout: nil)
18
+ # Waits for a message or the timeout. Only the owning Ractor can receive.
19
+ # @param timeout [Numeric, nil] the maximum seconds to wait, or nil to wait indefinitely
20
+ # @return [BasicObject, nil] the received message, or nil on timeout
21
+ # @raise [Farce::Ractor::ClosedError] if the port is closed
22
+ #
23
+ # @!method close
24
+ # Closes the port. Only the owning Ractor can close it.
25
+ # @return [self]
26
+ #
27
+ # @!method closed?
28
+ # @return [Boolean] whether the port is closed
29
+ module Port
30
+ include Internal::MarshalSupport::Reject
31
+ include Internal::Noncopyable
32
+ include Shareable::Native
33
+ include Shareable::Unfreezable
34
+
35
+ # @api private
36
+ def initialize(...)
37
+ # Native Ractor ports cannot hold Ruby instance variables.
38
+ Internal::Storage.ractor[self] = true
39
+ super
40
+ end
41
+
42
+ # Checks whether the current Ractor created this port.
43
+ # @return [Boolean] whether the current Ractor owns the port
44
+ def owned? = !!Internal::Storage.ractor[self]
45
+
46
+ # Forwards all arguments to {#send}.
47
+ # @return [self]
48
+ def <<(...) = send(...)
49
+
50
+ # Forwards all arguments to {#send}.
51
+ # @return [self]
52
+ def push(...) = send(...)
53
+
54
+ # Forwards all arguments to {#receive}.
55
+ # @return [BasicObject, nil] the received message, or nil on timeout
56
+ def pop(...) = receive(...)
57
+
58
+ # @api private
59
+ def pretty_print(pp)
60
+ string = inspect
61
+ return pp.text(string) unless match = string.match(/\A#<([\w:]+)((?: \w+:#?\w+)+)>\z/)
62
+
63
+ pp.group(1, "#<#{match[1]}", ">") do
64
+ match[2].split.each do |pair|
65
+ pp.breakable " "
66
+ key, value = pair.split(":", 2)
67
+ pp.text "#{key}:"
68
+ pp.text value
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end