farce 0.0.1.alpha2-x86_64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +26 -0
  3. data/CONTRIBUTING.md +71 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1524 -0
  6. data/SECURITY.md +10 -0
  7. data/docs/benchmarks.md +185 -0
  8. data/docs/gems/dry-types.md +290 -0
  9. data/docs/gems/msgpack.md +70 -0
  10. data/docs/gems/ractor-shim.md +63 -0
  11. data/docs/modes.md +628 -0
  12. data/docs/scopes.md +649 -0
  13. data/docs/variants.md +346 -0
  14. data/ext/ext_helper.rb +20 -0
  15. data/ext/farce/README.md +21 -0
  16. data/ext/farce/atom.c +1023 -0
  17. data/ext/farce/bounded_map.c +1683 -0
  18. data/ext/farce/containers.h +77 -0
  19. data/ext/farce/counter.c +399 -0
  20. data/ext/farce/darwin.c +100 -0
  21. data/ext/farce/depend +12 -0
  22. data/ext/farce/dict.c +1523 -0
  23. data/ext/farce/dict.h +152 -0
  24. data/ext/farce/drivers.c +237 -0
  25. data/ext/farce/exchanger.c +299 -0
  26. data/ext/farce/extconf.rb +99 -0
  27. data/ext/farce/farce.c +359 -0
  28. data/ext/farce/flag.c +288 -0
  29. data/ext/farce/io.c +338 -0
  30. data/ext/farce/lock.c +510 -0
  31. data/ext/farce/map.c +2240 -0
  32. data/ext/farce/priority_queue.c +2056 -0
  33. data/ext/farce/queue.c +1059 -0
  34. data/ext/farce/reactor.c +820 -0
  35. data/ext/farce/reactor.h +103 -0
  36. data/ext/farce/shareable.h +31 -0
  37. data/ext/farce/signal.c +350 -0
  38. data/ext/farce/transaction.c +354 -0
  39. data/ext/farce/transaction.h +40 -0
  40. data/ext/farce/tree_map.c +1953 -0
  41. data/ext/farce/trie.c +2020 -0
  42. data/ext/farce/unshareable.c +155 -0
  43. data/ext/farce/unshared_io_pool.h +234 -0
  44. data/ext/farce/unshared_signal.c +263 -0
  45. data/ext/farce/unshared_wait.h +193 -0
  46. data/ext/farce/unsupported.c +6 -0
  47. data/ext/farce/vector.c +1195 -0
  48. data/ext/farce/weak_map.c +1714 -0
  49. data/ext/java/org/farce/BoundedMap.java +394 -0
  50. data/ext/java/org/farce/FiberScheduler.java +141 -0
  51. data/ext/java/org/farce/PriorityKey.java +45 -0
  52. data/ext/java/org/farce/PriorityQueue.java +373 -0
  53. data/ext/java/org/farce/QueueSignal.java +28 -0
  54. data/ext/rebind/README.md +14 -0
  55. data/ext/rebind/extconf.rb +10 -0
  56. data/ext/rebind/rebind.c +186 -0
  57. data/lib/farce/_yard/internal.rb +13 -0
  58. data/lib/farce/_yard/macros.rb +61 -0
  59. data/lib/farce/_yard/ractor.rb +46 -0
  60. data/lib/farce/abstract/atom.rb +186 -0
  61. data/lib/farce/abstract/bounded_map.rb +232 -0
  62. data/lib/farce/abstract/collection.rb +151 -0
  63. data/lib/farce/abstract/concurrent_map.rb +381 -0
  64. data/lib/farce/abstract/counter.rb +193 -0
  65. data/lib/farce/abstract/duplicable_map.rb +229 -0
  66. data/lib/farce/abstract/exchanger.rb +26 -0
  67. data/lib/farce/abstract/flag.rb +71 -0
  68. data/lib/farce/abstract/lazy.rb +115 -0
  69. data/lib/farce/abstract/lease.rb +104 -0
  70. data/lib/farce/abstract/lease_map.rb +261 -0
  71. data/lib/farce/abstract/lease_pool.rb +91 -0
  72. data/lib/farce/abstract/lfu_map.rb +20 -0
  73. data/lib/farce/abstract/lru_map.rb +25 -0
  74. data/lib/farce/abstract/map.rb +345 -0
  75. data/lib/farce/abstract/molecule.rb +245 -0
  76. data/lib/farce/abstract/port.rb +74 -0
  77. data/lib/farce/abstract/priority_queue.rb +117 -0
  78. data/lib/farce/abstract/queue.rb +269 -0
  79. data/lib/farce/abstract/scheduler.rb +111 -0
  80. data/lib/farce/abstract/set.rb +910 -0
  81. data/lib/farce/abstract/sorted_set.rb +172 -0
  82. data/lib/farce/abstract/timer_queue.rb +136 -0
  83. data/lib/farce/abstract/tree_map.rb +269 -0
  84. data/lib/farce/abstract/value.rb +68 -0
  85. data/lib/farce/abstract/vector.rb +1126 -0
  86. data/lib/farce/abstract/weak_atom.rb +32 -0
  87. data/lib/farce/abstract/weak_key_map.rb +12 -0
  88. data/lib/farce/abstract/weak_map.rb +13 -0
  89. data/lib/farce/abstract/weak_set.rb +12 -0
  90. data/lib/farce/abstract/weak_value_map.rb +12 -0
  91. data/lib/farce/abstract.rb +17 -0
  92. data/lib/farce/atom.rb +293 -0
  93. data/lib/farce/class_mirror.rb +87 -0
  94. data/lib/farce/clock.rb +121 -0
  95. data/lib/farce/config.rb +229 -0
  96. data/lib/farce/counter.rb +71 -0
  97. data/lib/farce/deduper.rb +122 -0
  98. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  99. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  101. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  102. data/lib/farce/engine/jruby/map.rb +505 -0
  103. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  104. data/lib/farce/engine/jruby/signal.rb +147 -0
  105. data/lib/farce/engine/jruby.rb +63 -0
  106. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  107. data/lib/farce/engine/jvm/counter.rb +102 -0
  108. data/lib/farce/engine/jvm/extension.rb +32 -0
  109. data/lib/farce/engine/jvm/farce.jar +0 -0
  110. data/lib/farce/engine/jvm/flag.rb +79 -0
  111. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  112. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  113. data/lib/farce/engine/jvm/types.rb +180 -0
  114. data/lib/farce/engine/jvm.rb +19 -0
  115. data/lib/farce/engine/ruby/3.4/farce.so +0 -0
  116. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  117. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  118. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  119. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  120. data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
  121. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  122. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  123. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  124. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  125. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  126. data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
  127. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  128. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  129. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  130. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  131. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  132. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  133. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  134. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  135. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  136. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  137. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  138. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  139. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  140. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  141. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  142. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  143. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  144. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  145. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  146. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  147. data/lib/farce/engine/ruby.rb +130 -0
  148. data/lib/farce/engine/shared/atom.rb +10 -0
  149. data/lib/farce/engine/shared/exchanger.rb +130 -0
  150. data/lib/farce/engine/shared/identity_key.rb +22 -0
  151. data/lib/farce/engine/shared/lease.rb +10 -0
  152. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  153. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  154. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  155. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  156. data/lib/farce/engine/shared/port.rb +44 -0
  157. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  158. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  159. data/lib/farce/engine/shared/queue.rb +233 -0
  160. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  161. data/lib/farce/engine/shared/rebindable.rb +15 -0
  162. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  163. data/lib/farce/engine/shared/strict_map.rb +117 -0
  164. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  165. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  166. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  167. data/lib/farce/engine/shared/trie.rb +317 -0
  168. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  169. data/lib/farce/engine/shared/unshareable.rb +14 -0
  170. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  171. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  172. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  173. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  174. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  175. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  176. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  177. data/lib/farce/engine/shared/vault.rb +31 -0
  178. data/lib/farce/engine/shared/vector.rb +83 -0
  179. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  180. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  181. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  182. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  183. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  184. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  185. data/lib/farce/engine/shared.rb +63 -0
  186. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  187. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  188. data/lib/farce/engine/truffleruby/map.rb +656 -0
  189. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  190. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  191. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  192. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  193. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  194. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  195. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  196. data/lib/farce/engine/truffleruby.rb +148 -0
  197. data/lib/farce/envelope.rb +335 -0
  198. data/lib/farce/error.rb +35 -0
  199. data/lib/farce/exchanger.rb +41 -0
  200. data/lib/farce/flag.rb +27 -0
  201. data/lib/farce/integrations/active_support/blank.rb +68 -0
  202. data/lib/farce/integrations/active_support/clock.rb +17 -0
  203. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  204. data/lib/farce/integrations/active_support/map.rb +175 -0
  205. data/lib/farce/integrations/active_support/set.rb +60 -0
  206. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  207. data/lib/farce/integrations/active_support/vector.rb +231 -0
  208. data/lib/farce/integrations/active_support.rb +9 -0
  209. data/lib/farce/integrations/activesupport.rb +5 -0
  210. data/lib/farce/integrations/bson.rb +108 -0
  211. data/lib/farce/integrations/cbor.rb +51 -0
  212. data/lib/farce/integrations/concurrent.rb +112 -0
  213. data/lib/farce/integrations/dry-types.rb +5 -0
  214. data/lib/farce/integrations/dry_types.rb +694 -0
  215. data/lib/farce/integrations/json.rb +7 -0
  216. data/lib/farce/integrations/msgpack.rb +112 -0
  217. data/lib/farce/integrations/oj.rb +69 -0
  218. data/lib/farce/integrations/psych.rb +191 -0
  219. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  220. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  221. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  222. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  223. data/lib/farce/integrations/shared/to_json.rb +42 -0
  224. data/lib/farce/integrations/sorted_set.rb +11 -0
  225. data/lib/farce/integrations/weakref.rb +38 -0
  226. data/lib/farce/integrations/yajl.rb +10 -0
  227. data/lib/farce/integrations.rb +156 -0
  228. data/lib/farce/internal/_frozen_config.rb +11 -0
  229. data/lib/farce/internal/autoloads.rb +47 -0
  230. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  231. data/lib/farce/internal/converter.rb +106 -0
  232. data/lib/farce/internal/copyable.rb +31 -0
  233. data/lib/farce/internal/delegation.rb +20 -0
  234. data/lib/farce/internal/external_transaction.rb +59 -0
  235. data/lib/farce/internal/fake_ractor.rb +179 -0
  236. data/lib/farce/internal/freeze.rb +118 -0
  237. data/lib/farce/internal/inspect.rb +157 -0
  238. data/lib/farce/internal/key_lock_map.rb +29 -0
  239. data/lib/farce/internal/key_normalizer.rb +289 -0
  240. data/lib/farce/internal/lease_initialization.rb +115 -0
  241. data/lib/farce/internal/lease_map.rb +441 -0
  242. data/lib/farce/internal/lease_pool_state.rb +228 -0
  243. data/lib/farce/internal/lease_state.rb +342 -0
  244. data/lib/farce/internal/lease_waiting.rb +13 -0
  245. data/lib/farce/internal/managed_queue.rb +26 -0
  246. data/lib/farce/internal/map_value_modes.rb +227 -0
  247. data/lib/farce/internal/marshal_support.rb +227 -0
  248. data/lib/farce/internal/mixin.rb +20 -0
  249. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  250. data/lib/farce/internal/noncopyable.rb +17 -0
  251. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  252. data/lib/farce/internal/pool_supervisor.rb +41 -0
  253. data/lib/farce/internal/pool_worker.rb +61 -0
  254. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  255. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  256. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  257. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  258. data/lib/farce/internal/portable_transaction.rb +164 -0
  259. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  260. data/lib/farce/internal/reservation_waiting.rb +24 -0
  261. data/lib/farce/internal/scheduled_task.rb +48 -0
  262. data/lib/farce/internal/scheduler_io.rb +171 -0
  263. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  264. data/lib/farce/internal/select_scheduler.rb +235 -0
  265. data/lib/farce/internal/storage.rb +162 -0
  266. data/lib/farce/internal/strict_lease.rb +30 -0
  267. data/lib/farce/internal/strict_lease_map.rb +20 -0
  268. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  269. data/lib/farce/internal/thread_pool.rb +166 -0
  270. data/lib/farce/internal/transaction_conflict.rb +9 -0
  271. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  272. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  273. data/lib/farce/internal/undefined.rb +22 -0
  274. data/lib/farce/internal/unshared_lease.rb +29 -0
  275. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  276. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  277. data/lib/farce/internal/value_serialization.rb +13 -0
  278. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  279. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  280. data/lib/farce/internal.rb +129 -0
  281. data/lib/farce/lazy.rb +100 -0
  282. data/lib/farce/lazy_ref.rb +40 -0
  283. data/lib/farce/lease.rb +28 -0
  284. data/lib/farce/lease_map.rb +34 -0
  285. data/lib/farce/lease_pool.rb +29 -0
  286. data/lib/farce/lfu_map.rb +53 -0
  287. data/lib/farce/local/atom.rb +23 -0
  288. data/lib/farce/local/counter.rb +88 -0
  289. data/lib/farce/local/flag.rb +65 -0
  290. data/lib/farce/local/lazy.rb +38 -0
  291. data/lib/farce/local/lazy_ref.rb +36 -0
  292. data/lib/farce/local/lease.rb +77 -0
  293. data/lib/farce/local/lease_map.rb +80 -0
  294. data/lib/farce/local/lease_pool.rb +38 -0
  295. data/lib/farce/local/lfu_map.rb +55 -0
  296. data/lib/farce/local/lru_map.rb +62 -0
  297. data/lib/farce/local/map.rb +47 -0
  298. data/lib/farce/local/molecule.rb +45 -0
  299. data/lib/farce/local/priority_queue.rb +53 -0
  300. data/lib/farce/local/queue.rb +32 -0
  301. data/lib/farce/local/scoped.rb +166 -0
  302. data/lib/farce/local/set.rb +18 -0
  303. data/lib/farce/local/sorted_set.rb +50 -0
  304. data/lib/farce/local/timer_queue.rb +41 -0
  305. data/lib/farce/local/tree_map.rb +47 -0
  306. data/lib/farce/local/vector.rb +30 -0
  307. data/lib/farce/local/weak_atom.rb +23 -0
  308. data/lib/farce/local/weak_key_map.rb +39 -0
  309. data/lib/farce/local/weak_map.rb +39 -0
  310. data/lib/farce/local/weak_set.rb +18 -0
  311. data/lib/farce/local/weak_value_map.rb +39 -0
  312. data/lib/farce/local.rb +35 -0
  313. data/lib/farce/lock.rb +54 -0
  314. data/lib/farce/lru_map.rb +63 -0
  315. data/lib/farce/map.rb +58 -0
  316. data/lib/farce/mode_manager.rb +142 -0
  317. data/lib/farce/molecule.rb +60 -0
  318. data/lib/farce/mutable.rb +171 -0
  319. data/lib/farce/pool.rb +332 -0
  320. data/lib/farce/port.rb +134 -0
  321. data/lib/farce/priority_queue.rb +70 -0
  322. data/lib/farce/proxy/register.rb +101 -0
  323. data/lib/farce/proxy/supervisor.rb +137 -0
  324. data/lib/farce/proxy/wrapper.rb +49 -0
  325. data/lib/farce/proxy.rb +291 -0
  326. data/lib/farce/queue.rb +60 -0
  327. data/lib/farce/ractor.rb +269 -0
  328. data/lib/farce/read_write_lock.rb +256 -0
  329. data/lib/farce/reference.rb +158 -0
  330. data/lib/farce/resolv/dns.rb +42 -0
  331. data/lib/farce/resolv.rb +85 -0
  332. data/lib/farce/scheduler.rb +536 -0
  333. data/lib/farce/set.rb +39 -0
  334. data/lib/farce/shareable.rb +150 -0
  335. data/lib/farce/signal.rb +97 -0
  336. data/lib/farce/sorted_set.rb +36 -0
  337. data/lib/farce/strict/atom.rb +34 -0
  338. data/lib/farce/strict/counter.rb +10 -0
  339. data/lib/farce/strict/exchanger.rb +25 -0
  340. data/lib/farce/strict/flag.rb +10 -0
  341. data/lib/farce/strict/lazy.rb +26 -0
  342. data/lib/farce/strict/lazy_ref.rb +26 -0
  343. data/lib/farce/strict/lease.rb +27 -0
  344. data/lib/farce/strict/lease_map.rb +33 -0
  345. data/lib/farce/strict/lease_pool.rb +28 -0
  346. data/lib/farce/strict/lfu_map.rb +27 -0
  347. data/lib/farce/strict/lru_map.rb +28 -0
  348. data/lib/farce/strict/map.rb +54 -0
  349. data/lib/farce/strict/molecule.rb +16 -0
  350. data/lib/farce/strict/port.rb +40 -0
  351. data/lib/farce/strict/priority_queue.rb +20 -0
  352. data/lib/farce/strict/queue.rb +17 -0
  353. data/lib/farce/strict/set.rb +14 -0
  354. data/lib/farce/strict/sorted_set.rb +19 -0
  355. data/lib/farce/strict/timer_queue.rb +13 -0
  356. data/lib/farce/strict/tree_map.rb +27 -0
  357. data/lib/farce/strict/vector.rb +24 -0
  358. data/lib/farce/strict/weak_atom.rb +31 -0
  359. data/lib/farce/strict/weak_key_map.rb +49 -0
  360. data/lib/farce/strict/weak_map.rb +49 -0
  361. data/lib/farce/strict/weak_set.rb +14 -0
  362. data/lib/farce/strict/weak_value_map.rb +48 -0
  363. data/lib/farce/strict.rb +28 -0
  364. data/lib/farce/system.rb +40 -0
  365. data/lib/farce/thread_scheduler.rb +70 -0
  366. data/lib/farce/timer_queue.rb +66 -0
  367. data/lib/farce/transaction/atom.rb +73 -0
  368. data/lib/farce/transaction/map.rb +25 -0
  369. data/lib/farce/transaction/map_operations.rb +143 -0
  370. data/lib/farce/transaction/molecule.rb +90 -0
  371. data/lib/farce/transaction/mutable.rb +61 -0
  372. data/lib/farce/transaction/set.rb +17 -0
  373. data/lib/farce/transaction/set_operations.rb +48 -0
  374. data/lib/farce/transaction/sorted_set.rb +18 -0
  375. data/lib/farce/transaction/tree_map.rb +78 -0
  376. data/lib/farce/transaction/vector.rb +139 -0
  377. data/lib/farce/transaction/wrapper.rb +202 -0
  378. data/lib/farce/transaction.rb +343 -0
  379. data/lib/farce/tree_map.rb +56 -0
  380. data/lib/farce/unsafe/lfu_map.rb +36 -0
  381. data/lib/farce/unsafe/lru_map.rb +36 -0
  382. data/lib/farce/unsafe/tree_map.rb +21 -0
  383. data/lib/farce/unsafe.rb +29 -0
  384. data/lib/farce/unshareable.rb +67 -0
  385. data/lib/farce/unshared/atom.rb +24 -0
  386. data/lib/farce/unshared/counter.rb +10 -0
  387. data/lib/farce/unshared/flag.rb +10 -0
  388. data/lib/farce/unshared/lazy.rb +38 -0
  389. data/lib/farce/unshared/lazy_ref.rb +26 -0
  390. data/lib/farce/unshared/lease.rb +27 -0
  391. data/lib/farce/unshared/lease_map.rb +26 -0
  392. data/lib/farce/unshared/lease_pool.rb +25 -0
  393. data/lib/farce/unshared/lfu_map.rb +20 -0
  394. data/lib/farce/unshared/lru_map.rb +20 -0
  395. data/lib/farce/unshared/map.rb +49 -0
  396. data/lib/farce/unshared/molecule.rb +16 -0
  397. data/lib/farce/unshared/priority_queue.rb +16 -0
  398. data/lib/farce/unshared/queue.rb +27 -0
  399. data/lib/farce/unshared/set.rb +14 -0
  400. data/lib/farce/unshared/sorted_set.rb +28 -0
  401. data/lib/farce/unshared/timer_queue.rb +16 -0
  402. data/lib/farce/unshared/tree_map.rb +21 -0
  403. data/lib/farce/unshared/vector.rb +19 -0
  404. data/lib/farce/unshared/weak_atom.rb +31 -0
  405. data/lib/farce/unshared/weak_key_map.rb +44 -0
  406. data/lib/farce/unshared/weak_map.rb +44 -0
  407. data/lib/farce/unshared/weak_set.rb +14 -0
  408. data/lib/farce/unshared/weak_value_map.rb +43 -0
  409. data/lib/farce/unshared.rb +28 -0
  410. data/lib/farce/vector.rb +228 -0
  411. data/lib/farce/version.rb +8 -0
  412. data/lib/farce/walker/definitions.rb +186 -0
  413. data/lib/farce/walker/modification.rb +355 -0
  414. data/lib/farce/walker.rb +319 -0
  415. data/lib/farce/weak_atom.rb +121 -0
  416. data/lib/farce/weak_key_map.rb +31 -0
  417. data/lib/farce/weak_map.rb +33 -0
  418. data/lib/farce/weak_ref.rb +67 -0
  419. data/lib/farce/weak_set.rb +82 -0
  420. data/lib/farce/weak_value.rb +195 -0
  421. data/lib/farce/weak_value_map.rb +32 -0
  422. data/lib/farce.rb +519 -0
  423. metadata +468 -0
