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
data/SECURITY.md ADDED
@@ -0,0 +1,10 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ Please do not open public issues or pull requests about open security vulnerabilities.
6
+
7
+ Report vulnerabilities privately to [security@rkh.im](mailto:security@rkh.im) with the subject line "Farce Security Vulnerability Report".
8
+ Include a description of the vulnerability, affected versions, and steps to reproduce it.
9
+
10
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for general contribution guidelines.
@@ -0,0 +1,185 @@
1
+ <!--
2
+ # @title Benchmarks
3
+ -->
4
+
5
+ # Benchmarks
6
+
7
+ Farce also aims to be fast and efficient, aiming for anywhere between a minimal overhead to outperforming other options.
8
+
9
+ Any numbers quoted here are to be taken with a grain of salt:
10
+
11
+ * They are based on micro-benchmarks, which may not reflect real-world performance.
12
+ * They are momentary snapshots. Gems and Ruby implementations are constantly evolving,
13
+ so these numbers may not be accurate in the future.
14
+ * Concrete numbers are largely measured on a local machine, which may not reflect your deployment environment.
15
+
16
+ You should measure the performance of your own application under realistic conditions.
17
+
18
+ ## Map performance
19
+
20
+ A shared map is a very common data structure for tracking state. While the read and write performance is hopefully not the bottleneck for your application.
21
+
22
+ Map implementation | Read | Write | Notes
23
+ -----------------------------|-------------|-------------|-----
24
+ `Hash` | fastest | fastest | Not ractor-shareable (when mutable), not thread-safe
25
+ `Concurrent::Hash` | 1.1x slower | 1.1x slower | Not ractor-shareable
26
+ `Farce::Strict::Map` | 1.2x slower | 1.1x slower |
27
+ `Farce::Unshared::Map` | 1.2x slower | 1.1x slower | Not ractor-shareable
28
+ `Farce::Map` | 1.3x slower | 1.1x slower |
29
+ `Concurrent::Map` | 1.4x slower | 3.2x slower | Not ractor-shareable
30
+ `Hash` + `Mutex` | 2.9x slower | 2.9x slower | Not ractor-shareable
31
+ `Ractor::LockHash` | 2.9x slower | 3.4x slower | Not fiber-friendly
32
+ `Ratomic::Map` | 3.1x slower | 2.7x slower | Breaks isolation, not fiber-friendly
33
+ `Ractor::KeyLockHash` | 3.2x slower | 2.5x slower | Not fiber-friendly
34
+ `Farce::LRUMap` | 3.4x slower | 7.6x slower | Automatic eviction
35
+ `Farce::LFUMap` | 3.5x slower | 7.6x slower | Automatic eviction
36
+ `Farce::Unsafe::TreeMap` | 3.7x slower | 4.1x slower | Ordered entries, not thread-safe, not ractor-shareable
37
+ `HashWithIndifferentAccess` | 4.5x slower | 5.3x slower | Not ractor-shareable
38
+ `RactorSafe::HashMap` | 4.8x slower | 4.8x slower |
39
+ `Farce::TreeMap` | 5.5x slower | 40x slower | Ordered entries
40
+ `Farce::LeaseMap` | 30x slower | 40x slower | Shared ractor for all lease maps
41
+ `Ractor::ActorHash` | 400x slower | 280x slower | Additional ractor per map
42
+
43
+ The map implementations namespaced under `Ractor` are from the [ractor-sharing](https://github.com/ko1/ractor-sharing) gem.
44
+
45
+ Also note that `Ratomic::Map` has a significant performance benefit over all other implementations when repeatedly writing to different keys in very large maps concurrently on a very high number of Ractors due to the underlying [DashMap](https://github.com/xacrimon/dashmap) implementing data sharding. This benefit does not materializes if different Ractors share the keys they use, so its usefulness is slightly hampered by the fact that you cannot iterate over Ratomic's maps at all.
46
+
47
+ ## Counter performance
48
+
49
+ > [!CAUTION]
50
+ > If counter performance is your application's bottleneck, **Ruby might not be the right choice for you**.
51
+
52
+ ### CRuby (4.0)
53
+
54
+ Implementation | Increment | Read value | Integer size | Note
55
+ ---------------------|-------------|----------------|--------------|-------
56
+ farce | fastest | fastest | 64-bit |
57
+ concurrent-ruby-ext | 1.2x slower | same-ish | 32-bit | no ractor support
58
+ ratomic | 1.5x slower | 1.6x slower | 64-bit | no overflow protection
59
+ ractor_safe | 2.1x slower | 2.1x slower | 64-bit |
60
+ concurrent-ruby | 12x slower | 5x slower | 32-bit | no ractor support
61
+
62
+ Performance differences between implementations are consistent between single-threaded and multi-threaded benchmarks.
63
+
64
+ ### JRuby
65
+
66
+ Implementation | Increment | Read value | Integer size
67
+ ---------------------|-------------|----------------|--------------
68
+ concurrent-ruby-ext | fastest | fastest | 64-bit
69
+ farce | 1.7x slower | 2.2x slower | 64-bit
70
+ concurrent-ruby | 15x slower | 9x slower | 32-bit
71
+
72
+ Farce uses a JVM-specific Ruby implementation, concurrent-ruby uses the same Mutex-based implementation as on other platforms, and concurrent-ruby-ext comes with a Java implementation of an atomic counter (hence also the difference in integer size). The overhead in Farce can largely be attributed to Ruby dispatch overhead.
73
+
74
+ ### TruffleRuby
75
+
76
+ Implementation | Increment | Read value | Integer size
77
+ ---------------------|-------------|----------------|--------------
78
+ farce | fastest | fastest | 64-bit
79
+ concurrent-ruby | 1.5x slower | 3.5x slower | 32-bit
80
+
81
+ TruffleRuby's performance numbers are not as reliable as other Ruby implementations, and may vary significantly between runs, versions, and whether the GraalVM is in use and has warmed up. Neither farce nor concurrent-ruby use a counter written in C, so they should both be fully optimizable by the GraalVM.
82
+
83
+ ## Lock performance
84
+
85
+ > [!CAUTION]
86
+ > If lock performance is your application's bottleneck, you might want to look into **different data structures**.
87
+ > Farce and concurrent-ruby provide plenty of options.
88
+
89
+ ### CRuby
90
+
91
+ Farce's locks are **between 5% and 10% slower** than `Mutex` for uncontended locks, and stay below a 50% performance penalty for highly contended locks between threads.
92
+
93
+ ### JRuby and TruffleRuby
94
+
95
+ Farce's locks have identical performance to `Mutex` (as they are a subclass of `Mutex`).
96
+
97
+ ## Queue performance
98
+
99
+ In the producer/consumer workload in `benchmark/queue.rb`, Ruby's built-in `Thread::Queue` and `Thread::SizedQueue` remain the fastest, but they do not support ractors.
100
+
101
+ Implementation | Performance | Notes
102
+ -------------------------------|-------------|-------------
103
+ `Thread::Queue` | Fastest | no ractor support
104
+ `Thread::SizedQueue` | 1.4x slower | no ractor support
105
+ `Farce::Strict::Queue` | 1.5x slower | only allows sharable objects
106
+ `Farce::Queue` | 2.1x slower |
107
+ `RactorSafe::Queue` | 2.9x slower | only allows sharable objects
108
+ `Ratomic::Queue` | 9.8x slower | breaks ractor isolation
109
+ `RactorQueue` | 30x slower | breaks ractor isolation
110
+ `Ractor::Port` (multiplexing) | 100x slower |
111
+
112
+ ## Priority queue performance
113
+
114
+ Many gems implement a priority queue or comparable data structure.
115
+ Farce's implementation is the only one that allows cross-ractor communication.
116
+ The below numbers compare non-blocking APIs, as only Farce implements a blocking API as well.
117
+
118
+ <table>
119
+ <thead>
120
+ <tr>
121
+ <th colspan="2"></th>
122
+ <th colspan="2">CRuby</th>
123
+ <th colspan="2">JRuby</th>
124
+ </tr>
125
+ <tr>
126
+ <th>↓ Gem</th>
127
+ <th>Insertion order →</th>
128
+ <th>Random</th>
129
+ <th>Descending</th>
130
+ <th>Random</th>
131
+ <th>Descending</th>
132
+ </tr>
133
+ </thead>
134
+ <tbody>
135
+ <tr>
136
+ <td colspan="2">farce 0.1.0</td>
137
+ <td>fastest</td>
138
+ <td>fastest</td>
139
+ <td>fastest</td>
140
+ <td>fastest</td>
141
+ </tr>
142
+ <tr>
143
+ <td colspan="2"><a href="https://github.com/mame/rbtree">rbtree</a> 0.4.7</td>
144
+ <td>1.1x slower</td>
145
+ <td>1.2x slower</td>
146
+ <td>–</td>
147
+ <td>–</td>
148
+ </tr>
149
+ <tr>
150
+ <td colspan="2"><a href="https://github.com/boborbt/priority_queue_cxx">priority_queue_cxx</a> 0.3.7</td>
151
+ <td>1.7x slower</td>
152
+ <td>1.7x slower</td>
153
+ <td>–</td>
154
+ <td>–</td>
155
+ </tr>
156
+ <tr>
157
+ <td colspan="2"><a href="https://github.com/socketry/io-event">io-event</a> 1.21.1</td>
158
+ <td>2.6x slower</td>
159
+ <td>3.9x slower</td>
160
+ <td>1.3x slower</td>
161
+ <td>1.7x slower</td>
162
+ </tr>
163
+ <tr>
164
+ <td colspan="2"><a href="https://github.com/rubyworks/pqueue">pqueue</a> 2.2.0</td>
165
+ <td>9.5x slower</td>
166
+ <td>8.0x slower</td>
167
+ <td>2.2x slower</td>
168
+ <td>1.9x slower</td>
169
+ </tr>
170
+ <tr>
171
+ <td colspan="2"><a href="https://github.com/matiasbattocchia/lazy-priority-queue">lazy_priority_queue</a> 0.1.1</td>
172
+ <td>9.9x slower</td>
173
+ <td>7.9x slower</td>
174
+ <td>3.9x slower</td>
175
+ <td>3.2x slower</td>
176
+ </tr>
177
+ <tr>
178
+ <td colspan="2"><a href="https://github.com/philiprehberger/rb-priority-queue">philiprehberger-priority_queue</a> 0.5.0</td>
179
+ <td>13x slower</td>
180
+ <td>19x slower</td>
181
+ <td>7.6x slower</td>
182
+ <td>11x slower</td>
183
+ </tr>
184
+ </tbody>
185
+ </table>
@@ -0,0 +1,290 @@
1
+ <!--
2
+ # @title Gem: dry-types
3
+ -->
4
+
5
+ # Farce / [dry-types](https://dry-rb.org/gems/dry-types/)
6
+
7
+ The opt-in dry-types integration validates input and constructs Farce values
8
+ from the result. It is useful when parsed input is headed to concurrent workers
9
+ or Farce-backed application state.
10
+
11
+ Add `dry-types` to your application and include both type imports:
12
+
13
+ ```ruby
14
+ require "dry-types"
15
+ require "farce"
16
+
17
+ module Types
18
+ include Dry.Types()
19
+ include Farce.DryTypes()
20
+ end
21
+ ```
22
+
23
+ `Farce.DryTypes()` follows the preceding `Dry.Types()` import. Root Farce types
24
+ use the corresponding dry default types. Namespaces and aliases gain matching
25
+ Farce constants without replacing existing dry types. Loading Farce by itself
26
+ does not load dry-types.
27
+
28
+ The imported constants construct new Farce objects. Use an instance type to
29
+ check an existing Farce object without conversion:
30
+
31
+ ```ruby
32
+ module Types
33
+ VectorInstance = Instance(Farce::Vector)
34
+ end
35
+
36
+ Types::VectorInstance.try(Farce::Vector.new).success? # => true
37
+ Types::VectorInstance.try([]).failure? # => true
38
+ ```
39
+
40
+ ## Vectors
41
+
42
+ Use `Vector.of` to apply a member type before constructing the vector:
43
+
44
+ ```ruby
45
+ module Types
46
+ IntegerVector = Vector.of(Coercible::Integer)
47
+ end
48
+
49
+ numbers = Types::IntegerVector[["1", 2]]
50
+ numbers.class # => Farce::Vector
51
+ numbers.to_a # => [1, 2]
52
+ numbers.mode # => :copy
53
+ ```
54
+
55
+ The bare `Vector` accepts any Array members. Imported dry namespaces control
56
+ the outer native input in the same way as their Array type:
57
+
58
+ ```ruby
59
+ Types::Vector.try("one").failure? # => true
60
+ Types::Coercible::Vector["one"].to_a # => ["one"]
61
+ ```
62
+
63
+ The resulting values compose with optional types, constraints, `try`, and
64
+ failure blocks:
65
+
66
+ ```ruby
67
+ Types::IntegerVector.optional[nil] # => nil
68
+
69
+ result = Types::IntegerVector.try(["invalid"])
70
+ result.failure? # => true
71
+
72
+ Types::IntegerVector.(["invalid"]) { |partial| [:invalid, partial] }
73
+ # => [:invalid, ["invalid"]]
74
+ ```
75
+
76
+ Member and source coercion complete before Farce construction. Their failure
77
+ blocks receive dry-types' partial native value, never a partially initialized
78
+ Farce collection. Constraints added to a collection type run on its constructed
79
+ Farce result. A size constraint on a Set therefore observes deduplication.
80
+
81
+ dry-types callable defaults return the block result directly. Construct the
82
+ typed value inside the block when each use needs a fresh Farce collection:
83
+
84
+ ```ruby
85
+ module Types
86
+ EmptyIntegerVector = IntegerVector.default { IntegerVector[[]] }
87
+ end
88
+
89
+ Types::EmptyIntegerVector[].class # => Farce::Vector
90
+ Types::EmptyIntegerVector[].empty? # => true
91
+ ```
92
+
93
+ ## Maps and schemas
94
+
95
+ Use `Map.map` for homogeneous key and value types:
96
+
97
+ ```ruby
98
+ module Types
99
+ ScoreMap = Map.map(String, Coercible::Integer)
100
+ end
101
+
102
+ scores = Types::ScoreMap["Ada" => "10", "Grace" => 12]
103
+ scores.class # => Farce::Map
104
+ scores.to_h # => {"Ada" => 10, "Grace" => 12}
105
+ ```
106
+
107
+ dry-types rejects keys that collide after coercion. The integration also
108
+ rejects identity Hash input with structurally equal keys because a structural
109
+ Farce Map could otherwise drop an entry.
110
+
111
+ Use `Map.schema` for fixed keys, defaults, key transforms, and nested types:
112
+
113
+ ```ruby
114
+ module Types
115
+ Batch = Map.schema(
116
+ name: String,
117
+ ids: IntegerVector,
118
+ ).strict
119
+ end
120
+
121
+ batch = Types::Batch[name: "nightly", ids: ["10", 20]]
122
+ batch[:name] # => "nightly"
123
+ batch[:ids].class # => Farce::Vector
124
+ batch[:ids].to_a # => [10, 20]
125
+ ```
126
+
127
+ Schema chaining and `with_key_transform` or `with_type_transform` retain Farce
128
+ construction. A non-strict schema omits unknown keys. Call `.strict` when
129
+ unknown keys should fail.
130
+
131
+ ## Sets
132
+
133
+ `Set.of` applies its member type before membership removes duplicates:
134
+
135
+ ```ruby
136
+ module Types
137
+ IntegerSet = Set.of(Coercible::Integer)
138
+ end
139
+
140
+ values = Types::IntegerSet[["1", 1, "2"]]
141
+ values.class # => Farce::Set
142
+ values.to_a.sort # => [1, 2]
143
+ ```
144
+
145
+ It accepts Arrays and Ruby Sets. The bare `Set` accepts any Array members.
146
+
147
+ ## Counters and flags
148
+
149
+ `Counter` uses the imported dry `Integer` type. `Flag` uses the imported dry
150
+ `Bool` type:
151
+
152
+ ```ruby
153
+ counter = Types::Coercible::Counter["3"]
154
+ counter.class # => Farce::Counter
155
+ counter.value # => 3
156
+
157
+ flag = Types::Params::Flag["yes"]
158
+ flag.class # => Farce::Flag
159
+ flag.value # => true
160
+ ```
161
+
162
+ A namespace only gains a Farce type when it has the corresponding dry type.
163
+ For example, dry-types defines `Coercible::Integer` but no `Coercible::Bool`,
164
+ so `Types::Coercible::Counter` exists while `Types::Coercible::Flag` does not.
165
+
166
+ The dry type validates the initial scalar. Counter and Flag retain their normal
167
+ Farce APIs after construction.
168
+
169
+ ## Atoms
170
+
171
+ The bare `Atom` accepts any initial value. Use `Atom.of` to validate or coerce
172
+ the initial contents:
173
+
174
+ ```ruby
175
+ module Types
176
+ IntegerAtom = Atom.of(Coercible::Integer)
177
+ end
178
+
179
+ atom = Types::IntegerAtom["4"]
180
+ atom.class # => Farce::Atom
181
+ atom.value # => 4
182
+ ```
183
+
184
+ The type applies only at construction. Later writes use the normal Atom API and
185
+ are not revalidated:
186
+
187
+ ```ruby
188
+ atom.value = "later"
189
+ atom.value # => "later"
190
+ ```
191
+
192
+ Nil as Atom contents differs from an optional Atom constructor:
193
+
194
+ ```ruby
195
+ Types::Atom[nil].value # => nil
196
+ Types::Atom.of(Types::Integer.optional)[nil].value # => nil
197
+ Types::Atom.of(Types::Integer).optional[nil] # => nil
198
+ ```
199
+
200
+ The first two expressions construct an Atom containing nil. The last expression
201
+ returns nil without constructing an Atom.
202
+
203
+ ## Dry imports and Farce variants
204
+
205
+ With no dry namespace arguments, `Farce.DryTypes()` inherits the closest
206
+ `Dry.Types()` import. With no preceding import, it uses the same strict defaults
207
+ as `Dry.Types()`. Pass dry namespace arguments, `default:`, and aliases to
208
+ select an independent source using the normal `Dry.Types()` rules:
209
+
210
+ ```ruby
211
+ module CoercingTypes
212
+ include Dry.Types()
213
+ include Farce.DryTypes(:strict, :coercible, default: :coercible)
214
+ end
215
+
216
+ CoercingTypes::Vector["1"].to_a # => ["1"]
217
+ ```
218
+
219
+ The dry namespace controls validation and coercion of native input. `variant:`
220
+ selects the Farce class produced after that succeeds:
221
+
222
+ ```ruby
223
+ module LocalTypes
224
+ include Dry.Types(default: :coercible)
225
+ include Farce.DryTypes(variant: :local, scope: :fiber)
226
+ end
227
+
228
+ vector = LocalTypes::Vector["job"]
229
+ vector.class # => Farce::Local::Vector
230
+ vector.scope # => :fiber
231
+ ```
232
+
233
+ Supported variants are `:shared`, `:strict`, `:unshared`, and `:local`.
234
+ `:shared` is the default and accepts `mode:`. `:local` accepts `scope:`.
235
+ Strict and Unshared variants accept neither option. Farce's `:strict` variant
236
+ and dry-types' `Strict` namespace configure separate parts of the conversion.
237
+
238
+ | `variant:` | Constructed classes |
239
+ | --- | --- |
240
+ | `:shared` | `Farce::Vector`, `Farce::Map`, `Farce::Set`, `Farce::Counter`, `Farce::Flag`, `Farce::Atom` |
241
+ | `:strict` | `Farce::Strict::Vector`, `Farce::Strict::Map`, `Farce::Strict::Set`, `Farce::Strict::Atom` |
242
+ | `:unshared` | `Farce::Unshared::Vector`, `Farce::Unshared::Map`, `Farce::Unshared::Set` |
243
+ | `:local` | `Farce::Local::Vector`, `Farce::Local::Map`, `Farce::Local::Set`, `Farce::Local::Counter`, `Farce::Local::Flag`, `Farce::Local::Atom` |
244
+
245
+ The integration imports only classes that Farce provides for the selected
246
+ variant. Strict has an Atom but no Counter or Flag. Unshared has none of these
247
+ three scalar-backed types.
248
+
249
+ For a single shared collection type, use `.with(mode: ...)`:
250
+
251
+ ```ruby
252
+ module Types
253
+ LocalValueVector = Vector.with(mode: :local)
254
+ end
255
+
256
+ payload = []
257
+ vector = Types::LocalValueVector[[payload]]
258
+ vector[0].equal?(payload) # => true
259
+ ```
260
+
261
+ The supported shared modes are `:copy`, `:local`, `:make_shareable`,
262
+ `:shareable_copy`, and `:raise`. They apply to collections and Atom. Counter and
263
+ Flag have no transfer mode. `:move` is rejected because dry-types creates and
264
+ examines intermediate values during coercion.
265
+
266
+ ## Farce input and ownership
267
+
268
+ Mode-free Strict, Unshared, and Local Farce collections can be converted
269
+ directly. Construction always returns a fresh configured variant.
270
+
271
+ Mode-backed `Farce::Vector`, `Farce::Map`, and `Farce::Set` input is rejected
272
+ before traversal. Materialize one explicitly when reading it is intended:
273
+
274
+ ```ruby
275
+ source = Farce::Vector.new(["1"])
276
+ converted = Types::IntegerVector[source.to_a]
277
+ converted.to_a # => [1]
278
+ ```
279
+
280
+ The explicit read establishes where transfer and ownership happen. This rule
281
+ also applies when the container's default mode is `:copy` because an individual
282
+ entry might have been inserted with `mode: :move`.
283
+
284
+ Vector materialization uses its normal snapshot. Map and set materialization
285
+ uses normal iteration and is not a globally atomic snapshot during concurrent
286
+ mutation. Validation describes the values processed by that call. Later writes
287
+ through the Farce API are not revalidated. Atom input is treated as its payload
288
+ and is never implicitly read from an existing Atom. Mutable values keep the
289
+ guarantees of the selected Farce mode. The dry type descriptor is application
290
+ configuration and is not promised to be Ractor-shareable.
@@ -0,0 +1,70 @@
1
+ <!--
2
+ # @title Gem: MessagePack
3
+ -->
4
+
5
+ # Farce / [MessagePack](https://github.com/msgpack/msgpack-ruby)
6
+
7
+ Use MessagePack to store or send Farce values. Add `msgpack` to your Gemfile
8
+ and load it:
9
+
10
+ ```ruby
11
+ require "msgpack"
12
+ require "farce"
13
+
14
+ jobs = Farce::Vector.new(["build", "test"])
15
+ bytes = jobs.to_msgpack # or: MessagePack.pack(jobs)
16
+ ```
17
+
18
+ Vectors, maps, sets, atoms, counters, and flags support `to_msgpack`, including
19
+ nested values and their Farce variants.
20
+
21
+ ## Restoring Farce objects
22
+
23
+ By default, unpacking returns ordinary Ruby values: arrays for vectors and sets,
24
+ hashes for maps, integers for counters, booleans for flags, and the stored values
25
+ for atoms. This makes the data easy to use outside Farce:
26
+
27
+ ```ruby
28
+ MessagePack.unpack(bytes) # => ["build", "test"]
29
+ ```
30
+
31
+ To restore Farce objects instead, use a factory for both packing and unpacking:
32
+
33
+ ```ruby
34
+ factory = Farce::MessagePack.factory
35
+ copy = factory.load(factory.dump(jobs))
36
+ copy.class # => Farce::Vector
37
+ copy.to_a # => ["build", "test"]
38
+ ```
39
+
40
+ The factory also restores nested Farce objects. It does not change
41
+ `MessagePack.pack` or `to_msgpack`. Restored objects contain the current values,
42
+ and counters retain their initial value for `reset`. Other settings, such as
43
+ transfer modes and local scopes, use constructor defaults unless configured below.
44
+
45
+ ## Custom factories
46
+
47
+ Choose extension IDs to fit your application's protocol:
48
+
49
+ ```ruby
50
+ factory = Farce::MessagePack.factory(types: {
51
+ Farce::Vector => 40,
52
+ Farce::Counter => 41
53
+ })
54
+ ```
55
+
56
+ `types:` replaces the default registrations, which use IDs 0 through 5 for
57
+ Vector, Map, Counter, Flag, Atom, and Set, respectively. Both ends must use the
58
+ same registrations. Register variants explicitly to restore their specific classes.
59
+
60
+ You can also add Farce types to an existing MessagePack factory and supply
61
+ constructor options for restored objects:
62
+
63
+ ```ruby
64
+ factory = MessagePack::Factory.new
65
+ Farce::MessagePack.register_type(factory, 60, Farce::Vector, mode: :make_shareable)
66
+ Farce::MessagePack.register_type(factory, 61, Farce::Local::Counter, scope: :fiber)
67
+ ```
68
+
69
+ Use unused IDs from 0 through 127. Nested values use the same factory, including
70
+ your application's other registered types.
@@ -0,0 +1,63 @@
1
+ <!--
2
+ # @title Gem: ractor-shim
3
+ -->
4
+
5
+ # Farce / [ractor-shim](https://github.com/eregon/ractor-shim)
6
+
7
+ > [!NOTE]
8
+ > This documentation is up to date for **Farce 0.1.0** and **ractor-shim 0.1.1**.
9
+
10
+ Both Farce and [ractor-shim](https://github.com/eregon/ractor-shim) provide shims for `Ractor` and `Ractor::Port` on platforms that don't fully support them. Farce namespaces these inside the `Farce` module, while ractor-shim installs these classes at top-level (where any shim-unaware code would automatically pick them up).
11
+
12
+ Farce ignores the shims provided by ractor-shim. Both gems can safely coexist in the same application.
13
+
14
+ ## Similarities
15
+
16
+ * Both of them will use `Thread` and `Queue` under the hood if Ractors are not available.
17
+ * Both implement most of the public Ractor API.
18
+ * On Ruby implementations not supporting Ractors they both treat all objects as shareable. `Ractor.make_shareable` will not deep-freeze objects, and `Ractor.shareable?` will always return true.
19
+
20
+ ## Implementation differences
21
+
22
+ The Ruby requirements for ractor-shim are much broader than for Farce, supporting Ruby 2.7 and later, while Farce requires Ruby 3.4 or newer. Farce is also significantly larger and more complex than ractor-shim. Its primary purpose isn't to provide a shim, but to provide tooling around Ractors and Fiber schedulers. So if all you need is a simple shim, ractor-shim is likely a better choice.
23
+
24
+ However, having these tools at its disposal allows Farce to provide a more complete and in some cases more performant solution.
25
+
26
+ ### Things Farce implements that ractor-shim does not
27
+
28
+ Farce supports ractors having multiple threads. The following snippet will work fine with Farce (after `include Farce`), but will raise an exception with ractor-shim on Ruby 2.x, TruffleRuby, and JRuby:
29
+
30
+ ```ruby
31
+ Ractor.new do
32
+ Thread.new { p Ractor.current }.join
33
+ end.join
34
+ ```
35
+
36
+ The `Ractor.store_if_absent` method provided by ractor-shim may not be thread-safe.
37
+
38
+ `Ractor.shareable_proc` and `Ractor.shareable_lambda` are not properly implemented in ractor-shim. They do not accept a `self` option and will not rebind the passed block. In addition, `shareable_lambda` does not actually produce lambdas on Ruby 3.
39
+
40
+ ### Things Farce implements more efficiently
41
+
42
+ * `Ractor.select` on ractor-shim uses busy waiting if native Ractors are not available. Farce uses better synchronization mechanisms to properly avoid busy waiting. Moreover, ractor-shim wraps the select logic in a global mutex, meaning only one `Ractor.select` can be active at any time. Farce does not have this limitation.
43
+ * The `Ractor::Port` shim provided by ractor-shim always creates a new Ractor for each port. Farce only does so if absolutely necessary (on Ruby 3.4, if sending unshareable objects over a non-default port).
44
+
45
+ On Ruby 3.4, the following code will create one Ractor if using Farce, but 6 Ractors if using ractor-shim:
46
+
47
+ ```ruby
48
+ ractor = Ractor.new do
49
+ counter = 0
50
+ while port = receive
51
+ counter += 1
52
+ port.send(counter)
53
+ end
54
+ end
55
+
56
+ 5.times do
57
+ port = Ractor::Port.new
58
+ ractor.send(port)
59
+ puts "Count is: #{port.receive}"
60
+ ensure
61
+ port.close
62
+ end
63
+ ```