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,229 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# Map operations that return independent maps of the same kind.
|
|
8
|
+
# Include this in subclasses of {Map} that support copying.
|
|
9
|
+
# Operations work on an independent copy, not an atomic snapshot of the source.
|
|
10
|
+
# Local copies transform the current scope and retain constructor defaults for other scopes.
|
|
11
|
+
module DuplicableMap
|
|
12
|
+
# Return an independent map containing only the requested keys that exist.
|
|
13
|
+
# @param keys [Array<BasicObject>] keys to retain, using the map's lookup rules
|
|
14
|
+
# @return [Map] A map of the same class with the same settings.
|
|
15
|
+
def slice(*keys)
|
|
16
|
+
with_map_copy do |_, map|
|
|
17
|
+
retained = {}.compare_by_identity
|
|
18
|
+
keys.each do |key|
|
|
19
|
+
key = normalize_copied_key(key)
|
|
20
|
+
retained[map.getkey(key)] = true if map.key?(key)
|
|
21
|
+
end
|
|
22
|
+
# Tree backends expose each, but not each_key.
|
|
23
|
+
map.each { |key, _| map.delete(key) unless retained.key?(key) } # rubocop:disable Style/HashEachMethods
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Return an independent map without the requested keys.
|
|
28
|
+
# @param keys [Array<BasicObject>] keys to omit, using the map's lookup rules
|
|
29
|
+
# @return [Map] A map of the same class with the same settings.
|
|
30
|
+
def except(*keys)
|
|
31
|
+
with_map_copy do |_, map|
|
|
32
|
+
keys.each { map.delete(normalize_copied_key(it)) }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Return an independent map without entries whose value is nil. False values are retained.
|
|
37
|
+
# @return [Map] A map of the same class with the same settings.
|
|
38
|
+
def compact
|
|
39
|
+
with_map_copy do |copy, map|
|
|
40
|
+
nil_value = copy.wrap_value(nil)
|
|
41
|
+
map.each { |key, value| map.delete(key) if nil_value.equal?(value) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Return an independent map containing entries accepted by the block.
|
|
46
|
+
# The block receives public values from the copy. Stored values and map settings are preserved.
|
|
47
|
+
# @yieldparam key [BasicObject] an existing key
|
|
48
|
+
# @yieldparam value [BasicObject] the public value
|
|
49
|
+
# @return [Map, Enumerator] A map of the same class, or an Enumerator without a block.
|
|
50
|
+
def select
|
|
51
|
+
return enum_for(__method__) { size } unless block_given?
|
|
52
|
+
with_map_copy do |copy, map|
|
|
53
|
+
map.each { |key, value| map.delete(key) unless yield(key, copy.unwrap_value(value)) }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
alias filter select
|
|
57
|
+
|
|
58
|
+
# Return an independent map excluding entries accepted by the block.
|
|
59
|
+
# The block receives public values from the copy. Stored values and map settings are preserved.
|
|
60
|
+
# @yieldparam key [BasicObject] an existing key
|
|
61
|
+
# @yieldparam value [BasicObject] the public value
|
|
62
|
+
# @return [Map, Enumerator] A map of the same class, or an Enumerator without a block.
|
|
63
|
+
def reject
|
|
64
|
+
return enum_for(__method__) { size } unless block_given?
|
|
65
|
+
with_map_copy do |copy, map|
|
|
66
|
+
map.each { |key, value| map.delete(key) if yield(key, copy.unwrap_value(value)) }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Return an independent map with transformed keys and unchanged stored values.
|
|
71
|
+
# Mapping entries take precedence over the block. Unmapped keys are retained when no block is given.
|
|
72
|
+
# Transformed keys pass through this map's normalizer. On collisions, the last visited entry wins.
|
|
73
|
+
# Bounded copies rebuild eviction history as transformed entries are inserted.
|
|
74
|
+
# @param mapping [Hash, #to_hash] optional replacements for existing keys
|
|
75
|
+
# @yieldparam key [BasicObject] an existing key
|
|
76
|
+
# @yieldreturn [BasicObject] the replacement key
|
|
77
|
+
# @return [Map, Enumerator] A map of the same class, or an Enumerator without a mapping or block.
|
|
78
|
+
def transform_keys(mapping = UNDEFINED)
|
|
79
|
+
if UNDEFINED.equal?(mapping)
|
|
80
|
+
return enum_for(__method__, mapping) { size } unless block_given?
|
|
81
|
+
mapping = nil
|
|
82
|
+
else
|
|
83
|
+
mapping = Hash.try_convert(mapping) || raise(TypeError, "mapping must be a Hash or respond to #to_hash")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
with_map_copy(empty: true) do |_, map|
|
|
87
|
+
internal_map.each do |key, value|
|
|
88
|
+
if mapping&.key?(key)
|
|
89
|
+
key = normalize_copied_key(mapping.fetch(key))
|
|
90
|
+
elsif block_given?
|
|
91
|
+
key = normalize_copied_key(yield(key))
|
|
92
|
+
end
|
|
93
|
+
map[key] = value
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Return an independent map with transformed values and unchanged keys.
|
|
99
|
+
# Results follow the map's transfer mode. Move-mode results are copied before transfer to preserve the source.
|
|
100
|
+
# Bounded copies count replacements as writes. The source's eviction history is unchanged.
|
|
101
|
+
# @yieldparam value [BasicObject] the current value
|
|
102
|
+
# @yieldreturn [BasicObject] the replacement value
|
|
103
|
+
# @return [Map, Enumerator] A map of the same class, or an Enumerator without a block.
|
|
104
|
+
def transform_values
|
|
105
|
+
return enum_for(__method__) { size } unless block_given?
|
|
106
|
+
copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move
|
|
107
|
+
with_map_copy do |copy, map|
|
|
108
|
+
map.each do |key, value|
|
|
109
|
+
value = yield copy.unwrap_value(value)
|
|
110
|
+
value = copier.unwrap(copier.wrap(value)) if copier
|
|
111
|
+
map[key] = copy.wrap_value(value)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Return an independent map with keys and values exchanged.
|
|
117
|
+
# New keys follow the map's normal key normalization and shareability rules.
|
|
118
|
+
# On collisions, the last visited entry wins. Bounded copies rebuild eviction history.
|
|
119
|
+
# @return [Map] A map of the same class with the same settings.
|
|
120
|
+
# @raise [Ractor::IsolationError] if a new key violates the map's shareability rules
|
|
121
|
+
def invert
|
|
122
|
+
copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move
|
|
123
|
+
empty_copy.tap do |copy|
|
|
124
|
+
each_pair do |key, value|
|
|
125
|
+
key = copier.unwrap(copier.wrap(key)) if copier
|
|
126
|
+
copy[value] = key
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Return an independent map with entries from each input applied in order.
|
|
132
|
+
# Incoming keys pass through the normalizer. A block resolves collisions using the canonical key.
|
|
133
|
+
# Move-mode values are copied before transfer to preserve the source and inputs.
|
|
134
|
+
# Bounded copies retain eviction history and apply their usual capacity limits to new writes.
|
|
135
|
+
# @param others [Array<Map, Hash, #to_hash>] maps to merge, with later entries taking precedence
|
|
136
|
+
# @yieldparam key [BasicObject] the canonical key shared by both maps
|
|
137
|
+
# @yieldparam old_value [BasicObject] the current value in the result
|
|
138
|
+
# @yieldparam new_value [BasicObject] the incoming value
|
|
139
|
+
# @yieldreturn [BasicObject] the replacement value
|
|
140
|
+
# @return [Map] A map of the same class with the same settings.
|
|
141
|
+
def merge(*others)
|
|
142
|
+
copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move
|
|
143
|
+
with_map_copy do |copy, map|
|
|
144
|
+
others.each do |other|
|
|
145
|
+
unless Map === other
|
|
146
|
+
other = Hash.try_convert(other) || raise(TypeError, "input must be a Map, Hash, or respond to #to_hash")
|
|
147
|
+
end
|
|
148
|
+
other.each_pair do |key, value|
|
|
149
|
+
key = normalize_copied_key(key)
|
|
150
|
+
value = yield(key, copy.unwrap_value(map[key]), value) if block_given? && map.key?(key)
|
|
151
|
+
value = copier.unwrap(copier.wrap(value)) if copier
|
|
152
|
+
map[key] = copy.wrap_value(value)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Return a lambda that looks up a key using this map's current contents and lookup rules.
|
|
159
|
+
# The lambda is Ractor-shareable when this map is Ractor-shareable.
|
|
160
|
+
# @return [Proc] A one-argument lookup lambda.
|
|
161
|
+
def to_proc
|
|
162
|
+
lookup = ->(key) { self[key] }
|
|
163
|
+
Ractor.shareable?(self) ? Ractor.shareable_lambda(self: self, &lookup) : lookup
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Return keys and values in a flattened Array.
|
|
167
|
+
# The default depth flattens entry pairs. Zero preserves pairs, and negative depths flatten all levels.
|
|
168
|
+
# @param level [Integer, #to_int] the number of Array levels to flatten
|
|
169
|
+
# @return [Array] The flattened entries.
|
|
170
|
+
def flatten(level = 1)
|
|
171
|
+
level = Integer.try_convert(level) || raise(TypeError, "level must be an Integer or respond to #to_int")
|
|
172
|
+
to_a.flatten(level)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
protected
|
|
176
|
+
|
|
177
|
+
# The backing map used by copying and transformation operations.
|
|
178
|
+
# Scoped maps override this to resolve storage for the current scope.
|
|
179
|
+
# @api private
|
|
180
|
+
def internal_map = @map
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
|
|
184
|
+
def initialize_dup(other)
|
|
185
|
+
super
|
|
186
|
+
publish_shareable_copy(other, operation: :dup) if is_a?(Shareable)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def initialize_clone(other, freeze: nil)
|
|
190
|
+
super
|
|
191
|
+
publish_shareable_copy(other, operation: :clone, freeze:) if is_a?(Shareable)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def initialize_copy(other, empty: false)
|
|
195
|
+
super(other)
|
|
196
|
+
normalizer = other.instance_variable_get(:@key_normalizer)
|
|
197
|
+
if normalizer && !is_a?(ConcurrentMap)
|
|
198
|
+
operations = Internal::KeyNormalizer.operations_for(self)
|
|
199
|
+
Internal::KeyNormalizer.install(self, normalizer, operations) unless is_a?(operations)
|
|
200
|
+
end
|
|
201
|
+
install_copied_map(copy_map_backend(other.internal_map, empty:))
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def install_copied_map(map) = @map = map
|
|
205
|
+
|
|
206
|
+
def empty_copy
|
|
207
|
+
# Preserve wrapper settings without copying entries or rerunning the public constructor.
|
|
208
|
+
copy = self.class.allocate
|
|
209
|
+
instance_variables.each { |name| copy.instance_variable_set(name, instance_variable_get(name)) }
|
|
210
|
+
copy.__send__(:initialize_copy, self, empty: true)
|
|
211
|
+
copy.__send__(:publish_shareable) if is_a?(Shareable)
|
|
212
|
+
copy
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def with_map_copy(empty: false)
|
|
216
|
+
copy = empty ? empty_copy : dup
|
|
217
|
+
map = copy.internal_map
|
|
218
|
+
map = map.instance_variable_get(:@map) if map.is_a?(Internal::KeyNormalizer::ConcurrentMap)
|
|
219
|
+
yield copy, map
|
|
220
|
+
copy
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def normalize_copied_key(key)
|
|
224
|
+
normalizer = instance_variable_get(:@key_normalizer)
|
|
225
|
+
normalizer ? normalizer.call(key) : key
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# A rendezvous where callers pair up and receive each other's offered value.
|
|
8
|
+
# Each call participates in one exchange. The exchanger can be reused by any number of callers.
|
|
9
|
+
class Exchanger
|
|
10
|
+
include Internal::Noncopyable
|
|
11
|
+
include Internal::Inspect
|
|
12
|
+
|
|
13
|
+
# Wait for a partner and return the partner's value.
|
|
14
|
+
# Offering nil allows a caller to receive a value without sending a payload.
|
|
15
|
+
# A timeout of zero only exchanges with a partner that is already waiting.
|
|
16
|
+
# A successful exchange of nil does not invoke the fallback.
|
|
17
|
+
#
|
|
18
|
+
# @param offered [BasicObject, nil] the value to give to the partner
|
|
19
|
+
# @param timeout [Numeric, nil] the maximum seconds to wait, or nil to wait indefinitely
|
|
20
|
+
# @yield called without arguments when the timeout expires
|
|
21
|
+
# @return [BasicObject, nil] the partner's value, or the fallback result or nil on timeout
|
|
22
|
+
# @raise [ArgumentError] if the timeout is negative or not finite
|
|
23
|
+
def exchange(offered, timeout: nil, &) = @exchanger.exchange(offered, timeout:, &)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Common boolean interface and serialization for atomic flags.
|
|
8
|
+
# @note This is a module rather than a class so {Farce::Flag} can inherit
|
|
9
|
+
# directly from the native flag and avoid delegation overhead.
|
|
10
|
+
#
|
|
11
|
+
# @!method value
|
|
12
|
+
# @return [Boolean] the current value
|
|
13
|
+
#
|
|
14
|
+
# @!method set
|
|
15
|
+
# Set the flag to true.
|
|
16
|
+
# @return [true]
|
|
17
|
+
#
|
|
18
|
+
# @!method unset
|
|
19
|
+
# Set the flag to false.
|
|
20
|
+
# @return [false]
|
|
21
|
+
#
|
|
22
|
+
# @!method store(value)
|
|
23
|
+
# Set the flag to the given value.
|
|
24
|
+
# @param value [Boolean] the new value
|
|
25
|
+
# @return [Boolean] the new value
|
|
26
|
+
# @raise [ArgumentError] if the value is not true or false
|
|
27
|
+
#
|
|
28
|
+
# @!method value=(value)
|
|
29
|
+
# Alias for {#store}
|
|
30
|
+
#
|
|
31
|
+
# @!method swap(value)
|
|
32
|
+
# Replace the value and return its previous state.
|
|
33
|
+
# @param value [Boolean] the new value
|
|
34
|
+
# @return [Boolean] the previous value
|
|
35
|
+
# @raise [ArgumentError] if the value is not true or false
|
|
36
|
+
#
|
|
37
|
+
# @!method compare_and_set(expected_value, replacement_value)
|
|
38
|
+
# Replace the value only if it matches the expected value.
|
|
39
|
+
# @param expected_value [Boolean] the expected current value
|
|
40
|
+
# @param replacement_value [Boolean] the new value
|
|
41
|
+
# @return [Boolean] whether the replacement succeeded
|
|
42
|
+
# @raise [ArgumentError] if either argument is not true or false
|
|
43
|
+
#
|
|
44
|
+
# @!method toggle
|
|
45
|
+
# Atomically invert the value.
|
|
46
|
+
# @return [Boolean] the new value
|
|
47
|
+
module Flag
|
|
48
|
+
include Internal::MarshalSupport::Flag
|
|
49
|
+
include Internal::Copyable
|
|
50
|
+
include Value
|
|
51
|
+
include Internal::ValueSerialization
|
|
52
|
+
include Internal::Inspect
|
|
53
|
+
|
|
54
|
+
# @api private
|
|
55
|
+
def inspect_with(inspector)
|
|
56
|
+
begin
|
|
57
|
+
current = value
|
|
58
|
+
rescue StandardError
|
|
59
|
+
# FrozenError may inspect an allocated flag before it is initialized.
|
|
60
|
+
return inspector.object_with_address(self)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
super do
|
|
64
|
+
yield if block_given?
|
|
65
|
+
inspector.breakable
|
|
66
|
+
inspector.object(current)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Shared factory, caching, and delegation behavior for lazy values.
|
|
8
|
+
class Lazy
|
|
9
|
+
include Internal::MarshalSupport::Initialize
|
|
10
|
+
include Internal::Copyable
|
|
11
|
+
include Internal::Inspect
|
|
12
|
+
include Value
|
|
13
|
+
|
|
14
|
+
# @overload initialize(factory)
|
|
15
|
+
# @param [Class, Proc, #call] factory The factory to use for creating the value. Must be ractor-shareable.
|
|
16
|
+
#
|
|
17
|
+
# @overload initialize(self: nil)
|
|
18
|
+
# @yield The block to use for creating the value. Must be ractor-shareable.
|
|
19
|
+
# @yieldreceiver [BasicObject] The `self` parameter provided, or `nil` if not provided.
|
|
20
|
+
# @yieldreturn [BasicObject] The value to be returned by the lazy instance.
|
|
21
|
+
# @param [BasicObject] self The `self` parameter to be provided to the block. Must be ractor-shareable.
|
|
22
|
+
def initialize(factory = nil, **, &)
|
|
23
|
+
@factory = prepare_factory(factory, **, &)
|
|
24
|
+
@atom = new_internal_atom
|
|
25
|
+
super()
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The first time this method is called, the value will be computed based on the factory provided.
|
|
29
|
+
# Subsequent calls will return the same value.
|
|
30
|
+
#
|
|
31
|
+
# Concurrent access computes the value once.
|
|
32
|
+
# Shareable variants support calls from any Ractor.
|
|
33
|
+
# @return [BasicObject] The value computed by the factory.
|
|
34
|
+
def value
|
|
35
|
+
atom = internal_atom
|
|
36
|
+
value = atom.value
|
|
37
|
+
if value.nil?
|
|
38
|
+
value = atom.store_if_absent do
|
|
39
|
+
value = compute_value
|
|
40
|
+
value.nil? ? UNDEFINED : value
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
value unless UNDEFINED.equal?(value)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @api private
|
|
47
|
+
def marshal_dump
|
|
48
|
+
current = marshal_current_value
|
|
49
|
+
resolved = !current.nil?
|
|
50
|
+
stored = UNDEFINED.equal?(current) ? nil : current
|
|
51
|
+
manager = @manager if defined?(@manager)
|
|
52
|
+
options = {}
|
|
53
|
+
options[:mode] = manager.mode if manager
|
|
54
|
+
options[:manager] = manager if manager
|
|
55
|
+
options[:scope] = scope if is_a?(Local::Lazy)
|
|
56
|
+
|
|
57
|
+
# Other scopes still need their factory even when this scope is resolved.
|
|
58
|
+
factory = @factory if !resolved || is_a?(Local::Lazy)
|
|
59
|
+
|
|
60
|
+
[1, resolved, factory, Internal::MarshalSupport.value(stored), options, frozen?]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @api private
|
|
64
|
+
def marshal_load(data)
|
|
65
|
+
resolved, factory, stored, options, frozen = Internal::MarshalSupport.payload(data, 5)
|
|
66
|
+
@manager = options.delete(:manager) if options.key?(:manager)
|
|
67
|
+
initialize(factory, **options)
|
|
68
|
+
if resolved
|
|
69
|
+
value = Internal::MarshalSupport.restore_value(stored)
|
|
70
|
+
internal_atom.store(value.nil? ? UNDEFINED : value)
|
|
71
|
+
end
|
|
72
|
+
Internal::MarshalSupport.freeze(self, frozen)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @api private
|
|
76
|
+
def inspect_with(inspector)
|
|
77
|
+
super do
|
|
78
|
+
inspector.breakable
|
|
79
|
+
display_value(inspector)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# @api private
|
|
86
|
+
def marshal_current_value = internal_atom.value
|
|
87
|
+
|
|
88
|
+
def internal_atom = @atom
|
|
89
|
+
def new_internal_atom = Internal::StrictAtom.new
|
|
90
|
+
def compute_value = @factory.is_a?(Class) ? @factory.new : @factory.call
|
|
91
|
+
def prepare_proc(factory, **) = Ractor.shareable_proc(**, &factory)
|
|
92
|
+
|
|
93
|
+
def prepare_factory(factory, **options, &block)
|
|
94
|
+
Internal.self_option(options.dup)
|
|
95
|
+
if block
|
|
96
|
+
raise ArgumentError, "factory and block cannot be both given" unless factory.nil?
|
|
97
|
+
factory = block
|
|
98
|
+
end
|
|
99
|
+
factory.is_a?(Proc) ? prepare_proc(factory, **options) : factory
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def display_value(inspector, ...)
|
|
103
|
+
case value = internal_atom.value
|
|
104
|
+
when nil then inspector.object(@factory, ...)
|
|
105
|
+
when UNDEFINED then inspector.object(nil)
|
|
106
|
+
else inspector.object(value, ...)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Delegates all method calls to {#value}.
|
|
111
|
+
def method_missing(...) = value.public_send(...)
|
|
112
|
+
def respond_to_missing?(...) = value.respond_to?(...)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Shared checkout, return, ownership, and retirement behavior for leases.
|
|
8
|
+
class Lease
|
|
9
|
+
include Internal::Noncopyable
|
|
10
|
+
include Internal::Inspect
|
|
11
|
+
|
|
12
|
+
# Construct a lease from one resource-building block.
|
|
13
|
+
# @yield builds the resource managed by the lease
|
|
14
|
+
# @yieldreturn [BasicObject] the initial resource
|
|
15
|
+
# @raise [ArgumentError] if no block is given or the resource is nil or boolean
|
|
16
|
+
def initialize
|
|
17
|
+
raise ArgumentError, "a resource constructor block is required" unless block_given?
|
|
18
|
+
|
|
19
|
+
@lease = new_internal_lease(yield)
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Acquire the resource, waiting until it is available.
|
|
24
|
+
# @param timeout [Numeric, nil] maximum seconds to wait
|
|
25
|
+
# @yieldparam resource [BasicObject] the acquired resource
|
|
26
|
+
# @return [BasicObject] the resource without a block, or the block result
|
|
27
|
+
# @raise [Farce::TimeoutError] if the timeout expires
|
|
28
|
+
# @raise [Farce::RetiredLeaseError] if the lease is retired
|
|
29
|
+
def checkout(timeout: nil, &block)
|
|
30
|
+
lease = internal_lease
|
|
31
|
+
block ? lease.checkout(timeout:, &block) : lease.checkout(timeout:)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Acquire the resource immediately if it is available.
|
|
35
|
+
# @yieldparam resource [BasicObject] the acquired resource
|
|
36
|
+
# @return [BasicObject, nil] the resource or block result, or nil when unavailable
|
|
37
|
+
# @raise [Farce::RetiredLeaseError] if the lease is retired
|
|
38
|
+
def try_checkout(&block)
|
|
39
|
+
lease = internal_lease
|
|
40
|
+
block ? lease.try_checkout(&block) : lease.try_checkout
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Return an explicitly checked-out resource or a replacement.
|
|
44
|
+
# @param resource [BasicObject] the resource to store
|
|
45
|
+
# @return [self]
|
|
46
|
+
# @raise [Farce::OwnershipError] unless the current Fiber owns an explicit checkout
|
|
47
|
+
# @raise [Farce::RetiredLeaseError] if the lease is retired
|
|
48
|
+
# @raise [ArgumentError] if the resource is nil or boolean
|
|
49
|
+
def checkin(resource)
|
|
50
|
+
internal_lease.checkin(resource)
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Permanently retire this lease and wake its waiters.
|
|
55
|
+
#
|
|
56
|
+
# The current Fiber must own the checkout. Retirement ends that checkout,
|
|
57
|
+
# so automatic block cleanup does not return the resource. The resource is
|
|
58
|
+
# not closed or otherwise disposed. Calling this again after retirement is safe.
|
|
59
|
+
# @return [self]
|
|
60
|
+
# @raise [Farce::OwnershipError] unless the current Fiber owns the checkout
|
|
61
|
+
def retire
|
|
62
|
+
internal_lease.retire
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Boolean] whether the resource is available for checkout
|
|
67
|
+
def available? = internal_lease.available?
|
|
68
|
+
|
|
69
|
+
# @return [Boolean] whether the resource is checked out
|
|
70
|
+
def checked_out? = internal_lease.checked_out?
|
|
71
|
+
|
|
72
|
+
# @return [Boolean] whether the current Fiber owns the checkout
|
|
73
|
+
def owned? = internal_lease.owned?
|
|
74
|
+
|
|
75
|
+
# @return [Boolean] whether the lease has been permanently retired
|
|
76
|
+
def retired? = internal_lease.retired?
|
|
77
|
+
|
|
78
|
+
# @api private
|
|
79
|
+
def inspect_with(inspector)
|
|
80
|
+
super do
|
|
81
|
+
yield if block_given?
|
|
82
|
+
inspector.breakable
|
|
83
|
+
next inspector.text("checked_out") if checked_out?
|
|
84
|
+
next inspector.text("available") if available?
|
|
85
|
+
next inspector.text("retired") if retired?
|
|
86
|
+
inspector.text("unknown")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def checkout_with_handoff(...) = internal_lease.checkout_with_handoff(...)
|
|
93
|
+
def try_checkout_with_handoff(...) = internal_lease.try_checkout_with_handoff(...)
|
|
94
|
+
def checkin_scope(resource) = internal_lease.checkin_scope(resource)
|
|
95
|
+
def explicitly_owned? = internal_lease.explicitly_owned?
|
|
96
|
+
def mark_scope_managed = internal_lease.mark_scope_managed
|
|
97
|
+
def scope_managed? = internal_lease.scope_managed?
|
|
98
|
+
def owned_resource = internal_lease.owned_resource
|
|
99
|
+
def replace_owned_resource(resource) = internal_lease.replace_owned_resource(resource)
|
|
100
|
+
def internal_lease = @lease
|
|
101
|
+
def new_internal_lease(_) = raise(NoMethodError, "abstract lease storage")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|