@@ -0,0 +1,694 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # @!group Dry Types Integration
6
+ require "farce"
7
+ require "dry/types"
8
+
9
+ module Farce
10
+ module Internal # :nodoc: all
11
+ # Implements the optional dry-types collection import.
12
+ module DryTypes
13
+ # Farce output configuration shared by the imported collection types.
14
+ class Configuration
15
+ VARIANTS = {
16
+ shared: Farce,
17
+ strict: Farce::Strict,
18
+ unshared: Farce::Unshared,
19
+ local: Farce::Local,
20
+ }.freeze
21
+ private_constant :VARIANTS
22
+
23
+ # The Farce collection family produced by the imported types.
24
+ # @return [Symbol] :shared, :strict, :unshared, or :local.
25
+ # @api private
26
+ attr_reader :variant
27
+
28
+ # The transfer mode for shared collections.
29
+ # @return [Symbol, Object] The selected mode or Farce's undefined sentinel.
30
+ # @api private
31
+ attr_reader :mode
32
+
33
+ # The storage scope for local collections.
34
+ # @return [Symbol, Object] The selected scope or Farce's undefined sentinel.
35
+ # @api private
36
+ attr_reader :scope
37
+
38
+ # Create validated Farce output configuration.
39
+ # @param variant [Symbol] The Farce collection family to construct.
40
+ # @param mode [Symbol, Object] The shared transfer mode or the undefined sentinel.
41
+ # @param scope [Symbol, Object] The local storage scope or the undefined sentinel.
42
+ # @return [Configuration] The frozen configuration.
43
+ # @api private
44
+ def initialize(variant:, mode: UNDEFINED, scope: UNDEFINED)
45
+ @variant = variant
46
+ @mode = mode
47
+ @scope = scope
48
+ validate!
49
+ freeze
50
+ end
51
+
52
+ # Resolve the configured Farce collection class.
53
+ # @param kind [Symbol] The lowercase Farce type name.
54
+ # @return [Class] The Farce class for the configured variant.
55
+ # @api private
56
+ def target(kind) = VARIANTS.fetch(variant).const_get(kind.to_s.capitalize, false)
57
+
58
+ # Report whether the configured Farce family defines a public type.
59
+ # @param kind [Symbol] The Farce type name in lowercase.
60
+ # @return [Boolean] Whether the variant supports that type.
61
+ # @api private
62
+ def target?(kind) = VARIANTS.fetch(variant).const_defined?(kind.to_s.capitalize, false)
63
+
64
+ # Return keywords accepted by the configured Farce constructor.
65
+ # @param kind [Symbol] The Farce value kind being constructed.
66
+ # @return [Hash] The mode or scope keywords for construction.
67
+ # @api private
68
+ def constructor_options(kind)
69
+ case variant
70
+ when :shared
71
+ return {} unless %i[vector map set atom].include?(kind)
72
+
73
+ { mode: UNDEFINED.equal?(mode) ? :copy : mode }
74
+ when :local then { scope: UNDEFINED.equal?(scope) ? :ractor : scope }
75
+ else {}
76
+ end
77
+ end
78
+
79
+ # Copy the configuration with output options replaced.
80
+ # @param kind [Symbol] The Farce value kind being configured.
81
+ # @param mode [Symbol, Object] The shared transfer mode or the undefined sentinel.
82
+ # @param scope [Symbol, Object] The local storage scope or the undefined sentinel.
83
+ # @return [Configuration] A validated configuration.
84
+ # @api private
85
+ def with(kind:, mode: UNDEFINED, scope: UNDEFINED)
86
+ if %i[counter flag].include?(kind) && !UNDEFINED.equal?(mode)
87
+ raise ArgumentError, "mode is not supported by Farce::#{kind.to_s.capitalize}"
88
+ end
89
+
90
+ mode = @mode if UNDEFINED.equal?(mode)
91
+ scope = @scope if UNDEFINED.equal?(scope)
92
+ self.class.new(variant:, mode:, scope:)
93
+ end
94
+
95
+ private
96
+
97
+ def validate!
98
+ unless %i[shared strict unshared local].include?(variant)
99
+ raise ArgumentError, "unknown Farce collection variant: #{variant.inspect}"
100
+ end
101
+
102
+ if variant == :shared
103
+ raise ArgumentError, "scope is only supported by the local variant" unless UNDEFINED.equal?(scope)
104
+ raise ArgumentError, "mode :move is not supported by dry-types constructors" if mode == :move
105
+ return if UNDEFINED.equal?(mode) || %i[copy local make_shareable raise shareable_copy].include?(mode)
106
+
107
+ raise ArgumentError, "invalid mode: #{mode.inspect}"
108
+ end
109
+
110
+ raise ArgumentError, "mode is only supported by the shared variant" unless UNDEFINED.equal?(mode)
111
+ if variant == :local
112
+ selected_scope = UNDEFINED.equal?(scope) ? :ractor : scope
113
+ unless Farce::SCOPES.include?(selected_scope)
114
+ raise ArgumentError, "invalid scope: #{selected_scope.inspect}"
115
+ end
116
+ return
117
+ end
118
+ return if UNDEFINED.equal?(scope)
119
+
120
+ raise ArgumentError, "scope is only supported by the local variant"
121
+ end
122
+ end
123
+
124
+ # A regular dry type that constructs a Farce value.
125
+ #
126
+ # @!method [](input = Dry::Types::Undefined)
127
+ # Apply this type using dry-types bracket syntax.
128
+ # @param input [Object] The input value.
129
+ # @yield [partial] Handle a coercion or construction failure.
130
+ # @yieldparam partial [Object] The partial value supplied by dry-types.
131
+ # @yieldreturn [Object] The fallback returned instead of a Farce value.
132
+ # @return [Object, nil] The Farce value, nil for an optional type, or the failure block result.
133
+ #
134
+ # @!method ===(input)
135
+ # Test whether input can produce a valid Farce value.
136
+ # @param input [Object] The value to test.
137
+ # @return [Boolean] Whether applying the type succeeds.
138
+ class CollectionType
139
+ include ::Dry::Types::Type
140
+ include ::Dry::Types::Builder
141
+
142
+ # The dry type evaluated before Farce construction.
143
+ # @return [Dry::Types::Type] The source type.
144
+ attr_reader :source
145
+
146
+ # The Farce value kind produced by this type.
147
+ # @return [Symbol] The lowercase Farce type name.
148
+ # @api private
149
+ attr_reader :kind
150
+
151
+ # The Farce output configuration.
152
+ # @return [Configuration] The variant and ownership settings.
153
+ # @api private
154
+ attr_reader :configuration
155
+
156
+ # Wrap a dry type with Farce construction.
157
+ # @param source [Dry::Types::Type] The source type.
158
+ # @param kind [Symbol] The lowercase Farce type name.
159
+ # @param configuration [Configuration] The Farce output configuration.
160
+ # @return [CollectionType] The configured dry type.
161
+ # @api private
162
+ def initialize(source, kind:, configuration:)
163
+ @source = source
164
+ @kind = kind
165
+ @configuration = configuration
166
+ @type = DryTypes.build_type(source, kind, configuration)
167
+ freeze
168
+ end
169
+
170
+ # Apply validation, coercion, and Farce construction to input.
171
+ # @param input [Object] The input value.
172
+ # @yield [partial] Handle a coercion or construction failure.
173
+ # @yieldparam partial [Object] The partial value supplied by dry-types.
174
+ # @yieldreturn [Object] The fallback returned instead of a Farce value.
175
+ # @return [Object, nil] The Farce value, nil for an optional type, or the failure block result.
176
+ def call(input = ::Dry::Types::Undefined, &) = @type.call(input, &)
177
+ alias [] call
178
+
179
+ # Apply the wrapped constructor without a failure callback.
180
+ # @param input [Object] The value to process.
181
+ # @return [Object, nil] The Farce value or nil for an optional type.
182
+ # @api private
183
+ def call_unsafe(input) = @type.call_unsafe(input)
184
+
185
+ # Apply the wrapped constructor with dry-types safe-call behavior.
186
+ # @param input [Object] The value to process.
187
+ # @yield [partial] Handle a coercion or construction failure.
188
+ # @yieldparam partial [Object] The partial value supplied by dry-types.
189
+ # @yieldreturn [Object] The fallback result.
190
+ # @return [Object, nil] The Farce value, nil for an optional type, or the failure block result.
191
+ # @api private
192
+ def call_safe(input, &) = @type.call_safe(input, &)
193
+
194
+ # Try to construct a Farce value and return a dry-types result.
195
+ # @param input [Object] The value to process.
196
+ # @yield [failure] Handle a failed attempt.
197
+ # @yieldparam failure [Dry::Types::Result::Failure] The failure result.
198
+ # @yieldreturn [Object] The fallback result.
199
+ # @return [Dry::Types::Result, Object] The result or failure block value.
200
+ def try(input, &) = @type.try(input, &)
201
+
202
+ # Test whether input can produce a valid Farce value.
203
+ # @param input [Object] The value to test.
204
+ # @return [Boolean] Whether applying the type succeeds.
205
+ def valid?(input = ::Dry::Types::Undefined) = @type.valid?(input)
206
+ alias === valid?
207
+
208
+ # Return the output primitive used by a non-optional type.
209
+ # @return [Class] The configured Farce collection class.
210
+ # @api private
211
+ def primitive = @type.primitive
212
+
213
+ # Test whether a value is accepted by the output type.
214
+ # @param input [Object] The value to test.
215
+ # @return [Boolean] Whether the value is a configured Farce object or accepted nil.
216
+ def primitive?(input) = @type.primitive?(input)
217
+
218
+ # Return the inherited namespace for a non-optional source type.
219
+ # @return [String, nil] The source namespace when one is configured.
220
+ # @api private
221
+ def namespace = @type.namespace
222
+
223
+ # Return the output type name.
224
+ # @return [String] The Farce class or optional union name.
225
+ def name = @type.name
226
+
227
+ # Report whether this is a default type.
228
+ # @return [Boolean] Whether a default is configured.
229
+ def default? = @type.default?
230
+
231
+ # Report whether this type contains constraints.
232
+ # @return [Boolean] Whether constraints are present.
233
+ def constrained? = @type.constrained?
234
+
235
+ # Report whether this type accepts nil.
236
+ # @return [Boolean] Whether the type is optional.
237
+ def optional? = @type.optional?
238
+
239
+ # Build a successful dry-types result.
240
+ # @param input [Object] The successful value.
241
+ # @return [Dry::Types::Result::Success] The success result.
242
+ # @api private
243
+ def success(input) = @type.success(input)
244
+
245
+ # Build a failed dry-types result.
246
+ # @param input [Object] The failed input.
247
+ # @param error [Dry::Types::CoercionError] The coercion error.
248
+ # @return [Dry::Types::Result::Failure] The failure result.
249
+ # @api private
250
+ def failure(input, error) = @type.failure(input, error)
251
+
252
+ # Return the dry-types abstract syntax tree.
253
+ # @param meta [Boolean] Whether metadata is included.
254
+ # @return [Array] The type AST.
255
+ def to_ast(meta: true) = @type.to_ast(meta:)
256
+
257
+ # Convert this type to a callable object.
258
+ # @return [Proc] A proc that applies the type.
259
+ def to_proc = proc { call(it) }
260
+
261
+ # Return the wrapped dry type representation.
262
+ # @return [String] The printable type representation.
263
+ def inspect = @type.inspect
264
+
265
+ # Return the dry-types constructor implementation.
266
+ # @return [Class] Dry::Types::Constructor.
267
+ # @api private
268
+ def constructor_type = ::Dry::Types::Constructor
269
+
270
+ # Read or extend this type's metadata.
271
+ # @overload meta
272
+ # @return [Hash] The current metadata.
273
+ # @overload meta(data)
274
+ # @param data [Hash] Metadata to merge into the source type.
275
+ # @return [CollectionType] A collection type carrying the metadata.
276
+ def meta(data = ::Dry::Types::Undefined)
277
+ return @type.meta if ::Dry::Types::Undefined.equal?(data)
278
+
279
+ self.class.new(source.meta(data), kind:, configuration:)
280
+ end
281
+
282
+ # Return a new type without source metadata.
283
+ # @return [CollectionType] A new type with pristine source metadata.
284
+ def pristine = self.class.new(source.pristine, kind:, configuration:)
285
+
286
+ # Return a new Farce type with different output or source options.
287
+ # @param mode [Symbol] The transfer mode for the shared variant.
288
+ # @param scope [Symbol] The storage scope for the local variant.
289
+ # @param source_options [Hash] Options forwarded to the source dry type.
290
+ # @return [CollectionType] A new configured type.
291
+ # @raise [ArgumentError] If the Farce type does not support the requested output option.
292
+ def with(mode: UNDEFINED, scope: UNDEFINED, **source_options)
293
+ configured = configuration.with(kind:, mode:, scope:)
294
+ next_source = source_options.empty? ? source : source.with(**source_options)
295
+ self.class.new(next_source, kind:, configuration: configured)
296
+ end
297
+
298
+ private
299
+
300
+ # Select post-construction constraint behavior.
301
+ # @return [Class] The coercible constrained type class.
302
+ # @api private
303
+ def constrained_type = ::Dry::Types::Constrained::Coercible
304
+ end
305
+
306
+ # A Vector or Set type that applies a member type to every input value.
307
+ class SequenceType < CollectionType
308
+ # Apply a dry type to every member before Farce construction.
309
+ # @param member [Dry::Types::Type, #call] The member type.
310
+ # @return [SequenceType] The typed collection.
311
+ def of(member)
312
+ typed = DryTypes.collection_source(source).of(member)
313
+ typed = DryTypes.restore_optional_source(source, typed)
314
+ self.class.new(typed, kind:, configuration:)
315
+ end
316
+ end
317
+
318
+ # An Atom type that validates or coerces its initial contents.
319
+ class AtomType < CollectionType
320
+ # Apply a dry type to the initial value before Atom construction.
321
+ #
322
+ # Later writes use the ordinary Farce Atom API and are not checked by
323
+ # this type.
324
+ # @param value_type [Dry::Types::Type] The initial value type.
325
+ # @return [AtomType] A new typed Atom constructor.
326
+ # @raise [ArgumentError] If value_type is not a dry type.
327
+ def of(value_type)
328
+ raise ArgumentError, "Atom.of requires a dry type" unless value_type.is_a?(::Dry::Types::Type)
329
+
330
+ self.class.new(value_type, kind:, configuration:)
331
+ end
332
+ end
333
+
334
+ # A Map type that supports dry-types homogeneous maps and schemas.
335
+ class MapType < CollectionType
336
+ # Apply dry types to every key and value before Farce construction.
337
+ # @param key_type [Dry::Types::Type] The key type.
338
+ # @param value_type [Dry::Types::Type] The value type.
339
+ # @return [MapType] The homogeneous map type.
340
+ def map(key_type, value_type)
341
+ typed = DryTypes.collection_source(source).map(key_type, value_type)
342
+ typed = DryTypes.restore_optional_source(source, typed)
343
+ self.class.new(typed, kind:, configuration:)
344
+ end
345
+
346
+ # Define or extend fixed keys and their dry types before Farce construction.
347
+ # @overload schema(keys_or_map, meta = {})
348
+ # Create a schema from the imported Hash source.
349
+ # @param keys_or_map [Hash, Array<Dry::Types::Schema::Key>] The schema definition.
350
+ # @param meta [Hash] Metadata applied while creating the schema.
351
+ # @return [MapType] The schema-backed map type.
352
+ # @overload schema(keys_or_map)
353
+ # Extend an existing schema.
354
+ # @param keys_or_map [Hash, Array<Dry::Types::Schema::Key>] Additional schema keys.
355
+ # @return [MapType] The schema-backed map type.
356
+ def schema(...)
357
+ typed = DryTypes.collection_source(source).schema(...)
358
+ typed = DryTypes.restore_optional_source(source, typed)
359
+ self.class.new(typed, kind:, configuration:)
360
+ end
361
+
362
+ # Return a schema that rejects unknown keys.
363
+ # @param strict [Boolean] Whether unknown keys are rejected.
364
+ # @return [MapType] The configured map type.
365
+ def strict(strict = true) = rebuild_map_source(:strict, strict) # rubocop:disable Style/OptionalBooleanParameter
366
+
367
+ # Transform input keys before schema lookup.
368
+ # @param transform [#call, nil] The key transform.
369
+ # @yield [key] Transform an input key when no callable argument is given.
370
+ # @yieldparam key [Object] An input key.
371
+ # @yieldreturn [Object] The transformed key.
372
+ # @return [MapType] The configured map type.
373
+ def with_key_transform(transform = nil, &) = rebuild_map_source(:with_key_transform, transform, &)
374
+
375
+ # Transform schema key types when defining a schema.
376
+ # @param transform [#call, nil] The type transform.
377
+ # @yield [type] Transform a schema key type when no callable argument is given.
378
+ # @yieldparam type [Dry::Types::Schema::Key] A schema key type.
379
+ # @yieldreturn [Dry::Types::Schema::Key] The transformed key type.
380
+ # @return [MapType] The configured map type.
381
+ def with_type_transform(transform = nil, &) = rebuild_map_source(:with_type_transform, transform, &)
382
+
383
+ private
384
+
385
+ # Explicit arguments avoid losing keyword calls inside JRuby forwarding methods.
386
+ # rubocop:disable-next Style/ArgumentsForwarding
387
+ def rebuild_map_source(method, *arguments, **options, &)
388
+ typed = DryTypes.collection_source(source).public_send(method, *arguments, **options, &)
389
+ typed = DryTypes.restore_optional_source(source, typed)
390
+ self.class.new(typed, kind:, configuration:)
391
+ end
392
+ end
393
+
394
+ # Import module installed by Farce.DryTypes().
395
+ class Import < Module
396
+ # Create a deferred Farce dry-types import.
397
+ # @param namespaces [Array<Symbol>] Explicit dry-types namespaces.
398
+ # @param default [Symbol, Object] The default namespace or Farce's undefined sentinel.
399
+ # @param aliases [Hash{Symbol => Symbol}] Dry-types namespace aliases.
400
+ # @param configuration [Configuration] The Farce output configuration.
401
+ # @return [Import] The import module.
402
+ # @api private
403
+ def initialize(namespaces, default:, aliases:, configuration:)
404
+ super()
405
+ @namespaces = namespaces.freeze
406
+ @default = default
407
+ @aliases = aliases.freeze
408
+ @configuration = configuration
409
+ end
410
+
411
+ # Install Farce types when this import is included.
412
+ # @param base [Module] The application type module.
413
+ # @return [void]
414
+ # @api private
415
+ def included(base)
416
+ source = source_import(base)
417
+ install_root(base, source)
418
+ install_namespaces(base, source)
419
+ super
420
+ end
421
+
422
+ private
423
+
424
+ def source_import(base)
425
+ return configured_import if explicitly_configured?
426
+
427
+ base.ancestors.find { it.is_a?(::Dry::Types::Module) } || ::Dry.Types()
428
+ end
429
+
430
+ def explicitly_configured?
431
+ !@namespaces.empty? || !@aliases.empty? || !UNDEFINED.equal?(@default)
432
+ end
433
+
434
+ def configured_import
435
+ if UNDEFINED.equal?(@default)
436
+ ::Dry.Types(*@namespaces, **@aliases)
437
+ else
438
+ ::Dry.Types(*@namespaces, default: @default, **@aliases)
439
+ end
440
+ end
441
+
442
+ def install_root(base, source)
443
+ install_collection_constants(base, source)
444
+ end
445
+
446
+ def install_namespaces(base, source)
447
+ source.constants(false).each do |name|
448
+ namespace = source.const_get(name, false)
449
+ next unless namespace.is_a?(Module)
450
+ next unless relevant_namespace?(namespace)
451
+
452
+ existing = base.const_get(name) if base.const_defined?(name)
453
+ ensure_available!(base, name)
454
+ base.const_set(name, namespace_overlay(namespace, existing))
455
+ end
456
+ end
457
+
458
+ def install_collection_constants(target, source)
459
+ if (array = usable_array_type(source))
460
+ install_constant(target, :Vector, SequenceType.new(array, kind: :vector, configuration: @configuration))
461
+ install_constant(target, :Set, SequenceType.new(array, kind: :set, configuration: @configuration))
462
+ end
463
+ if (hash = usable_hash_type(source))
464
+ install_constant(target, :Map, MapType.new(hash, kind: :map, configuration: @configuration))
465
+ end
466
+ install_scalar_constants(target, source)
467
+ end
468
+
469
+ def install_scalar_constants(target, source)
470
+ if @configuration.target?(:counter) && (integer = usable_type(source, :Integer))
471
+ type = CollectionType.new(integer, kind: :counter, configuration: @configuration)
472
+ install_constant(target, :Counter, type)
473
+ end
474
+ if @configuration.target?(:flag) && (bool = usable_type(source, :Bool))
475
+ install_constant(target, :Flag, CollectionType.new(bool, kind: :flag, configuration: @configuration))
476
+ end
477
+ return unless @configuration.target?(:atom) && dry_namespace?(source)
478
+
479
+ any = ::Dry::Types["any"]
480
+ install_constant(target, :Atom, AtomType.new(any, kind: :atom, configuration: @configuration))
481
+ end
482
+
483
+ def usable_array_type(source)
484
+ type = source.const_get(:Array, false) if source.const_defined?(:Array, false)
485
+ collection = DryTypes.collection_source(type) if type
486
+ type if valid_source?(collection, ::Array) && collection.respond_to?(:of)
487
+ end
488
+
489
+ def usable_hash_type(source)
490
+ type = source.const_get(:Hash, false) if source.const_defined?(:Hash, false)
491
+ collection = DryTypes.collection_source(type) if type
492
+ type if valid_source?(collection, ::Hash) && collection.respond_to?(:map) && collection.respond_to?(:schema)
493
+ end
494
+
495
+ def valid_source?(type, primitive)
496
+ return false unless type.is_a?(::Dry::Types::Type) && type.respond_to?(:primitive)
497
+
498
+ actual = type.primitive
499
+ actual.is_a?(Class) && actual <= primitive
500
+ end
501
+
502
+ def usable_type(source, name)
503
+ type = source.const_get(name, false) if source.const_defined?(name, false)
504
+ type if type.is_a?(::Dry::Types::Type)
505
+ end
506
+
507
+ def dry_namespace?(source)
508
+ source.constants(false).any? do |name|
509
+ source.const_get(name, false).is_a?(::Dry::Types::Type)
510
+ end
511
+ end
512
+
513
+ def install_constant(target, name, value)
514
+ ensure_available!(target, name)
515
+ target.const_set(name, value)
516
+ end
517
+
518
+ def relevant_namespace?(namespace)
519
+ return true if usable_array_type(namespace) || usable_hash_type(namespace)
520
+ return true if scalar_namespace?(namespace)
521
+
522
+ namespace.constants(false).any? do |name|
523
+ child = namespace.const_get(name, false)
524
+ child.is_a?(Module) && relevant_namespace?(child)
525
+ end
526
+ end
527
+
528
+ def scalar_namespace?(namespace)
529
+ (@configuration.target?(:counter) && usable_type(namespace, :Integer)) ||
530
+ (@configuration.target?(:flag) && usable_type(namespace, :Bool)) ||
531
+ (@configuration.target?(:atom) && dry_namespace?(namespace))
532
+ end
533
+
534
+ def namespace_overlay(namespace, existing = nil)
535
+ overlay = Module.new
536
+ overlay.include(namespace)
537
+ overlay.include(existing) if existing.is_a?(Module) && !existing.equal?(namespace)
538
+ install_collection_constants(overlay, namespace)
539
+ namespace.constants(false).each do |name|
540
+ child = namespace.const_get(name, false)
541
+ next unless child.is_a?(Module) && relevant_namespace?(child)
542
+
543
+ prior = existing.const_get(name) if existing.is_a?(Module) && existing.const_defined?(name)
544
+ overlay.const_set(name, namespace_overlay(child, prior))
545
+ end
546
+ overlay
547
+ end
548
+
549
+ def ensure_available!(target, name)
550
+ return unless target.const_defined?(name, false)
551
+
552
+ raise ArgumentError, "cannot import Farce dry type over #{target}::#{name}"
553
+ end
554
+ end
555
+
556
+ extend self
557
+
558
+ # Create the import module used by Farce.DryTypes().
559
+ # @param namespaces [Array<Symbol>] Explicit dry-types namespaces.
560
+ # @param default [Symbol, Object] The default namespace or Farce's undefined sentinel.
561
+ # @param aliases [Hash{Symbol => Symbol}] Dry-types namespace aliases.
562
+ # @param variant [Symbol] The Farce collection family.
563
+ # @param mode [Symbol, Object] The shared transfer mode or the undefined sentinel.
564
+ # @param scope [Symbol, Object] The local scope or the undefined sentinel.
565
+ # @return [Import] The import module.
566
+ # @api private
567
+ def import(namespaces, default:, aliases:, variant:, mode:, scope:)
568
+ configuration = Configuration.new(variant:, mode:, scope:)
569
+ Import.new(namespaces, default:, aliases:, configuration:)
570
+ end
571
+
572
+ # Build the delegated dry constructor for a Farce value.
573
+ # @param source [Dry::Types::Type] The source type.
574
+ # @param kind [Symbol] The lowercase Farce type name.
575
+ # @param configuration [Configuration] The Farce output configuration.
576
+ # @return [Dry::Types::Type] The constructor type.
577
+ # @api private
578
+ def build_type(source, kind, configuration)
579
+ target = configuration.target(kind)
580
+ constructor = lambda do |input, &failure|
581
+ values = source.call(materialize(input, kind), &failure)
582
+ reject_structural_key_collisions!(values) if kind == :map
583
+ optional_nil = kind != :atom && values.nil? && source.optional?
584
+ optional_nil ? nil : target.new(values, **configuration.constructor_options(kind))
585
+ rescue Farce::Ractor::IsolationError, ArgumentError, TypeError, NoMethodError, RangeError => e
586
+ ::Dry::Types::CoercionError.handle(e, &failure)
587
+ end
588
+
589
+ output_type(target, source, kind).constructor(constructor)
590
+ end
591
+
592
+ # Unwrap the collection branch of an optional source type.
593
+ # @param source [Dry::Types::Type] The possibly optional source.
594
+ # @return [Dry::Types::Type] The Array or Hash branch.
595
+ # @api private
596
+ def collection_source(source)
597
+ source.respond_to?(:optional?) && source.optional? ? source.right : source
598
+ end
599
+
600
+ # Restore the nil branch after configuring an optional collection.
601
+ # @param original [Dry::Types::Type] The original source type.
602
+ # @param typed [Dry::Types::Type] The configured collection branch.
603
+ # @return [Dry::Types::Type] The configured type with optionality restored.
604
+ # @api private
605
+ def restore_optional_source(original, typed)
606
+ original.respond_to?(:optional?) && original.optional? ? original.left | typed : typed
607
+ end
608
+
609
+ private
610
+
611
+ def output_type(target, source, kind)
612
+ type = ::Dry.Types().Nominal(target)
613
+ type = type.with(namespace: source.namespace) if source.respond_to?(:namespace) && source.namespace
614
+ type = type.meta(source.meta) if source.respond_to?(:meta) && !source.meta.empty?
615
+ type = type.constrained(type: target)
616
+ kind != :atom && source.respond_to?(:optional?) && source.optional? ? type.optional : type
617
+ end
618
+
619
+ def materialize(input, kind)
620
+ case kind
621
+ when :vector then vector_input(input)
622
+ when :map then map_input(input)
623
+ when :set then materialize_set(input)
624
+ else input
625
+ end
626
+ end
627
+
628
+ def vector_input(input)
629
+ return input unless input.is_a?(Farce::Abstract::Vector)
630
+
631
+ reject_mode_backed_input!(input)
632
+ input.to_a
633
+ end
634
+
635
+ def map_input(input)
636
+ return input unless input.is_a?(Farce::Abstract::Map)
637
+
638
+ reject_mode_backed_input!(input)
639
+ input.to_h
640
+ end
641
+
642
+ def materialize_set(input)
643
+ if input.is_a?(Farce::Abstract::Set)
644
+ reject_mode_backed_input!(input)
645
+ input.to_a
646
+ elsif input.is_a?(::Set)
647
+ input.to_a
648
+ else
649
+ input
650
+ end
651
+ end
652
+
653
+ def reject_mode_backed_input!(input)
654
+ return unless input.respond_to?(:mode)
655
+
656
+ raise ArgumentError, "mode-backed Farce collections must be materialized before dry-types processing"
657
+ end
658
+
659
+ def reject_structural_key_collisions!(hash)
660
+ return unless hash.is_a?(::Hash) && hash.compare_by_identity?
661
+
662
+ structural = {}
663
+ hash.each_key do |key|
664
+ raise ArgumentError, "duplicate structural hash key #{key.inspect}" if structural.key?(key)
665
+
666
+ structural[key] = true
667
+ end
668
+ end
669
+ end
670
+ end
671
+
672
+ # @note This methods is only available if dry-types has been loaded.
673
+ #
674
+ # Build a dry-types import for Farce types.
675
+ #
676
+ # With no dry namespace options, the import uses the nearest Dry.Types()
677
+ # import already included in the receiving module. Without one, it uses the
678
+ # same strict defaults as Dry.Types(). Dry namespace arguments, `default:`,
679
+ # and aliases select an independent source import using Dry.Types() rules.
680
+ #
681
+ # @param namespaces [Array<Symbol>] Dry type namespaces to import Farce counterparts for.
682
+ # @param default [Symbol] The Dry namespace used for root Farce type constants.
683
+ # @param variant [Symbol] The output variant: :shared, :strict, :unshared, or :local.
684
+ # @param mode [Symbol] The transfer mode for the shared variant.
685
+ # @param scope [Symbol] The storage scope for the local variant.
686
+ # @param aliases [Hash{Symbol => Symbol}] Dry namespace aliases.
687
+ # @return [Module] A module for inclusion beside Dry.Types().
688
+ def self.DryTypes( # rubocop:disable Naming/MethodName
689
+ *namespaces, default: UNDEFINED, variant: :shared, mode: UNDEFINED, scope: UNDEFINED, **aliases
690
+ )
691
+ internal = const_get(:Internal, false).const_get(:DryTypes, false)
692
+ internal.import(namespaces, default:, aliases:, variant:, mode:, scope:)
693
+ end
694
+ end