farce 0.0.1.alpha2-x86-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1524 -0
- data/SECURITY.md +10 -0
- data/docs/benchmarks.md +185 -0
- data/docs/gems/dry-types.md +290 -0
- data/docs/gems/msgpack.md +70 -0
- data/docs/gems/ractor-shim.md +63 -0
- data/docs/modes.md +628 -0
- data/docs/scopes.md +649 -0
- data/docs/variants.md +346 -0
- data/ext/ext_helper.rb +20 -0
- data/ext/farce/README.md +21 -0
- data/ext/farce/atom.c +1023 -0
- data/ext/farce/bounded_map.c +1683 -0
- data/ext/farce/containers.h +77 -0
- data/ext/farce/counter.c +399 -0
- data/ext/farce/darwin.c +100 -0
- data/ext/farce/depend +12 -0
- data/ext/farce/dict.c +1523 -0
- data/ext/farce/dict.h +152 -0
- data/ext/farce/drivers.c +237 -0
- data/ext/farce/exchanger.c +299 -0
- data/ext/farce/extconf.rb +99 -0
- data/ext/farce/farce.c +359 -0
- data/ext/farce/flag.c +288 -0
- data/ext/farce/io.c +338 -0
- data/ext/farce/lock.c +510 -0
- data/ext/farce/map.c +2240 -0
- data/ext/farce/priority_queue.c +2056 -0
- data/ext/farce/queue.c +1059 -0
- data/ext/farce/reactor.c +820 -0
- data/ext/farce/reactor.h +103 -0
- data/ext/farce/shareable.h +31 -0
- data/ext/farce/signal.c +350 -0
- data/ext/farce/transaction.c +354 -0
- data/ext/farce/transaction.h +40 -0
- data/ext/farce/tree_map.c +1953 -0
- data/ext/farce/trie.c +2020 -0
- data/ext/farce/unshareable.c +155 -0
- data/ext/farce/unshared_io_pool.h +234 -0
- data/ext/farce/unshared_signal.c +263 -0
- data/ext/farce/unshared_wait.h +193 -0
- data/ext/farce/unsupported.c +6 -0
- data/ext/farce/vector.c +1195 -0
- data/ext/farce/weak_map.c +1714 -0
- data/ext/java/org/farce/BoundedMap.java +394 -0
- data/ext/java/org/farce/FiberScheduler.java +141 -0
- data/ext/java/org/farce/PriorityKey.java +45 -0
- data/ext/java/org/farce/PriorityQueue.java +373 -0
- data/ext/java/org/farce/QueueSignal.java +28 -0
- data/ext/rebind/README.md +14 -0
- data/ext/rebind/extconf.rb +10 -0
- data/ext/rebind/rebind.c +186 -0
- data/lib/farce/_yard/internal.rb +13 -0
- data/lib/farce/_yard/macros.rb +61 -0
- data/lib/farce/_yard/ractor.rb +46 -0
- data/lib/farce/abstract/atom.rb +186 -0
- data/lib/farce/abstract/bounded_map.rb +232 -0
- data/lib/farce/abstract/collection.rb +151 -0
- data/lib/farce/abstract/concurrent_map.rb +381 -0
- data/lib/farce/abstract/counter.rb +193 -0
- data/lib/farce/abstract/duplicable_map.rb +229 -0
- data/lib/farce/abstract/exchanger.rb +26 -0
- data/lib/farce/abstract/flag.rb +71 -0
- data/lib/farce/abstract/lazy.rb +115 -0
- data/lib/farce/abstract/lease.rb +104 -0
- data/lib/farce/abstract/lease_map.rb +261 -0
- data/lib/farce/abstract/lease_pool.rb +91 -0
- data/lib/farce/abstract/lfu_map.rb +20 -0
- data/lib/farce/abstract/lru_map.rb +25 -0
- data/lib/farce/abstract/map.rb +345 -0
- data/lib/farce/abstract/molecule.rb +245 -0
- data/lib/farce/abstract/port.rb +74 -0
- data/lib/farce/abstract/priority_queue.rb +117 -0
- data/lib/farce/abstract/queue.rb +269 -0
- data/lib/farce/abstract/scheduler.rb +111 -0
- data/lib/farce/abstract/set.rb +910 -0
- data/lib/farce/abstract/sorted_set.rb +172 -0
- data/lib/farce/abstract/timer_queue.rb +136 -0
- data/lib/farce/abstract/tree_map.rb +269 -0
- data/lib/farce/abstract/value.rb +68 -0
- data/lib/farce/abstract/vector.rb +1126 -0
- data/lib/farce/abstract/weak_atom.rb +32 -0
- data/lib/farce/abstract/weak_key_map.rb +12 -0
- data/lib/farce/abstract/weak_map.rb +13 -0
- data/lib/farce/abstract/weak_set.rb +12 -0
- data/lib/farce/abstract/weak_value_map.rb +12 -0
- data/lib/farce/abstract.rb +17 -0
- data/lib/farce/atom.rb +293 -0
- data/lib/farce/class_mirror.rb +87 -0
- data/lib/farce/clock.rb +121 -0
- data/lib/farce/config.rb +229 -0
- data/lib/farce/counter.rb +71 -0
- data/lib/farce/deduper.rb +122 -0
- data/lib/farce/engine/jruby/bounded_map.rb +314 -0
- data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
- data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
- data/lib/farce/engine/jruby/map.rb +505 -0
- data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
- data/lib/farce/engine/jruby/signal.rb +147 -0
- data/lib/farce/engine/jruby.rb +63 -0
- data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
- data/lib/farce/engine/jvm/counter.rb +102 -0
- data/lib/farce/engine/jvm/extension.rb +32 -0
- data/lib/farce/engine/jvm/farce.jar +0 -0
- data/lib/farce/engine/jvm/flag.rb +79 -0
- data/lib/farce/engine/jvm/priority_queue.rb +217 -0
- data/lib/farce/engine/jvm/tree_map.rb +350 -0
- data/lib/farce/engine/jvm/types.rb +180 -0
- data/lib/farce/engine/jvm.rb +19 -0
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
- data/lib/farce/engine/ruby/3.4/port.rb +186 -0
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
- data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
- data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
- data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/port.rb +19 -0
- data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
- data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
- data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
- data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
- data/lib/farce/engine/ruby/4.1/port.rb +21 -0
- data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
- data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
- data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
- data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
- data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
- data/lib/farce/engine/ruby/shared/lease.rb +26 -0
- data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
- data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
- data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
- data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
- data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
- data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
- data/lib/farce/engine/ruby/shared/vault.rb +144 -0
- data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
- data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
- data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
- data/lib/farce/engine/ruby.rb +130 -0
- data/lib/farce/engine/shared/atom.rb +10 -0
- data/lib/farce/engine/shared/exchanger.rb +130 -0
- data/lib/farce/engine/shared/identity_key.rb +22 -0
- data/lib/farce/engine/shared/lease.rb +10 -0
- data/lib/farce/engine/shared/lease_pool.rb +10 -0
- data/lib/farce/engine/shared/main_scheduler.rb +20 -0
- data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
- data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/shared/port.rb +44 -0
- data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
- data/lib/farce/engine/shared/proxy_owner.rb +43 -0
- data/lib/farce/engine/shared/queue.rb +233 -0
- data/lib/farce/engine/shared/ractor_methods.rb +73 -0
- data/lib/farce/engine/shared/rebindable.rb +15 -0
- data/lib/farce/engine/shared/strict_atom.rb +73 -0
- data/lib/farce/engine/shared/strict_map.rb +117 -0
- data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
- data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
- data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
- data/lib/farce/engine/shared/trie.rb +317 -0
- data/lib/farce/engine/shared/trie_builder.rb +199 -0
- data/lib/farce/engine/shared/unshareable.rb +14 -0
- data/lib/farce/engine/shared/unshared_atom.rb +256 -0
- data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
- data/lib/farce/engine/shared/unshared_queue.rb +18 -0
- data/lib/farce/engine/shared/unshared_signal.rb +21 -0
- data/lib/farce/engine/shared/unshared_vector.rb +377 -0
- data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
- data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
- data/lib/farce/engine/shared/vault.rb +31 -0
- data/lib/farce/engine/shared/vector.rb +83 -0
- data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
- data/lib/farce/engine/shared/weak_atom.rb +20 -0
- data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
- data/lib/farce/engine/shared/weak_map/index.rb +249 -0
- data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
- data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
- data/lib/farce/engine/shared.rb +63 -0
- data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
- data/lib/farce/engine/truffleruby/lock.rb +121 -0
- data/lib/farce/engine/truffleruby/map.rb +656 -0
- data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
- data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
- data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
- data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
- data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
- data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
- data/lib/farce/engine/truffleruby/signal.rb +77 -0
- data/lib/farce/engine/truffleruby.rb +148 -0
- data/lib/farce/envelope.rb +335 -0
- data/lib/farce/error.rb +35 -0
- data/lib/farce/exchanger.rb +41 -0
- data/lib/farce/flag.rb +27 -0
- data/lib/farce/integrations/active_support/blank.rb +68 -0
- data/lib/farce/integrations/active_support/clock.rb +17 -0
- data/lib/farce/integrations/active_support/duplicable.rb +78 -0
- data/lib/farce/integrations/active_support/map.rb +175 -0
- data/lib/farce/integrations/active_support/set.rb +60 -0
- data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
- data/lib/farce/integrations/active_support/vector.rb +231 -0
- data/lib/farce/integrations/active_support.rb +9 -0
- data/lib/farce/integrations/activesupport.rb +5 -0
- data/lib/farce/integrations/bson.rb +108 -0
- data/lib/farce/integrations/cbor.rb +51 -0
- data/lib/farce/integrations/concurrent.rb +112 -0
- data/lib/farce/integrations/dry-types.rb +5 -0
- data/lib/farce/integrations/dry_types.rb +694 -0
- data/lib/farce/integrations/json.rb +7 -0
- data/lib/farce/integrations/msgpack.rb +112 -0
- data/lib/farce/integrations/oj.rb +69 -0
- data/lib/farce/integrations/psych.rb +191 -0
- data/lib/farce/integrations/ractor-sharing.rb +5 -0
- data/lib/farce/integrations/ractor-tmvar.rb +5 -0
- data/lib/farce/integrations/ractor_sharing.rb +172 -0
- data/lib/farce/integrations/ractor_tmvar.rb +64 -0
- data/lib/farce/integrations/shared/to_json.rb +42 -0
- data/lib/farce/integrations/sorted_set.rb +11 -0
- data/lib/farce/integrations/weakref.rb +38 -0
- data/lib/farce/integrations/yajl.rb +10 -0
- data/lib/farce/integrations.rb +156 -0
- data/lib/farce/internal/_frozen_config.rb +11 -0
- data/lib/farce/internal/autoloads.rb +47 -0
- data/lib/farce/internal/blocking_priority_queue.rb +122 -0
- data/lib/farce/internal/converter.rb +106 -0
- data/lib/farce/internal/copyable.rb +31 -0
- data/lib/farce/internal/delegation.rb +20 -0
- data/lib/farce/internal/external_transaction.rb +59 -0
- data/lib/farce/internal/fake_ractor.rb +179 -0
- data/lib/farce/internal/freeze.rb +118 -0
- data/lib/farce/internal/inspect.rb +157 -0
- data/lib/farce/internal/key_lock_map.rb +29 -0
- data/lib/farce/internal/key_normalizer.rb +289 -0
- data/lib/farce/internal/lease_initialization.rb +115 -0
- data/lib/farce/internal/lease_map.rb +441 -0
- data/lib/farce/internal/lease_pool_state.rb +228 -0
- data/lib/farce/internal/lease_state.rb +342 -0
- data/lib/farce/internal/lease_waiting.rb +13 -0
- data/lib/farce/internal/managed_queue.rb +26 -0
- data/lib/farce/internal/map_value_modes.rb +227 -0
- data/lib/farce/internal/marshal_support.rb +227 -0
- data/lib/farce/internal/mixin.rb +20 -0
- data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
- data/lib/farce/internal/noncopyable.rb +17 -0
- data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
- data/lib/farce/internal/pool_supervisor.rb +41 -0
- data/lib/farce/internal/pool_worker.rb +61 -0
- data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
- data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
- data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
- data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
- data/lib/farce/internal/portable_transaction.rb +164 -0
- data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
- data/lib/farce/internal/reservation_waiting.rb +24 -0
- data/lib/farce/internal/scheduled_task.rb +48 -0
- data/lib/farce/internal/scheduler_io.rb +171 -0
- data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
- data/lib/farce/internal/select_scheduler.rb +235 -0
- data/lib/farce/internal/storage.rb +162 -0
- data/lib/farce/internal/strict_lease.rb +30 -0
- data/lib/farce/internal/strict_lease_map.rb +20 -0
- data/lib/farce/internal/strict_lease_pool.rb +29 -0
- data/lib/farce/internal/thread_pool.rb +166 -0
- data/lib/farce/internal/transaction_conflict.rb +9 -0
- data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
- data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
- data/lib/farce/internal/undefined.rb +22 -0
- data/lib/farce/internal/unshared_lease.rb +29 -0
- data/lib/farce/internal/unshared_lease_pool.rb +34 -0
- data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
- data/lib/farce/internal/value_serialization.rb +13 -0
- data/lib/farce/internal/weak_map_value_modes.rb +58 -0
- data/lib/farce/internal/weak_mode_manager.rb +26 -0
- data/lib/farce/internal.rb +129 -0
- data/lib/farce/lazy.rb +100 -0
- data/lib/farce/lazy_ref.rb +40 -0
- data/lib/farce/lease.rb +28 -0
- data/lib/farce/lease_map.rb +34 -0
- data/lib/farce/lease_pool.rb +29 -0
- data/lib/farce/lfu_map.rb +53 -0
- data/lib/farce/local/atom.rb +23 -0
- data/lib/farce/local/counter.rb +88 -0
- data/lib/farce/local/flag.rb +65 -0
- data/lib/farce/local/lazy.rb +38 -0
- data/lib/farce/local/lazy_ref.rb +36 -0
- data/lib/farce/local/lease.rb +77 -0
- data/lib/farce/local/lease_map.rb +80 -0
- data/lib/farce/local/lease_pool.rb +38 -0
- data/lib/farce/local/lfu_map.rb +55 -0
- data/lib/farce/local/lru_map.rb +62 -0
- data/lib/farce/local/map.rb +47 -0
- data/lib/farce/local/molecule.rb +45 -0
- data/lib/farce/local/priority_queue.rb +53 -0
- data/lib/farce/local/queue.rb +32 -0
- data/lib/farce/local/scoped.rb +166 -0
- data/lib/farce/local/set.rb +18 -0
- data/lib/farce/local/sorted_set.rb +50 -0
- data/lib/farce/local/timer_queue.rb +41 -0
- data/lib/farce/local/tree_map.rb +47 -0
- data/lib/farce/local/vector.rb +30 -0
- data/lib/farce/local/weak_atom.rb +23 -0
- data/lib/farce/local/weak_key_map.rb +39 -0
- data/lib/farce/local/weak_map.rb +39 -0
- data/lib/farce/local/weak_set.rb +18 -0
- data/lib/farce/local/weak_value_map.rb +39 -0
- data/lib/farce/local.rb +35 -0
- data/lib/farce/lock.rb +54 -0
- data/lib/farce/lru_map.rb +63 -0
- data/lib/farce/map.rb +58 -0
- data/lib/farce/mode_manager.rb +142 -0
- data/lib/farce/molecule.rb +60 -0
- data/lib/farce/mutable.rb +171 -0
- data/lib/farce/pool.rb +332 -0
- data/lib/farce/port.rb +134 -0
- data/lib/farce/priority_queue.rb +70 -0
- data/lib/farce/proxy/register.rb +101 -0
- data/lib/farce/proxy/supervisor.rb +137 -0
- data/lib/farce/proxy/wrapper.rb +49 -0
- data/lib/farce/proxy.rb +291 -0
- data/lib/farce/queue.rb +60 -0
- data/lib/farce/ractor.rb +269 -0
- data/lib/farce/read_write_lock.rb +256 -0
- data/lib/farce/reference.rb +158 -0
- data/lib/farce/resolv/dns.rb +42 -0
- data/lib/farce/resolv.rb +85 -0
- data/lib/farce/scheduler.rb +536 -0
- data/lib/farce/set.rb +39 -0
- data/lib/farce/shareable.rb +150 -0
- data/lib/farce/signal.rb +97 -0
- data/lib/farce/sorted_set.rb +36 -0
- data/lib/farce/strict/atom.rb +34 -0
- data/lib/farce/strict/counter.rb +10 -0
- data/lib/farce/strict/exchanger.rb +25 -0
- data/lib/farce/strict/flag.rb +10 -0
- data/lib/farce/strict/lazy.rb +26 -0
- data/lib/farce/strict/lazy_ref.rb +26 -0
- data/lib/farce/strict/lease.rb +27 -0
- data/lib/farce/strict/lease_map.rb +33 -0
- data/lib/farce/strict/lease_pool.rb +28 -0
- data/lib/farce/strict/lfu_map.rb +27 -0
- data/lib/farce/strict/lru_map.rb +28 -0
- data/lib/farce/strict/map.rb +54 -0
- data/lib/farce/strict/molecule.rb +16 -0
- data/lib/farce/strict/port.rb +40 -0
- data/lib/farce/strict/priority_queue.rb +20 -0
- data/lib/farce/strict/queue.rb +17 -0
- data/lib/farce/strict/set.rb +14 -0
- data/lib/farce/strict/sorted_set.rb +19 -0
- data/lib/farce/strict/timer_queue.rb +13 -0
- data/lib/farce/strict/tree_map.rb +27 -0
- data/lib/farce/strict/vector.rb +24 -0
- data/lib/farce/strict/weak_atom.rb +31 -0
- data/lib/farce/strict/weak_key_map.rb +49 -0
- data/lib/farce/strict/weak_map.rb +49 -0
- data/lib/farce/strict/weak_set.rb +14 -0
- data/lib/farce/strict/weak_value_map.rb +48 -0
- data/lib/farce/strict.rb +28 -0
- data/lib/farce/system.rb +40 -0
- data/lib/farce/thread_scheduler.rb +70 -0
- data/lib/farce/timer_queue.rb +66 -0
- data/lib/farce/transaction/atom.rb +73 -0
- data/lib/farce/transaction/map.rb +25 -0
- data/lib/farce/transaction/map_operations.rb +143 -0
- data/lib/farce/transaction/molecule.rb +90 -0
- data/lib/farce/transaction/mutable.rb +61 -0
- data/lib/farce/transaction/set.rb +17 -0
- data/lib/farce/transaction/set_operations.rb +48 -0
- data/lib/farce/transaction/sorted_set.rb +18 -0
- data/lib/farce/transaction/tree_map.rb +78 -0
- data/lib/farce/transaction/vector.rb +139 -0
- data/lib/farce/transaction/wrapper.rb +202 -0
- data/lib/farce/transaction.rb +343 -0
- data/lib/farce/tree_map.rb +56 -0
- data/lib/farce/unsafe/lfu_map.rb +36 -0
- data/lib/farce/unsafe/lru_map.rb +36 -0
- data/lib/farce/unsafe/tree_map.rb +21 -0
- data/lib/farce/unsafe.rb +29 -0
- data/lib/farce/unshareable.rb +67 -0
- data/lib/farce/unshared/atom.rb +24 -0
- data/lib/farce/unshared/counter.rb +10 -0
- data/lib/farce/unshared/flag.rb +10 -0
- data/lib/farce/unshared/lazy.rb +38 -0
- data/lib/farce/unshared/lazy_ref.rb +26 -0
- data/lib/farce/unshared/lease.rb +27 -0
- data/lib/farce/unshared/lease_map.rb +26 -0
- data/lib/farce/unshared/lease_pool.rb +25 -0
- data/lib/farce/unshared/lfu_map.rb +20 -0
- data/lib/farce/unshared/lru_map.rb +20 -0
- data/lib/farce/unshared/map.rb +49 -0
- data/lib/farce/unshared/molecule.rb +16 -0
- data/lib/farce/unshared/priority_queue.rb +16 -0
- data/lib/farce/unshared/queue.rb +27 -0
- data/lib/farce/unshared/set.rb +14 -0
- data/lib/farce/unshared/sorted_set.rb +28 -0
- data/lib/farce/unshared/timer_queue.rb +16 -0
- data/lib/farce/unshared/tree_map.rb +21 -0
- data/lib/farce/unshared/vector.rb +19 -0
- data/lib/farce/unshared/weak_atom.rb +31 -0
- data/lib/farce/unshared/weak_key_map.rb +44 -0
- data/lib/farce/unshared/weak_map.rb +44 -0
- data/lib/farce/unshared/weak_set.rb +14 -0
- data/lib/farce/unshared/weak_value_map.rb +43 -0
- data/lib/farce/unshared.rb +28 -0
- data/lib/farce/vector.rb +228 -0
- data/lib/farce/version.rb +8 -0
- data/lib/farce/walker/definitions.rb +186 -0
- data/lib/farce/walker/modification.rb +355 -0
- data/lib/farce/walker.rb +319 -0
- data/lib/farce/weak_atom.rb +121 -0
- data/lib/farce/weak_key_map.rb +31 -0
- data/lib/farce/weak_map.rb +33 -0
- data/lib/farce/weak_ref.rb +67 -0
- data/lib/farce/weak_set.rb +82 -0
- data/lib/farce/weak_value.rb +195 -0
- data/lib/farce/weak_value_map.rb +32 -0
- data/lib/farce.rb +519 -0
- metadata +468 -0
data/lib/farce.rb
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
# We don't actually use Zeitwerk, but this works around a Zeitwerk bug.
|
|
7
|
+
# Zeitwerk might break if a Ractor starts before it is loaded.
|
|
8
|
+
#
|
|
9
|
+
# Ractor.new {}
|
|
10
|
+
# require "zeitwerk"
|
|
11
|
+
# require "zeitwerk" # NoMethodError: super: no superclass method 'require' for main
|
|
12
|
+
#
|
|
13
|
+
# This has absolutely nothing to do with Farce, except that Farce might create a Ractor.
|
|
14
|
+
require "zeitwerk"
|
|
15
|
+
rescue LoadError => e
|
|
16
|
+
raise unless e.path == "zeitwerk"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require "farce/config"
|
|
20
|
+
require "farce/internal"
|
|
21
|
+
require "farce/engine/#{RUBY_ENGINE}"
|
|
22
|
+
require "farce/version"
|
|
23
|
+
require "farce/error"
|
|
24
|
+
require "farce/system"
|
|
25
|
+
|
|
26
|
+
# Namespace for everything provided by Farce.
|
|
27
|
+
#
|
|
28
|
+
# ## Including Farce
|
|
29
|
+
#
|
|
30
|
+
# Including Farce in a class or module will include **all public camel-case constants** defined under the Farce
|
|
31
|
+
# namespace.
|
|
32
|
+
#
|
|
33
|
+
# ```ruby
|
|
34
|
+
# require "farce"
|
|
35
|
+
#
|
|
36
|
+
# # This could also be done under a class or module, to avoid polluting the global namespace.
|
|
37
|
+
# include Farce
|
|
38
|
+
#
|
|
39
|
+
# # Now Ractor is available, even on JRuby or TruffleRuby!
|
|
40
|
+
# Ractor.new { puts "Hello from a Ractor!" }
|
|
41
|
+
#
|
|
42
|
+
# # Other constants are also available.
|
|
43
|
+
# Clock.parse(1.minute.from_now)
|
|
44
|
+
#
|
|
45
|
+
# # VERSION is not exposed. This is to avoid polluting other libraries with it.
|
|
46
|
+
# defined?(VERSION) # => false
|
|
47
|
+
# ```
|
|
48
|
+
module Farce
|
|
49
|
+
include Internal::Autoloads
|
|
50
|
+
|
|
51
|
+
# The valid storage scopes for local values and collections.
|
|
52
|
+
# @return [::Set<Symbol>]
|
|
53
|
+
SCOPES = ::Set[:ractor, :thread_group, :thread, :fiber_storage, :fiber].freeze
|
|
54
|
+
|
|
55
|
+
# The valid transfer modes for values that are not Ractor-shareable.
|
|
56
|
+
# @return [::Set<Symbol>]
|
|
57
|
+
MODES = ::Set[:copy, :move, :local, :make_shareable, :mutable, :raise, :shareable_copy, :dedup, :proxy].freeze
|
|
58
|
+
|
|
59
|
+
UNDEFINED = Internal::Undefined.new("UNDEFINED")
|
|
60
|
+
|
|
61
|
+
autoload :DEDUPER, "farce/deduper"
|
|
62
|
+
private_constant :Internal, :UNDEFINED, :DEDUPER
|
|
63
|
+
|
|
64
|
+
# @overload transaction(*objects, retries: nil, backoff_after: 10, max_backoff: 1.0)
|
|
65
|
+
# Creates and runs a new transaction attempt.
|
|
66
|
+
#
|
|
67
|
+
# Automatically retries failed attempts indefinitely unless a retry limit is specified.
|
|
68
|
+
# Starts backing off after the specified number of attempts, up to the maximum delay.
|
|
69
|
+
#
|
|
70
|
+
# @example Modifying multiple entries in a map
|
|
71
|
+
# accounts = Farce::Map.new({a: 100, b: 200})
|
|
72
|
+
#
|
|
73
|
+
# # transfer 80 from :a to :b, but only if both succeed
|
|
74
|
+
# success = Farce.transaction(accounts) do |tx, accounts|
|
|
75
|
+
# tx.abort! if accounts[:b] < 80
|
|
76
|
+
# accounts[:a] += 80
|
|
77
|
+
# accounts[:b] -= 80
|
|
78
|
+
# end
|
|
79
|
+
#
|
|
80
|
+
# if success
|
|
81
|
+
# puts "Transaction succeeded"
|
|
82
|
+
# else
|
|
83
|
+
# puts "Transaction failed"
|
|
84
|
+
# end
|
|
85
|
+
#
|
|
86
|
+
# @example Programmatically registering objects for transactions
|
|
87
|
+
# map = Farce::Map.new({a: 1, b: 2})
|
|
88
|
+
# summary = Farce::Atom.new("size not calculated")
|
|
89
|
+
#
|
|
90
|
+
# # make sure map[:size], map.size, and the summary all match
|
|
91
|
+
# Farce.transaction do |tx|
|
|
92
|
+
# tx_map = tx[map]
|
|
93
|
+
# tx_map[:size] = size = tx_map.size
|
|
94
|
+
# tx[summary].value = "size: #{size}"
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# @param objects [Array] list of objects to enroll in the transaction
|
|
98
|
+
# @param retries [Integer, nil] maximum additional attempts, or nil for unlimited retries
|
|
99
|
+
# @param backoff_after [Integer] number of attempts before starting to back off
|
|
100
|
+
# @param max_backoff [Numeric] maximum backoff delay in seconds
|
|
101
|
+
# @yield [transaction, *objects] the current transaction and the enrolled objects
|
|
102
|
+
# @yieldparam transaction [Farce::Transaction] the current transaction
|
|
103
|
+
# @yieldparam objects [Array] the enrolled objects
|
|
104
|
+
# @return [Boolean] whether the transaction committed successfully
|
|
105
|
+
def self.transaction(...) = Transaction.run(...)
|
|
106
|
+
|
|
107
|
+
# @overload clock
|
|
108
|
+
# The current clock time
|
|
109
|
+
#
|
|
110
|
+
# @overload clock(value)
|
|
111
|
+
# Parses value into a monotonic clock time.
|
|
112
|
+
# @param value [nil, Numeric, Time, ActiveSupport::Duration, Hash] the value to convert to clock time
|
|
113
|
+
# @see Clock.parse
|
|
114
|
+
#
|
|
115
|
+
# @overload clock(at:)
|
|
116
|
+
# Gives the clock time for a fixed point in time. Independent of the current time.
|
|
117
|
+
# @param at [Numeric, Time] the value to convert to clock time
|
|
118
|
+
#
|
|
119
|
+
# @overload clock(time:)
|
|
120
|
+
# Gives the clock time for a fixed point in time. Independent of the current time.
|
|
121
|
+
# @param time [Numeric, Time] the value to convert to clock time
|
|
122
|
+
#
|
|
123
|
+
# @overload clock(timeout_at:)
|
|
124
|
+
# Gives the clock time for a fixed point in time. Independent of the current time.
|
|
125
|
+
# @param timeout_at [Numeric, Time] the value to convert to clock time
|
|
126
|
+
#
|
|
127
|
+
# @overload clock(delay:)
|
|
128
|
+
# Gives the clock time for a relative offset from the current time.
|
|
129
|
+
# @param delay [Numeric] the value to convert to clock time
|
|
130
|
+
#
|
|
131
|
+
# @overload clock(offset:)
|
|
132
|
+
# Gives the clock time for a relative offset from the current time.
|
|
133
|
+
# @param offset [Numeric] the value to convert to clock time
|
|
134
|
+
#
|
|
135
|
+
# @overload clock(timeout:)
|
|
136
|
+
# Gives the clock time for a relative offset from the current time.
|
|
137
|
+
# @param timeout [Numeric] the value to convert to clock time
|
|
138
|
+
#
|
|
139
|
+
# @overload clock(wait:)
|
|
140
|
+
# Gives the clock time for a relative offset from the current time.
|
|
141
|
+
# @param wait [Numeric] the value to convert to clock time
|
|
142
|
+
#
|
|
143
|
+
# @return [Float] monotonic clock time in seconds, from when clock was called the first time
|
|
144
|
+
def self.clock(...) = Clock.parse(...)
|
|
145
|
+
|
|
146
|
+
# Deduplicate values using the default {Deduper}.
|
|
147
|
+
# Cached values are held weakly, so retaining only an object_id does not keep
|
|
148
|
+
# its canonical object alive. Keep the returned object to preserve its identity.
|
|
149
|
+
#
|
|
150
|
+
# @overload dedup(object, copy: false, skip: nil)
|
|
151
|
+
# Reuse equal strings and frozen containers throughout an object graph.
|
|
152
|
+
# @example Preserve the input
|
|
153
|
+
# first = Farce.dedup(["foo"], copy: true)
|
|
154
|
+
# Farce.dedup(["foo"]).equal?(first) # => true
|
|
155
|
+
# @param object [Object] the root object
|
|
156
|
+
# @param copy [Boolean, Symbol] false to update the input, true to copy it,
|
|
157
|
+
# or a copy method such as :clone
|
|
158
|
+
# @param skip [Module, Array<Module>, nil] additional classes or modules to skip
|
|
159
|
+
# @return [Object] the deduplicated result
|
|
160
|
+
#
|
|
161
|
+
# @overload dedup
|
|
162
|
+
# Return the default deduper to configure subsequent calls.
|
|
163
|
+
# @example Exclude a class and its children
|
|
164
|
+
# Farce.dedup.skip(SomeClass)
|
|
165
|
+
# @example Cache another value class
|
|
166
|
+
# Farce.dedup.store(MyValue)
|
|
167
|
+
# @return [Deduper]
|
|
168
|
+
# @see Deduper#dedup
|
|
169
|
+
def self.dedup(object = UNDEFINED, **)
|
|
170
|
+
return DEDUPER if UNDEFINED.equal?(object)
|
|
171
|
+
DEDUPER.dedup(object, **)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# @overload enfarce(object, freeze: nil, mode: :copy)
|
|
175
|
+
# Converts vanilla Ruby objects into their {Farce} equivalents.
|
|
176
|
+
#
|
|
177
|
+
# @!macro modes
|
|
178
|
+
#
|
|
179
|
+
# @example
|
|
180
|
+
# Farce.enfarce({ foo: ["bar"] }) # => #<Farce::Map {foo: #<Farce::Vector ["bar"]>}>
|
|
181
|
+
#
|
|
182
|
+
# @yield [object] Optional block, called with any object that doesn't have a specific conversion defined.
|
|
183
|
+
# @yieldparam object [BasicObject] the object to convert
|
|
184
|
+
# @yieldreturn [BasicObject] the converted object
|
|
185
|
+
# @param object [BasicObject] The root object to convert
|
|
186
|
+
# @param freeze [Boolean, nil]
|
|
187
|
+
# Whether to freeze the converted objects.
|
|
188
|
+
# If set to `nil` (default), the freezing behavior will depend on the original object's frozen state.
|
|
189
|
+
# @param mode [Symbol] The conversion mode, e.g., `:copy`.
|
|
190
|
+
# @return [BasicObject] the converted object
|
|
191
|
+
# @see Farce::Local.enfarce
|
|
192
|
+
# @see Farce::Strict.enfarce
|
|
193
|
+
# @see Farce::Unsafe.enfarce
|
|
194
|
+
# @see Farce::Unshared.enfarce
|
|
195
|
+
def self.enfarce(object, **, &) = Internal::Converter.new(self, **, &).convert(object)
|
|
196
|
+
|
|
197
|
+
# Recursively freeze an object graph using {Walker} traversal.
|
|
198
|
+
#
|
|
199
|
+
# Visits container elements, hash keys and values, and instance variables.
|
|
200
|
+
# Shared children and cycles are preserved.
|
|
201
|
+
#
|
|
202
|
+
# Classes and modules are skipped by default. If it is enabled, then traversal visits
|
|
203
|
+
# instance variables, directly defined public constants, and directly defined class variables.
|
|
204
|
+
# Autoloads are skipped.
|
|
205
|
+
#
|
|
206
|
+
# Freezes objects in place and returns the original root. Already frozen
|
|
207
|
+
# objects are still traversed so their mutable children are frozen too.
|
|
208
|
+
#
|
|
209
|
+
# @example Freeze nested values in place
|
|
210
|
+
# values = { tags: [+"ruby"] }
|
|
211
|
+
# Farce.freeze_graph(values).equal?(values) # => true
|
|
212
|
+
# values[:tags].frozen? # => true
|
|
213
|
+
# values[:tags].first.frozen? # => true
|
|
214
|
+
#
|
|
215
|
+
# @example Freeze children of an already frozen container
|
|
216
|
+
# values = [+"ruby"].freeze
|
|
217
|
+
# Farce.freeze_graph(values).equal?(values) # => true
|
|
218
|
+
# values.first.frozen? # => true
|
|
219
|
+
#
|
|
220
|
+
# @example Freeze module state while allowing new methods
|
|
221
|
+
# mod = Module.new
|
|
222
|
+
# mod.instance_variable_set(:@tags, [+"ruby"])
|
|
223
|
+
# Farce.freeze_graph(mod, traverse_modules: true)
|
|
224
|
+
# mod.instance_variable_get(:@tags).first.frozen? # => true
|
|
225
|
+
# mod.frozen? # => false
|
|
226
|
+
#
|
|
227
|
+
# @param object [Object] the root object
|
|
228
|
+
# @param freeze_modules [Boolean] whether to freeze classes and modules
|
|
229
|
+
# @param traverse_modules [Boolean] whether to visit class and module instance
|
|
230
|
+
# variables. Defaults to `freeze_modules`, but can be set independently.
|
|
231
|
+
# @return [Object] the original root. Skipped modules retain their frozen state.
|
|
232
|
+
# @see Walker
|
|
233
|
+
def self.freeze_graph(object, freeze_modules: false, traverse_modules: freeze_modules)
|
|
234
|
+
Walker.visit(object) do |node, walker|
|
|
235
|
+
if Module === node
|
|
236
|
+
traverse = traverse_modules
|
|
237
|
+
freeze = freeze_modules
|
|
238
|
+
else
|
|
239
|
+
traverse = true
|
|
240
|
+
freeze = true
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
walker.traverse if traverse
|
|
244
|
+
node.freeze if freeze
|
|
245
|
+
node
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Binds a proc, lambda, block, bound or unbound method to a new self.
|
|
250
|
+
#
|
|
251
|
+
# This is similar to the following common approaches:
|
|
252
|
+
#
|
|
253
|
+
# 1. **`Ractor`**: using `Ractor.shareable_proc`/`Ractor.shareable_lambda`
|
|
254
|
+
# 2. **`BasicObject`**: using `#instance_exec`/`#instance_eval` (used by many DSLs, like Hanami or the dry-rb gems)
|
|
255
|
+
# 3. **`Module`**: using `#define_method` and method binding (used by many DSLs, like Sinatra or the money gem)
|
|
256
|
+
#
|
|
257
|
+
# Approach 2 and 3 are very popular for DSLs, but the resulting objects cannot be shared across ractors.
|
|
258
|
+
# The first approach fixes that, but only works on a limited number of procs and receivers, and is not available on
|
|
259
|
+
# all Ruby implementations.
|
|
260
|
+
#
|
|
261
|
+
# Property | `Ractor` | `BasicObject` | `Module` | `Farce`
|
|
262
|
+
# ------------------------------------|------------|---------------|---------------|----------
|
|
263
|
+
# Works with every proc | 🚫 **no** | ✅ yes | ✅ yes | ✅ yes
|
|
264
|
+
# Results can be made shareable | ✅ yes | 🚫 **no** | 🚫 **no** | ✅ yes
|
|
265
|
+
# Preserves parameters | ✅ yes | 🚫 **no** | ✅ yes | ✅ yes
|
|
266
|
+
# Procs can accept blocks | ✅ yes | 🚫 **no** | ✅ yes | ✅ yes
|
|
267
|
+
# Preserves lambda-ness | ⚠️ manually | 🚫 **no** | 🚫 **no** | ✅ yes
|
|
268
|
+
# Works on JRuby and TruffleRuby | 🚫 **no** | ✅ yes | ✅ yes | ✅ yes
|
|
269
|
+
# Performance overhead | ✅ none | ⚠️ up to 200% | ⚠️ up to 80% | ✅ none
|
|
270
|
+
#
|
|
271
|
+
# If you want the proc to also be shareable, use {Ractor.shareable_proc} instead.
|
|
272
|
+
#
|
|
273
|
+
# The performance overhead of `BasicObject#instance_exec`/`BasicObject#instance_eval` is the most significant on the
|
|
274
|
+
# official Ruby implementation, but is still present on JRuby, which does not exhibit a performance penalty for
|
|
275
|
+
# `Module#define_method`. On TruffleRuby, all approaches have similar performance. The more work is done inside
|
|
276
|
+
# the proc, the less significant the overhead becomes.
|
|
277
|
+
#
|
|
278
|
+
# @example
|
|
279
|
+
# # Rebinding a block to a new self
|
|
280
|
+
# callback = Farce.rebind(self: 42) { self * 10 }
|
|
281
|
+
# callback.call # => 420
|
|
282
|
+
#
|
|
283
|
+
# # Rebound procs preserve parameters and can accept blocks
|
|
284
|
+
# block = ->(key, &fallback) { fetch(key, &fallback) }
|
|
285
|
+
# rebound = Farce.rebind(block, self: { a: 1, b: 2 })
|
|
286
|
+
# rebound.call(:a) { 0 } # => 1
|
|
287
|
+
# rebound.call(:c) { 0 } # => 0
|
|
288
|
+
# rebound.parameters == block.parameters # => true
|
|
289
|
+
#
|
|
290
|
+
# # Rebinding an unbound method to a new self returns a bound method
|
|
291
|
+
# method = Object.instance_method(:inspect) # => #<UnboundMethod>
|
|
292
|
+
# method = Farce.rebind(method, self: 42) # => #<Method>
|
|
293
|
+
# method.receiver # => 42
|
|
294
|
+
# method.call # => "42"
|
|
295
|
+
#
|
|
296
|
+
# # lambda-ness is preserved
|
|
297
|
+
# Farce.rebind(proc {}).lambda? # => false
|
|
298
|
+
# Farce.rebind(lambda {}).lambda? # => true
|
|
299
|
+
#
|
|
300
|
+
# # If there is no binding change, identity is preserved
|
|
301
|
+
# Farce.rebind(&:to_s) == :to_s.to_proc # => true
|
|
302
|
+
#
|
|
303
|
+
# @overload rebind(self: nil, lambda: nil)
|
|
304
|
+
# @yield The block to bind to the new self.
|
|
305
|
+
# @yieldreceiver [BasicObject] The object passed as `self` (or `nil`)
|
|
306
|
+
# @param self [BasicObject] The new self to bind to.
|
|
307
|
+
# @return [Proc] The bound proc.
|
|
308
|
+
#
|
|
309
|
+
# @overload rebind(bindable, self: nil, lambda: nil)
|
|
310
|
+
# @param bindable [Proc, Method, UnboundMethod] The proc or method to bind to the new self.
|
|
311
|
+
# @param self [Object] The new self to bind to.
|
|
312
|
+
# @return [Proc, Method]
|
|
313
|
+
# The bound proc or method.
|
|
314
|
+
# A method is returned if the argument was a Method or UnboundMethod, otherwise a Proc is returned.
|
|
315
|
+
#
|
|
316
|
+
# @!macro rebind_lambda
|
|
317
|
+
# @param lambda [Boolean, nil]
|
|
318
|
+
# If true, a block-based proc will be converted to a lambda. If false to a non-lambda proc.
|
|
319
|
+
# If nil, the original lambda-ness will be preserved.
|
|
320
|
+
# Ignored for methods or procs not based on blocks (like `Symbol#to_proc`).
|
|
321
|
+
#
|
|
322
|
+
# @return [Proc, Method] The bound proc or method.
|
|
323
|
+
def self.rebind(bindable = nil, lambda: nil, **self_option, &block)
|
|
324
|
+
raise ArgumentError, "more than one block given" if bindable && block
|
|
325
|
+
raise ArgumentError, "tried to create Proc object without a block" unless bindable ||= block
|
|
326
|
+
new_self = Internal.self_option(self_option)
|
|
327
|
+
|
|
328
|
+
if bindable.is_a? Proc
|
|
329
|
+
return bindable if !Internal.rebindable?(bindable) || bindable.binding.receiver.equal?(new_self)
|
|
330
|
+
rebound = Internal.rebind(bindable, new_self, lambda)
|
|
331
|
+
rebound.freeze if bindable.frozen?
|
|
332
|
+
return rebound
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
if bindable.is_a? Method
|
|
336
|
+
return bindable if bindable.receiver.equal?(new_self)
|
|
337
|
+
bindable = bindable.unbind
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
return bindable.bind(new_self) if bindable.is_a? UnboundMethod
|
|
341
|
+
raise ArgumentError, "invalid bindable: #{bindable.inspect}"
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Allows executing code on the main ractor from other ractors.
|
|
345
|
+
# This allows modifying objects and calling methods only accessible from the main ractor.
|
|
346
|
+
#
|
|
347
|
+
# If a block is given, executes it on the main ractor, passing any given arguments to it.
|
|
348
|
+
# Blocks the current thread until the block has finished executing.
|
|
349
|
+
#
|
|
350
|
+
# Arguments are transferred based on the given mode.
|
|
351
|
+
#
|
|
352
|
+
# @!macro modes
|
|
353
|
+
#
|
|
354
|
+
# Calls from the main ractor execute directly, preserving the block and arguments.
|
|
355
|
+
#
|
|
356
|
+
# If no block is given, it returns a scheduler to execute tasks on the main ractor.
|
|
357
|
+
# This allows scheduling without blocking the current thread.
|
|
358
|
+
#
|
|
359
|
+
# On JRuby and TruffleRuby, blocks run inline because there is no native Ractor isolation.
|
|
360
|
+
# The returned {ThreadScheduler} starts a new thread for each scheduled task.
|
|
361
|
+
#
|
|
362
|
+
# @example
|
|
363
|
+
# $results = []
|
|
364
|
+
#
|
|
365
|
+
# Farce::Ractor.new do
|
|
366
|
+
# # maybe computing this string on the main ractor is too expensive?
|
|
367
|
+
# my_string = "foo bar baz"
|
|
368
|
+
#
|
|
369
|
+
# # can't access $results on the current ractor directly, as it isn't shareable
|
|
370
|
+
# Farce.on_main(my_string) { $results << it }
|
|
371
|
+
# end.join
|
|
372
|
+
#
|
|
373
|
+
# $results # => ["foo bar baz"]
|
|
374
|
+
#
|
|
375
|
+
# @example Blocking vs non-blocking
|
|
376
|
+
# Farce::Ractor.new do
|
|
377
|
+
# # This blocks the current thread until the block has finished executing.
|
|
378
|
+
# Farce.on_main do
|
|
379
|
+
# sleep 1
|
|
380
|
+
# puts "Hi from the main ractor!"
|
|
381
|
+
# end
|
|
382
|
+
#
|
|
383
|
+
# # This does not block the current thread.
|
|
384
|
+
# Farce.on_main.schedule do
|
|
385
|
+
# sleep 1
|
|
386
|
+
# puts "Hi again from the main ractor!"
|
|
387
|
+
# end
|
|
388
|
+
#
|
|
389
|
+
# puts "Hi from the current ractor!"
|
|
390
|
+
# end
|
|
391
|
+
#
|
|
392
|
+
# sleep 3 # Wait for all scheduled tasks to complete.
|
|
393
|
+
#
|
|
394
|
+
# # Expected output:
|
|
395
|
+
# # Hi from the main ractor!
|
|
396
|
+
# # Hi from the current ractor!
|
|
397
|
+
# # Hi again from the main ractor!
|
|
398
|
+
#
|
|
399
|
+
# @overload on_main(*args, mode: :copy)
|
|
400
|
+
# @param args [Array] The arguments to be passed to the block.
|
|
401
|
+
# @param mode [Symbol] The argument transfer mode when called from another ractor.
|
|
402
|
+
# @yield [*args] The block to be executed on the main ractor.
|
|
403
|
+
# @yieldparam [*args] The arguments passed to the block.
|
|
404
|
+
# @return [nil]
|
|
405
|
+
#
|
|
406
|
+
# @overload on_main
|
|
407
|
+
# Returns a scheduler that executes tasks on the main ractor.
|
|
408
|
+
# @return [Abstract::Scheduler]
|
|
409
|
+
#
|
|
410
|
+
# @return [Abstract::Scheduler, nil]
|
|
411
|
+
# @see .in_parallel
|
|
412
|
+
def self.on_main(*args, mode: UNDEFINED, &)
|
|
413
|
+
unless block_given?
|
|
414
|
+
raise LocalJumpError, "no block given" unless args.empty? && UNDEFINED.equal?(mode)
|
|
415
|
+
return Internal::MainScheduler
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
if Ractor.main?
|
|
419
|
+
yield(*args)
|
|
420
|
+
else
|
|
421
|
+
mode = :copy if UNDEFINED.equal?(mode)
|
|
422
|
+
Internal::MainScheduler.execute(*args, mode:, auto_local: false, &)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
nil
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# Schedules work without waiting for the block to finish.
|
|
429
|
+
# On CRuby, uses a shared Ractor pool with at most {System.cpu_count} workers.
|
|
430
|
+
# On JRuby and TruffleRuby, starts a new thread for each task.
|
|
431
|
+
#
|
|
432
|
+
# Without a block, returns the shared scheduler. The CRuby pool starts workers
|
|
433
|
+
# when tasks arrive. Pass mutable task data as arguments so it can be transferred based on the given mode.
|
|
434
|
+
#
|
|
435
|
+
# @!macro modes
|
|
436
|
+
#
|
|
437
|
+
# @example
|
|
438
|
+
# Farce.in_parallel("hello") { |message| puts message.upcase }
|
|
439
|
+
# Farce.in_parallel.schedule { puts "another task" }
|
|
440
|
+
#
|
|
441
|
+
# @overload in_parallel(*args, mode: :copy)
|
|
442
|
+
# @param args [Array<Object>] Arguments passed to the block.
|
|
443
|
+
# @param mode [Symbol] Argument transfer mode. Ignored on JRuby and TruffleRuby.
|
|
444
|
+
# @yield [*args] The task to schedule.
|
|
445
|
+
# @return [nil]
|
|
446
|
+
#
|
|
447
|
+
# @overload in_parallel
|
|
448
|
+
# @return [Abstract::Scheduler] The shared scheduler.
|
|
449
|
+
#
|
|
450
|
+
# @return [Abstract::Scheduler, nil]
|
|
451
|
+
# @see .on_main
|
|
452
|
+
def self.in_parallel(*args, mode: UNDEFINED, &)
|
|
453
|
+
unless block_given?
|
|
454
|
+
raise LocalJumpError, "no block given" unless args.empty? && UNDEFINED.equal?(mode)
|
|
455
|
+
return Internal::ParallelScheduler
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
mode = :copy if UNDEFINED.equal?(mode)
|
|
459
|
+
Internal::ParallelScheduler.schedule(*args, mode:, &)
|
|
460
|
+
nil
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# @overload schedule(*args, mode: :copy, auto_local: true, **kwargs)
|
|
464
|
+
# Schedules work to be executed out of band.
|
|
465
|
+
#
|
|
466
|
+
# If the `mode` is set to `:local`, it will use the current thread's fiber scheduler to schedule the task.
|
|
467
|
+
# If no fiber scheduler is available, it will create or reuse a Ractor-local scheduler (on the main Ractor,
|
|
468
|
+
# this is the same scheduler as {.on_main} uses).
|
|
469
|
+
#
|
|
470
|
+
# If `auto_local` is set to `true` (but with a different `mode`), the same logic is used as in local mode, except
|
|
471
|
+
# it will not create a new ractor-local scheduler if one is not already available.
|
|
472
|
+
#
|
|
473
|
+
# @example Scheduling work
|
|
474
|
+
# # just run this asynchronously, don't care how
|
|
475
|
+
# Farce.schedule("hello") { |message| puts message.upcase }
|
|
476
|
+
#
|
|
477
|
+
# @example Using a fiber scheduler
|
|
478
|
+
# Async do
|
|
479
|
+
# # this is basically the same as calling Async { do_something }
|
|
480
|
+
# Farce.schedule { do_something }
|
|
481
|
+
# end
|
|
482
|
+
#
|
|
483
|
+
# @param args [Array<Object>] Arguments passed to the block.
|
|
484
|
+
# @param mode [Symbol] Argument transfer mode. Ignored on JRuby and TruffleRuby.
|
|
485
|
+
# @param auto_local [Boolean] Whether to automatically use the local scheduler if available.
|
|
486
|
+
# @param kwargs [Hash] Additional keyword arguments passed to the scheduler.
|
|
487
|
+
# @yield [*args] The task to schedule.
|
|
488
|
+
# @return [nil]
|
|
489
|
+
def self.schedule(*, mode: :copy, auto_local: true, **, &)
|
|
490
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
491
|
+
|
|
492
|
+
if auto_local || mode == :local
|
|
493
|
+
if Fiber.respond_to?(:scheduler) && fiber_scheduler = Fiber.scheduler
|
|
494
|
+
fiber_scheduler.fiber(**) { yield(*) }
|
|
495
|
+
return
|
|
496
|
+
end
|
|
497
|
+
scheduler = Ractor.main? ? Internal::MainScheduler : Internal::Storage[:local_scheduler]
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
scheduler ||=
|
|
501
|
+
if mode == :local
|
|
502
|
+
Internal::Storage.store_if_absent(:local_scheduler) do
|
|
503
|
+
Internal.native_ractors? ? Scheduler.create(Thread) : ThreadScheduler.new
|
|
504
|
+
end
|
|
505
|
+
else
|
|
506
|
+
Internal::ParallelScheduler
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
scheduler.schedule(*, mode:, auto_local:, **, &)
|
|
510
|
+
nil
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def self.append_features(mod) = Internal::Mixin.__send__(:append_features, mod)
|
|
514
|
+
def self.included(mod) = Internal::Mixin.__send__(:included, mod)
|
|
515
|
+
private_class_method :append_features, :included
|
|
516
|
+
|
|
517
|
+
Integrations.setup
|
|
518
|
+
Internal.finalize_engine
|
|
519
|
+
end
|