farce 0 → 0.1.0
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1525 -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/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/vault.rb +56 -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/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 +435 -8
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
# @!group WeakRef Integration
|
|
6
|
+
require "farce" unless defined?(Farce::Walker)
|
|
7
|
+
require "weakref" unless defined?(WeakRef)
|
|
8
|
+
|
|
9
|
+
module Farce
|
|
10
|
+
# Traverse the live referent. Collected references have no children.
|
|
11
|
+
Walker.define(::WeakRef) do |object, walker|
|
|
12
|
+
value = begin
|
|
13
|
+
object.__getobj__
|
|
14
|
+
rescue ::WeakRef::RefError
|
|
15
|
+
next object
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
walker.update(object, [value]) do |target, results|
|
|
19
|
+
# WeakRef has no setter, so replacement values need a new reference.
|
|
20
|
+
target.class.new(results.first)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Internal::Converter.define(::WeakRef, WeakRef) do
|
|
25
|
+
def convert!(ref)
|
|
26
|
+
@seen.fetch(ref) do
|
|
27
|
+
begin
|
|
28
|
+
value = ref.__getobj__
|
|
29
|
+
rescue ::WeakRef::RefError
|
|
30
|
+
next @seen[ref] = Farce::WeakRef::RECYCLED
|
|
31
|
+
end
|
|
32
|
+
converted = convert(value)
|
|
33
|
+
# Return new values directly so they have a strong owner.
|
|
34
|
+
@seen[ref] = converted.equal?(value) ? Farce::WeakRef.new(converted) : converted
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
# @!group Yajl Integration
|
|
6
|
+
# Yajl 1.4.3 cannot encode or parse inside non-main native Ractors.
|
|
7
|
+
require "farce"
|
|
8
|
+
require "yajl" unless defined?(Yajl::Encoder)
|
|
9
|
+
require "json" unless [].respond_to?(:to_json)
|
|
10
|
+
require_relative "shared/to_json"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @api private
|
|
7
|
+
module Integrations
|
|
8
|
+
# Dependency entry points, ending with the feature that activates each integration.
|
|
9
|
+
INTEGRATIONS = {
|
|
10
|
+
active_support: %w[active_support active_support/core_ext].freeze,
|
|
11
|
+
bson: %w[bson].freeze,
|
|
12
|
+
cbor: %w[cbor].freeze,
|
|
13
|
+
dry_types: %w[dry/types].freeze,
|
|
14
|
+
concurrent: %w[concurrent/map concurrent/tvar concurrent].freeze,
|
|
15
|
+
json: %w[json].freeze,
|
|
16
|
+
msgpack: %w[msgpack].freeze,
|
|
17
|
+
psych: %w[psych].freeze,
|
|
18
|
+
oj: %w[oj].freeze,
|
|
19
|
+
sorted_set: %w[sorted_set].freeze,
|
|
20
|
+
weakref: %w[weakref].freeze,
|
|
21
|
+
yajl: %w[yajl].freeze,
|
|
22
|
+
ractor_tmvar: %w[ractor/tvar ractor/tmvar].freeze,
|
|
23
|
+
ractor_sharing: %w[
|
|
24
|
+
ractor/tvar
|
|
25
|
+
ractor/lockvar
|
|
26
|
+
ractor/lockhash
|
|
27
|
+
ractor/keylockhash
|
|
28
|
+
ractor/active_object
|
|
29
|
+
ractor/actor_hash
|
|
30
|
+
ractor/sharing
|
|
31
|
+
].freeze,
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
PATHS = INTEGRATIONS.to_h { [_2.last, _1] }.merge(
|
|
35
|
+
"concurrent/tvar" => :concurrent,
|
|
36
|
+
"ractor/tvar" => :ractor_sharing,
|
|
37
|
+
"oj/json" => :oj,
|
|
38
|
+
"yajl/json_gem" => :yajl,
|
|
39
|
+
).freeze
|
|
40
|
+
|
|
41
|
+
# Zeitwerk aliases Kernel#require. Prepending there can leave the aliased
|
|
42
|
+
# wrapper without a valid super target on TruffleRuby. Define the instance
|
|
43
|
+
# hook above Object so Kernel#require remains available for those aliases
|
|
44
|
+
# and Ruby's Ractor-aware Object#require stays in the lookup chain.
|
|
45
|
+
module RequireHook
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# Load a feature and its integration while preserving require's result.
|
|
49
|
+
# @param path [String, #to_path] The feature to load.
|
|
50
|
+
# @return [Boolean] Whether the requested feature was newly loaded.
|
|
51
|
+
def require(path, ...)
|
|
52
|
+
path = File.path(path)
|
|
53
|
+
result = Integrations.loading(path) { super }
|
|
54
|
+
integration = PATHS[path.delete_suffix(".rb")]
|
|
55
|
+
if integration && !Integrations.loading?(integration) && Farce.config.autoload_integrations
|
|
56
|
+
integration_path = "farce/integrations/#{integration}"
|
|
57
|
+
Integrations.loading(integration_path) { super(integration_path) }
|
|
58
|
+
end
|
|
59
|
+
result
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
private_constant :RequireHook
|
|
63
|
+
|
|
64
|
+
# A prepended singleton hook can recurse when Zeitwerk aliases it. Preserve
|
|
65
|
+
# the original method explicitly instead of relying on super here.
|
|
66
|
+
class << Kernel
|
|
67
|
+
alias farce_original_require require
|
|
68
|
+
private :farce_original_require
|
|
69
|
+
|
|
70
|
+
# Load a feature and its integration through Kernel.require.
|
|
71
|
+
# @api private
|
|
72
|
+
# @param path [String, #to_path] The feature to load.
|
|
73
|
+
# @return [Boolean] Whether the requested feature was newly loaded.
|
|
74
|
+
def require(path, ...)
|
|
75
|
+
path = File.path(path)
|
|
76
|
+
result = Integrations.loading(path) { farce_original_require(path, ...) }
|
|
77
|
+
integration = PATHS[path.delete_suffix(".rb")]
|
|
78
|
+
if integration && !Integrations.loading?(integration) && Farce.config.autoload_integrations
|
|
79
|
+
integration_path = "farce/integrations/#{integration}"
|
|
80
|
+
Integrations.loading(integration_path) { farce_original_require(integration_path) }
|
|
81
|
+
end
|
|
82
|
+
result
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private_constant :INTEGRATIONS, :PATHS
|
|
87
|
+
|
|
88
|
+
extend self
|
|
89
|
+
|
|
90
|
+
# Avoid requiring an integration again while it loads its own dependencies.
|
|
91
|
+
# @api private
|
|
92
|
+
def loading(path)
|
|
93
|
+
return yield unless path.start_with?("farce/integrations/")
|
|
94
|
+
previous = Thread.current[:farce_loading_integration]
|
|
95
|
+
Thread.current[:farce_loading_integration] = path.delete_prefix("farce/integrations/").delete_suffix(".rb").to_sym
|
|
96
|
+
begin
|
|
97
|
+
yield
|
|
98
|
+
ensure
|
|
99
|
+
Thread.current[:farce_loading_integration] = previous
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @api private
|
|
104
|
+
def loading?(integration) = Thread.current[:farce_loading_integration] == integration
|
|
105
|
+
|
|
106
|
+
# Activate integrations at startup when automatic loading is enabled.
|
|
107
|
+
# @api private
|
|
108
|
+
def setup
|
|
109
|
+
Object.prepend(RequireHook)
|
|
110
|
+
load_active if Farce.config.autoload_integrations
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Loads all integrations for gems that have already been loaded.
|
|
114
|
+
# @return [Array<Symbol>] the list of integrations that were loaded
|
|
115
|
+
# @!scope class
|
|
116
|
+
def load_active
|
|
117
|
+
result = []
|
|
118
|
+
INTEGRATIONS.each_key do |integration|
|
|
119
|
+
next unless loaded?("farce/integrations/#{integration}") ||
|
|
120
|
+
PATHS.any? { |path, target| target == integration && loaded?(path) }
|
|
121
|
+
require "farce/integrations/#{integration}"
|
|
122
|
+
result << integration
|
|
123
|
+
end
|
|
124
|
+
result
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Attempts to load all available integrations.
|
|
128
|
+
# If the integration could be loaded, it will be included in the result.
|
|
129
|
+
# @return [Array<Symbol>] the list of integrations that were loaded
|
|
130
|
+
# @!scope class
|
|
131
|
+
def load_available
|
|
132
|
+
result = []
|
|
133
|
+
INTEGRATIONS.each do |integration, require_paths|
|
|
134
|
+
next unless try_require("farce/integrations/#{integration}", *require_paths)
|
|
135
|
+
result << integration
|
|
136
|
+
end
|
|
137
|
+
result
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def loaded?(path)
|
|
143
|
+
path = "#{path}.rb" unless path.end_with?(".rb")
|
|
144
|
+
paths = $LOAD_PATH.map { File.expand_path(path, it) }
|
|
145
|
+
paths.any? { $LOADED_FEATURES.include?(it) }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def try_require(path, *ignore)
|
|
149
|
+
require path
|
|
150
|
+
true
|
|
151
|
+
rescue LoadError => e
|
|
152
|
+
raise e unless e.path == path || ignore.include?(e.path)
|
|
153
|
+
false
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal # :nodoc: all
|
|
7
|
+
# Autoload runs on the main Ractor, where CONFIG can still be accessed before
|
|
8
|
+
# freezing. Keep this lazy so requiring Farce leaves configuration mutable.
|
|
9
|
+
FROZEN_CONFIG = CONFIG.freeze
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
# @!visibility private
|
|
9
|
+
module Autoloads
|
|
10
|
+
def self.[](*, **)
|
|
11
|
+
Module.new do
|
|
12
|
+
define_singleton_method(:append_features) do |namespace|
|
|
13
|
+
Autoloads.define(namespace, *, **)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
SEGMENTS = { "io" => "IO", "lru" => "LRU", "lfu" => "LFU" }.freeze
|
|
19
|
+
private_constant :SEGMENTS
|
|
20
|
+
|
|
21
|
+
def self.inflect(name, **inflections)
|
|
22
|
+
name.split(%r{::|/}).map do |part|
|
|
23
|
+
next if part.empty?
|
|
24
|
+
inflections.fetch(part.to_sym) { part.split("_").map { SEGMENTS.fetch(it, it.sub(/^./, &:upcase)) }.join }
|
|
25
|
+
end.compact.join("::")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.define(namespace, path = nil, skip: nil, **)
|
|
29
|
+
path ||= namespace.name.gsub(/([a-z])([A-Z])/, "\\1_\\2").gsub("::", "/").downcase
|
|
30
|
+
path = File.expand_path(path, "#{__dir__}/../..")
|
|
31
|
+
skip = ::Set[*skip]
|
|
32
|
+
|
|
33
|
+
skip.map!(&:to_s)
|
|
34
|
+
|
|
35
|
+
Dir.glob("#{path}/*.rb").each do |file|
|
|
36
|
+
base_name = File.basename(file, ".rb")
|
|
37
|
+
next if base_name.start_with?("_") || base_name.start_with?(".") || skip.include?(base_name)
|
|
38
|
+
const_name = inflect(base_name, **)
|
|
39
|
+
next if namespace.const_defined?(const_name, false) || $LOADED_FEATURES.include?(file)
|
|
40
|
+
namespace.autoload(const_name, file)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.append_features(namespace) = define(namespace)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
# Shared blocking wrapper behavior for the public priority-based queues.
|
|
9
|
+
module BlockingPriorityQueue
|
|
10
|
+
# Remove all values and wake waiters.
|
|
11
|
+
def clear
|
|
12
|
+
internal_queue.clear
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Close the queue and wake waiters.
|
|
17
|
+
def close
|
|
18
|
+
internal_queue.close
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Stop new pushes and close after the final value is removed.
|
|
23
|
+
def seal
|
|
24
|
+
internal_queue.seal
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Wait until capacity is available without adding a value.
|
|
29
|
+
def wait_push(timeout: nil)
|
|
30
|
+
raise_unwritable if sealed?
|
|
31
|
+
return true unless capacity
|
|
32
|
+
|
|
33
|
+
wait(timeout) do
|
|
34
|
+
raise_unwritable if sealed?
|
|
35
|
+
size < capacity
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The approximate number of waiting execution contexts.
|
|
40
|
+
def num_waiting = internal_signal.num_waiting
|
|
41
|
+
|
|
42
|
+
Internal.delegate(
|
|
43
|
+
self, :internal_queue, :age_tracking?, :capacity, :closed?, :empty?, :generation,
|
|
44
|
+
:oldest_age, :oldest_enqueued_at, :sealed?, :size,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def initialize_copy(_other)
|
|
50
|
+
raise TypeError, "priority queues cannot be copied"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def initialize(capacity:, reverse_order: false, track_age: false)
|
|
54
|
+
@reverse_order = reverse_order
|
|
55
|
+
@signal = queue_signal
|
|
56
|
+
@queue = queue_storage_class.new(capacity:, signal: internal_signal, track_age:)
|
|
57
|
+
super()
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def internal_signal = @signal
|
|
61
|
+
|
|
62
|
+
def queue_storage_class = Internal::PriorityQueue
|
|
63
|
+
def queue_signal = Signal.new
|
|
64
|
+
|
|
65
|
+
def delete_from_storage(priority, value, compare_by_identity:)
|
|
66
|
+
if compare_by_identity
|
|
67
|
+
internal_queue.delete_identity(priority, value)
|
|
68
|
+
else
|
|
69
|
+
internal_queue.delete(priority, value)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def push_to_storage(priority, non_block, value, timeout:)
|
|
74
|
+
deadline = timeout_at(timeout) unless timeout.nil?
|
|
75
|
+
|
|
76
|
+
while true
|
|
77
|
+
return true if internal_queue.push(priority, value)
|
|
78
|
+
raise ThreadError, "queue full" if non_block
|
|
79
|
+
return false unless wait_push(timeout: remaining_timeout(deadline))
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def normalize_timeout(timeout)
|
|
84
|
+
return nil if timeout.nil?
|
|
85
|
+
|
|
86
|
+
timeout = Float(timeout)
|
|
87
|
+
raise ArgumentError, "timeout must be non-negative" if timeout.negative?
|
|
88
|
+
raise ArgumentError, "timeout must be finite" unless timeout.finite?
|
|
89
|
+
raise ArgumentError, "timeout must be a number" if timeout.nan?
|
|
90
|
+
|
|
91
|
+
timeout
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def wait(timeout)
|
|
95
|
+
deadline = timeout_at(timeout)
|
|
96
|
+
|
|
97
|
+
while true
|
|
98
|
+
generation = internal_signal.generation
|
|
99
|
+
raise ::Farce::ClosedQueueError, "queue is closed" if closed?
|
|
100
|
+
return true if yield
|
|
101
|
+
return false unless internal_signal.wait(generation, timeout: remaining_timeout(deadline))
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def raise_unwritable
|
|
106
|
+
closed = closed?
|
|
107
|
+
error = closed ? ::Farce::ClosedQueueError : ::Farce::SealedQueueError
|
|
108
|
+
raise error, closed ? "queue is closed" : "queue is sealed"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def timeout_at(timeout)
|
|
112
|
+
Clock.timeout(normalize_timeout(timeout)) unless timeout.nil?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def remaining_timeout(timeout_at)
|
|
116
|
+
return unless timeout_at
|
|
117
|
+
timeout = timeout_at - Clock.now
|
|
118
|
+
timeout.positive? ? timeout : 0
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
class Converter
|
|
9
|
+
class Factory
|
|
10
|
+
class << self
|
|
11
|
+
attr_writer :target_name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.target_name
|
|
15
|
+
return @target_name if defined?(@target_name) && @target_name
|
|
16
|
+
superclass.target_name if superclass.respond_to?(:target_name)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :target_class, :namespace, :options, :converter
|
|
20
|
+
|
|
21
|
+
def initialize(converter)
|
|
22
|
+
@converter = converter
|
|
23
|
+
@namespace = converter.namespace
|
|
24
|
+
@options = converter.options
|
|
25
|
+
@seen = {}.compare_by_identity
|
|
26
|
+
|
|
27
|
+
case target_name = self.class.target_name
|
|
28
|
+
when Symbol, String then @target_class = @namespace.const_get(target_name)
|
|
29
|
+
when Class then @target_class = target_name
|
|
30
|
+
else raise TypeError, "Unsupported target name: #{target_name.inspect}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def convert(value) = @converter.convert(value)
|
|
35
|
+
|
|
36
|
+
def convert!(value)
|
|
37
|
+
@seen.fetch(value) do
|
|
38
|
+
instance = @seen[value] = prepare(value)
|
|
39
|
+
apply(instance, value)
|
|
40
|
+
yield instance
|
|
41
|
+
instance
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def prepare(_, **) = @target_class.new(**, **@options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
REGISTER = ClassMirror.new(Factory)
|
|
49
|
+
private_constant :REGISTER
|
|
50
|
+
|
|
51
|
+
def self.define(klass, target_name, &block)
|
|
52
|
+
if block && block.arity != 0
|
|
53
|
+
definition = Internal.prepare_method_definition(&block)
|
|
54
|
+
block = proc { define_method(:apply, &definition) }
|
|
55
|
+
end
|
|
56
|
+
factory_class = REGISTER.define(klass, &block)
|
|
57
|
+
factory_class.target_name = target_name
|
|
58
|
+
factory_class
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
define(Hash, :Map) do
|
|
62
|
+
def apply(instance, value) = value.each { instance[_1] = convert(_2) }
|
|
63
|
+
|
|
64
|
+
def prepare(value, **)
|
|
65
|
+
return super unless value.compare_by_identity?
|
|
66
|
+
super(value, compare_keys_by_identity: true, **)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
define(Array, :Vector) { |instance, value| value.each { instance << convert(it) } }
|
|
71
|
+
|
|
72
|
+
define(::Set, :Set) do
|
|
73
|
+
def apply(instance, value) = value.each { instance << convert(it) }
|
|
74
|
+
|
|
75
|
+
def prepare(value, **)
|
|
76
|
+
return super unless value.compare_by_identity?
|
|
77
|
+
super(value, compare_by_identity: true, **)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
define(ObjectSpace::WeakMap, :WeakMap) do
|
|
82
|
+
def apply(instance, value) = value.each { instance[_1] = convert(_2) }
|
|
83
|
+
def prepare(value, **) = super(value, compare_keys_by_identity: true, **)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
attr_reader :options, :namespace
|
|
87
|
+
|
|
88
|
+
def initialize(namespace, freeze: nil, **options, &callback)
|
|
89
|
+
@namespace = namespace
|
|
90
|
+
@options = options
|
|
91
|
+
@freeze = freeze
|
|
92
|
+
@factories = {}
|
|
93
|
+
@callback = callback
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def convert(value)
|
|
97
|
+
factory_class = REGISTER[value.class]
|
|
98
|
+
return @callback ? @callback.call(value) : value unless factory_class.target_name
|
|
99
|
+
factory = @factories[factory_class] ||= factory_class.new(self)
|
|
100
|
+
factory.convert!(value) do |result|
|
|
101
|
+
result.freeze if @freeze.nil? ? value.frozen? : @freeze
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal
|
|
7
|
+
# Preserve the publication guarantees of public shareable wrappers.
|
|
8
|
+
module Copyable
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def initialize_dup(other)
|
|
12
|
+
super
|
|
13
|
+
publish_copy(other, operation: :dup) if is_a?(Shareable)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize_clone(other, freeze: nil)
|
|
17
|
+
super
|
|
18
|
+
publish_copy(other, operation: :clone, freeze:) if is_a?(Shareable)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def publish_copy(other, operation:, freeze: nil)
|
|
22
|
+
if respond_to?(:publish_shareable_copy, true)
|
|
23
|
+
publish_shareable_copy(other, operation:, freeze:)
|
|
24
|
+
elsif operation == :dup || freeze != false
|
|
25
|
+
Ractor.make_shareable(self) if Internal.native_ractors?
|
|
26
|
+
self.freeze
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal
|
|
7
|
+
# Mixin to have some BasicObject methods still trigger method_missing
|
|
8
|
+
# Notable exceptions: #equal?, #__send__, #__id__
|
|
9
|
+
module Delegation
|
|
10
|
+
def ==(other) = method_missing(:==, other)
|
|
11
|
+
def ! = method_missing(:!)
|
|
12
|
+
def instance_eval(...) = method_missing(:instance_eval, ...)
|
|
13
|
+
def instance_exec(...) = method_missing(:instance_exec, ...)
|
|
14
|
+
|
|
15
|
+
def !=(other)
|
|
16
|
+
method_missing(:!=, other)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal # :nodoc: all
|
|
7
|
+
# Own portable locks while native participants hold logical reservations.
|
|
8
|
+
# Portable replacements remain hidden until the foreign commit is resolved.
|
|
9
|
+
class ExternalTransaction
|
|
10
|
+
def self.commit(entries, external, guards, transaction)
|
|
11
|
+
groups = external.map(&:commit_group).uniq
|
|
12
|
+
raise TypeError, "only one external commit integration may participate" unless groups.size == 1
|
|
13
|
+
|
|
14
|
+
native, portable = entries.partition { NativeTransactionEntry === it }
|
|
15
|
+
context = new(portable, guards, groups.first.new(external), transaction)
|
|
16
|
+
flags = guards.map { it.respond_to?(:native_flag) ? it.native_flag : it }
|
|
17
|
+
Internal.reserve_transaction(native, flags, context)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(entries, guards, group, transaction)
|
|
21
|
+
@entries, @guards, @group, @transaction = entries, guards, group, transaction
|
|
22
|
+
@acquired = []
|
|
23
|
+
@attempted = nil
|
|
24
|
+
@entries.each(&:prepare)
|
|
25
|
+
@locks = (@entries.flat_map(&:locks) + @guards.filter_map { it.lock if it.respond_to?(:native_flag) })
|
|
26
|
+
.uniq.sort_by(&:object_id)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def acquire?
|
|
30
|
+
@locks.each do |lock|
|
|
31
|
+
return false if lock.owned?
|
|
32
|
+
@attempted = lock
|
|
33
|
+
return false unless lock.try_lock
|
|
34
|
+
@acquired << lock
|
|
35
|
+
@attempted = nil
|
|
36
|
+
end
|
|
37
|
+
@guards.none?(&:value) && @entries.all?(&:valid?)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def publish_external
|
|
41
|
+
@entries.each { it.reserve if it.respond_to?(:reserve) }
|
|
42
|
+
@entries.each(&:apply)
|
|
43
|
+
@group.commit
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def committed? = @group.committed?
|
|
47
|
+
def restore = @entries.reverse_each(&:restore)
|
|
48
|
+
|
|
49
|
+
# Repeatable even if a return TracePoint interrupted a completed unlock.
|
|
50
|
+
def finish
|
|
51
|
+
@entries.each { it.unreserve if it.respond_to?(:unreserve) }
|
|
52
|
+
[*@acquired, @attempted].compact.uniq.reverse_each do |lock|
|
|
53
|
+
lock.unlock if lock.owned?
|
|
54
|
+
end
|
|
55
|
+
@entries.each(&:notify) if committed?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|