farce 0.0.1.alpha2-x86_64-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Superclass for all maps defined by Farce.
|
|
8
|
+
# @note
|
|
9
|
+
# The supported methods are generally compatible with their Hash counterparts,
|
|
10
|
+
# with the notable exception of {ConcurrentMap#update}.
|
|
11
|
+
#
|
|
12
|
+
# A Hash-like collection with slightly reduced functionality to allow for better concurrency models.
|
|
13
|
+
#
|
|
14
|
+
# Constructors accept a Hash, another map, or an object whose #each yields key/value pairs.
|
|
15
|
+
# Arrays of pairs and enumerators are supported. Initial entries are inserted in source order.
|
|
16
|
+
# Local maps retain the initial entries for reuse in each scope.
|
|
17
|
+
#
|
|
18
|
+
# `dup` and `clone` create independent storage and coordination while sharing keys and stored values.
|
|
19
|
+
# Value modes and key normalization are preserved without transferring values again.
|
|
20
|
+
# Copies of shareable maps remain shareable unless explicitly cloned with `freeze: false`.
|
|
21
|
+
# Local copies retain the current scope's contents. Other scopes use the original constructor configuration.
|
|
22
|
+
# Lease maps reject copying because resources cannot safely be given independent ownership controls.
|
|
23
|
+
#
|
|
24
|
+
# Iteration order is implementation-dependent. In particular, insertion order is not guaranteed.
|
|
25
|
+
#
|
|
26
|
+
# Implementations can compare keys and values either by equality or by identity. Operations accepting a
|
|
27
|
+
# `timeout` wait at most that many seconds to acquire the access needed for the operation. A timeout must be a
|
|
28
|
+
# finite, non-negative number, `nil` waits indefinitely.
|
|
29
|
+
#
|
|
30
|
+
# @!method [](key)
|
|
31
|
+
# Look up a key without waiting for atomic-update access.
|
|
32
|
+
# @param key [BasicObject] The key to look up.
|
|
33
|
+
# @return [BasicObject, nil] The associated value, or nil if the key is absent.
|
|
34
|
+
# @abstract
|
|
35
|
+
#
|
|
36
|
+
# @!method []=(key, value)
|
|
37
|
+
# Associate a value with a key without a timeout.
|
|
38
|
+
# @param key [BasicObject] The key to store.
|
|
39
|
+
# @param value [BasicObject] The value to store.
|
|
40
|
+
# @return [BasicObject] `value`.
|
|
41
|
+
# @abstract
|
|
42
|
+
#
|
|
43
|
+
# @!method store_if_absent(key)
|
|
44
|
+
# Read an existing value or construct and store a value for an absent key.
|
|
45
|
+
# Existing nil and false values count as present when the implementation permits them.
|
|
46
|
+
# The block runs without holding a map-wide lock. Implementations document their
|
|
47
|
+
# coordination guarantees, ownership requirements, and optional timeout support.
|
|
48
|
+
# A later removal or eviction can cause another call to construct a new value.
|
|
49
|
+
# @param key [BasicObject] The key to look up or store.
|
|
50
|
+
# @yield Called without arguments when the key is absent.
|
|
51
|
+
# @yieldreturn [BasicObject] The value to store and return.
|
|
52
|
+
# @return [BasicObject] The existing or newly constructed value.
|
|
53
|
+
# @raise [LocalJumpError] If no block is given.
|
|
54
|
+
# @abstract
|
|
55
|
+
#
|
|
56
|
+
# @!method clear
|
|
57
|
+
# Remove all entries from the map.
|
|
58
|
+
# @return [self]
|
|
59
|
+
# @abstract
|
|
60
|
+
#
|
|
61
|
+
# @!method compare_keys_by_identity?
|
|
62
|
+
# @return [Boolean] Whether keys are compared by identity instead of `hash` and `eql?`.
|
|
63
|
+
# @abstract
|
|
64
|
+
#
|
|
65
|
+
# @!method compare_values_by_identity?
|
|
66
|
+
# @return [Boolean] Whether values are compared by identity instead of equality.
|
|
67
|
+
# @abstract
|
|
68
|
+
#
|
|
69
|
+
# @!method delete(key)
|
|
70
|
+
# Remove a key and its associated value.
|
|
71
|
+
# @param key [BasicObject] The key to remove.
|
|
72
|
+
# @return [BasicObject, nil] The removed value, or nil if the key was absent.
|
|
73
|
+
# @abstract
|
|
74
|
+
#
|
|
75
|
+
# @!method each
|
|
76
|
+
# Iterate over the map's key-value pairs.
|
|
77
|
+
# Entry consistency and access requirements depend on the implementation. Iteration order is not guaranteed
|
|
78
|
+
# to match insertion order.
|
|
79
|
+
# @overload each
|
|
80
|
+
# @yield [pair] Called once for each entry.
|
|
81
|
+
# @yieldparam pair [Array<BasicObject>] A two-element `[key, value]` pair.
|
|
82
|
+
# @return [self]
|
|
83
|
+
# @overload each
|
|
84
|
+
# @return [Enumerator] An enumerator over two-element `[key, value]` pairs.
|
|
85
|
+
# @abstract
|
|
86
|
+
#
|
|
87
|
+
# @!method each_key
|
|
88
|
+
# Iterate over the keys currently stored in the map.
|
|
89
|
+
# Keys are not guaranteed to be yielded in insertion order.
|
|
90
|
+
# @overload each_key
|
|
91
|
+
# @yield [key] Called once for each stored key.
|
|
92
|
+
# @yieldparam key [BasicObject] A stored key.
|
|
93
|
+
# @return [self]
|
|
94
|
+
# @overload each_key
|
|
95
|
+
# @return [Enumerator] An enumerator over the stored keys.
|
|
96
|
+
# @abstract
|
|
97
|
+
#
|
|
98
|
+
# @!method each_pair
|
|
99
|
+
# Iterate over key-value pairs in the same manner as {#each}.
|
|
100
|
+
# @see #each
|
|
101
|
+
# @abstract
|
|
102
|
+
#
|
|
103
|
+
# @!method each_value
|
|
104
|
+
# Iterate over the values currently stored in the map.
|
|
105
|
+
# Values are not guaranteed to be yielded in insertion order.
|
|
106
|
+
# @overload each_value
|
|
107
|
+
# @yield [value] Called once for each stored value.
|
|
108
|
+
# @yieldparam value [BasicObject] A stored value.
|
|
109
|
+
# @return [self]
|
|
110
|
+
# @overload each_value
|
|
111
|
+
# @return [Enumerator] An enumerator over the stored values.
|
|
112
|
+
# @abstract
|
|
113
|
+
#
|
|
114
|
+
# @!method fetch(key, *defaults)
|
|
115
|
+
# Fetch the value associated with a key, using the same missing-key behavior as Hash#fetch.
|
|
116
|
+
# If both a default and a block are provided, the block takes precedence and a warning is emitted.
|
|
117
|
+
# @overload fetch(key)
|
|
118
|
+
# @param key [BasicObject] The key to look up.
|
|
119
|
+
# @return [BasicObject] The associated value.
|
|
120
|
+
# @raise [KeyError] If the key is absent.
|
|
121
|
+
# @overload fetch(key, default)
|
|
122
|
+
# @param key [BasicObject] The key to look up.
|
|
123
|
+
# @param default [BasicObject] The value to return if the key is absent.
|
|
124
|
+
# @return [BasicObject] The associated value or `default`.
|
|
125
|
+
# @overload fetch(key)
|
|
126
|
+
# @param key [BasicObject] The key to look up.
|
|
127
|
+
# @yield [key] Called if the key is absent.
|
|
128
|
+
# @yieldparam key [BasicObject] The missing key.
|
|
129
|
+
# @yieldreturn [BasicObject] The value to return.
|
|
130
|
+
# @return [BasicObject] The associated value or the block result.
|
|
131
|
+
# @abstract
|
|
132
|
+
#
|
|
133
|
+
# @!method getkey(key)
|
|
134
|
+
# Return the stored key that matches a lookup key.
|
|
135
|
+
# @param key [BasicObject] The key to match.
|
|
136
|
+
# @return [BasicObject, nil] The matching stored key, or nil if no key matches.
|
|
137
|
+
# @abstract
|
|
138
|
+
#
|
|
139
|
+
# @!method key?(key)
|
|
140
|
+
# Test whether a key is present, including when its associated value is nil.
|
|
141
|
+
# @param key [BasicObject] The key to look up.
|
|
142
|
+
# @return [Boolean] Whether the key is present.
|
|
143
|
+
# @abstract
|
|
144
|
+
#
|
|
145
|
+
# @!method keys
|
|
146
|
+
# Return the keys currently stored in the map.
|
|
147
|
+
# The returned keys are not guaranteed to be in insertion order.
|
|
148
|
+
# @return [Array<BasicObject>] A new array containing the stored keys.
|
|
149
|
+
# @abstract
|
|
150
|
+
#
|
|
151
|
+
# @!method size
|
|
152
|
+
# Return the number of entries currently in the map.
|
|
153
|
+
# @return [Integer] The number of entries.
|
|
154
|
+
# @abstract
|
|
155
|
+
class Map
|
|
156
|
+
include Internal::MarshalSupport::Map
|
|
157
|
+
include Enumerable
|
|
158
|
+
include Internal::Inspect
|
|
159
|
+
|
|
160
|
+
# Store a value using the map's assignment operation.
|
|
161
|
+
# Concurrent maps override this method to support timeouts.
|
|
162
|
+
# @param key [BasicObject] the key to store
|
|
163
|
+
# @param value [BasicObject] the value to store
|
|
164
|
+
# @return [BasicObject] `value`
|
|
165
|
+
def store(key, value) = self[key] = value
|
|
166
|
+
|
|
167
|
+
# Return a two-element array containing a key and its associated value, if the key is present,
|
|
168
|
+
# or nil if the key is absent.
|
|
169
|
+
# @param key [BasicObject] The key to look up.
|
|
170
|
+
# @return [Array(BasicObject, BasicObject), nil] A two-element `[key, value]` array, or nil if the key is absent.
|
|
171
|
+
def assoc(key)
|
|
172
|
+
value = fetch(key) { return nil }
|
|
173
|
+
[key, value]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# (see #compare_keys_by_identity?)
|
|
177
|
+
def compare_by_identity? = compare_keys_by_identity?
|
|
178
|
+
|
|
179
|
+
# Implements Ruby's [dig interface](https://docs.ruby-lang.org/en/master/language/dig_methods_rdoc.html).
|
|
180
|
+
# @param key [BasicObject] The key to look up.
|
|
181
|
+
# @param rest [Array<BasicObject>] Additional keys to look up in nested maps.
|
|
182
|
+
# @return [BasicObject, nil] The value found at the nested location, or nil if any key is absent or nil.
|
|
183
|
+
def dig(key, *rest)
|
|
184
|
+
value = self[key]
|
|
185
|
+
return value if rest.empty? || value.nil?
|
|
186
|
+
value.dig(*rest)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Returns whether the map contains no entries.
|
|
190
|
+
# @return [Boolean] Whether the map is empty.
|
|
191
|
+
def empty? = size.zero?
|
|
192
|
+
|
|
193
|
+
# Return the number of entries currently in the map.
|
|
194
|
+
# @return [Integer]
|
|
195
|
+
def length = size
|
|
196
|
+
|
|
197
|
+
# Return whether an observed value matches using this map's value comparison setting.
|
|
198
|
+
# Values are unwrapped before comparison. Concurrent changes may make the result stale.
|
|
199
|
+
# @param value [BasicObject] the value to find
|
|
200
|
+
# @return [Boolean]
|
|
201
|
+
def value?(value)
|
|
202
|
+
identity = compare_values_by_identity?
|
|
203
|
+
each_value.any? { |stored| identity ? stored.equal?(value) : stored == value }
|
|
204
|
+
end
|
|
205
|
+
alias has_value? value?
|
|
206
|
+
|
|
207
|
+
# Return a matching key using this map's value comparison setting, or nil.
|
|
208
|
+
# The first observed match is returned. No insertion order is guaranteed.
|
|
209
|
+
# @param value [BasicObject] the value to find
|
|
210
|
+
# @return [BasicObject, nil]
|
|
211
|
+
def key(value)
|
|
212
|
+
pair = rassoc(value)
|
|
213
|
+
pair&.first
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Return an observed key/value pair using this map's value comparison setting, or nil.
|
|
217
|
+
# Values are unwrapped before comparison. Concurrent changes may make the result stale.
|
|
218
|
+
# @param value [BasicObject] the value to find
|
|
219
|
+
# @return [Array, nil]
|
|
220
|
+
def rassoc(value)
|
|
221
|
+
identity = compare_values_by_identity?
|
|
222
|
+
each_pair do |key, stored|
|
|
223
|
+
return [key, stored] if identity ? stored.equal?(value) : stored == value
|
|
224
|
+
end
|
|
225
|
+
nil
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Alias for {#key?}
|
|
229
|
+
def has_key?(...) = key?(...) # rubocop:disable Naming/PredicatePrefix
|
|
230
|
+
alias member? has_key?
|
|
231
|
+
alias include? has_key?
|
|
232
|
+
|
|
233
|
+
# Fetches the values associated with multiple keys, using the same missing-key behavior as Hash#fetch.
|
|
234
|
+
# @yield [key] Called for each missing key.
|
|
235
|
+
# @yieldparam key [BasicObject] The missing key.
|
|
236
|
+
# @yieldreturn [BasicObject] The value to return for the missing key.
|
|
237
|
+
# @param keys [Array<BasicObject>] The keys to look up.
|
|
238
|
+
# @return [Array<BasicObject>] An array of the associated values.
|
|
239
|
+
def fetch_values(*keys, &) = keys.map { fetch(it, &) }
|
|
240
|
+
|
|
241
|
+
# @note
|
|
242
|
+
# Some maps may still accept non-shareable keys or values, but convert them into shareable representations.
|
|
243
|
+
# This method will still return `true` for such maps.
|
|
244
|
+
#
|
|
245
|
+
# @return [Boolean] Whether the map requires keys to be Ractor-shareable
|
|
246
|
+
def shareable_keys? = false
|
|
247
|
+
|
|
248
|
+
# @return [Boolean] Whether the map requires values to be Ractor-shareable
|
|
249
|
+
def shareable_values? = false
|
|
250
|
+
|
|
251
|
+
# Creates a new Array containing the map's key-value pairs as two-element arrays.
|
|
252
|
+
# @return [Array<Array(BasicObject, BasicObject)>>] A new Array of `[key, value]` arrays.
|
|
253
|
+
def to_a = each_pair.to_a
|
|
254
|
+
|
|
255
|
+
# Creates a new Hash containing the map's entries.
|
|
256
|
+
# Preserves identity comparison for keys, including when a block transforms entries.
|
|
257
|
+
# @yieldparam key [BasicObject] an existing key
|
|
258
|
+
# @yieldparam value [BasicObject] its value
|
|
259
|
+
# @yieldreturn [Array(BasicObject, BasicObject)] the key and value for the new Hash
|
|
260
|
+
# @return [Hash] A new Hash with the original entries, or the pairs returned by the block.
|
|
261
|
+
def to_h(&) = entries_to_hash(each_pair, &)
|
|
262
|
+
|
|
263
|
+
# Support implicit Hash conversion using this map's {#to_h} implementation.
|
|
264
|
+
# @return [Hash] A new Hash containing the map's entries.
|
|
265
|
+
def to_hash = to_h
|
|
266
|
+
|
|
267
|
+
# Support hash patterns using the same entries and key comparison as {#to_h}.
|
|
268
|
+
# Like Hash, this returns all entries regardless of the requested keys.
|
|
269
|
+
# @param keys [Array, nil] the optional key hint supplied by Ruby's pattern matcher
|
|
270
|
+
# @return [Hash] A new Hash containing the map's entries.
|
|
271
|
+
def deconstruct_keys(keys) = to_h # rubocop:disable Lint/UnusedMethodArgument
|
|
272
|
+
|
|
273
|
+
# Fetches the values associated with multiple keys, returning nil for any missing keys.
|
|
274
|
+
# @param keys [Array<BasicObject>] The keys to look up.
|
|
275
|
+
# @return [Array<BasicObject>] An array of the associated values, with nil for any missing keys.
|
|
276
|
+
def values_at(*keys) = keys.map { self[it] }
|
|
277
|
+
|
|
278
|
+
# Some maps reference their keys weakly, automatically dropping entries when a key gets garbage-collected.
|
|
279
|
+
# @return [Boolean] Whether the map uses weak references for keys.
|
|
280
|
+
def weak_keys? = false
|
|
281
|
+
|
|
282
|
+
# Some maps reference their values weakly, automatically dropping entries when a value gets garbage-collected.
|
|
283
|
+
# @return [Boolean] Whether the map uses weak references for values.
|
|
284
|
+
def weak_values? = false
|
|
285
|
+
|
|
286
|
+
# @return [String] String representation of the map, suitable for debugging.
|
|
287
|
+
def to_s = inspect
|
|
288
|
+
|
|
289
|
+
# @api private
|
|
290
|
+
def inspect_with(inspector)
|
|
291
|
+
super do
|
|
292
|
+
yield if block_given?
|
|
293
|
+
inspector.breakable
|
|
294
|
+
inspector.group("{", "}") do
|
|
295
|
+
inspector.breakable ""
|
|
296
|
+
inspector.seplist(self, nil, :each_for_inspect) do |key, value|
|
|
297
|
+
inspector.group { inspect_pair(inspector, key, value) }
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
protected
|
|
304
|
+
|
|
305
|
+
# Convert a public value to its stored representation.
|
|
306
|
+
# @api private
|
|
307
|
+
def wrap_value(value) = value
|
|
308
|
+
|
|
309
|
+
# Convert a stored representation to its public value.
|
|
310
|
+
# @api private
|
|
311
|
+
def unwrap_value(value) = value
|
|
312
|
+
|
|
313
|
+
private
|
|
314
|
+
|
|
315
|
+
def entries_to_hash(entries, &)
|
|
316
|
+
return entries.to_h(&) unless compare_keys_by_identity?
|
|
317
|
+
hash = {}.compare_by_identity
|
|
318
|
+
entries.each do |key, value|
|
|
319
|
+
if block_given?
|
|
320
|
+
pair = Array.try_convert(yield(key, value))
|
|
321
|
+
raise TypeError, "block must return an Array or respond to #to_ary" unless pair
|
|
322
|
+
raise ArgumentError, "block must return a two-element pair" unless pair.size == 2
|
|
323
|
+
key, value = pair
|
|
324
|
+
end
|
|
325
|
+
hash[key] = value
|
|
326
|
+
end
|
|
327
|
+
hash
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def convert_entries(entries)
|
|
331
|
+
return entries if Map === entries
|
|
332
|
+
if entries.respond_to?(:to_hash)
|
|
333
|
+
entries = Hash.try_convert(entries)
|
|
334
|
+
raise TypeError, "entries must be a Hash or respond to #to_hash" unless entries
|
|
335
|
+
end
|
|
336
|
+
return entries if entries.nil? || entries.respond_to?(:each)
|
|
337
|
+
raise TypeError, "entries must yield key/value pairs with #each"
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def each_for_inspect(&) = each(&)
|
|
341
|
+
def inspect_pair(inspector, key, value) = inspector.hash_pair(key, value) { inspect_value(inspector, value) }
|
|
342
|
+
def inspect_value(inspector, ...) = inspector.object(...)
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract A record whose fields are independently atomic references.
|
|
8
|
+
#
|
|
9
|
+
# Define a record class with {.define}, then read or assign its named fields.
|
|
10
|
+
# Use each field's `<name>_atom` for updates, comparisons, and waits.
|
|
11
|
+
# Operations on several fields are not a transaction or a consistent snapshot.
|
|
12
|
+
class Molecule
|
|
13
|
+
include Internal::MarshalSupport::Initialize
|
|
14
|
+
include Internal::Freeze::Tracked
|
|
15
|
+
include Internal::Inspect
|
|
16
|
+
include Enumerable
|
|
17
|
+
|
|
18
|
+
EMPTY_ARRAY = [].freeze
|
|
19
|
+
private_constant :EMPTY_ARRAY
|
|
20
|
+
|
|
21
|
+
ACCESSORS = Module.new do
|
|
22
|
+
def get = public_send(:"#{__callee__}_atom").value
|
|
23
|
+
def set(value) = public_send(:"#{__callee__.to_s.delete_suffix("=")}_atom").value = value
|
|
24
|
+
def atom = @molecule_atoms.fetch(__callee__, nil)
|
|
25
|
+
|
|
26
|
+
def atom=(value)
|
|
27
|
+
@molecule_atoms[__callee__.to_s.delete_suffix("=").to_sym] = value
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private_constant :ACCESSORS
|
|
32
|
+
|
|
33
|
+
# Create a record class with readers, writers, and `<name>_atom` accessors.
|
|
34
|
+
# Missing initial values default to nil. Generated classes may be subclassed.
|
|
35
|
+
# @param fields [Array<Symbol, String>] unique field names
|
|
36
|
+
# @param compare_by_identity [Boolean, nil] the default comparison policy, or nil to inherit
|
|
37
|
+
# @return [Class<Molecule>] the record class
|
|
38
|
+
# @raise [ArgumentError] if names conflict with the record interface
|
|
39
|
+
def self.define(*fields, compare_by_identity: nil)
|
|
40
|
+
fields = fields.map(&:to_sym)
|
|
41
|
+
names = fields.flat_map { [it, :"#{it}=", :"#{it}_atom", :"#{it}_atom="] }
|
|
42
|
+
|
|
43
|
+
conflicts = names.any? do |name|
|
|
44
|
+
next true if name == :freeze
|
|
45
|
+
next false unless method_defined?(name) || private_method_defined?(name)
|
|
46
|
+
instance_method(name).owner != Enumerable
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if names.uniq.length != names.length || conflicts
|
|
50
|
+
raise ArgumentError, "field names must be unique and must not override the molecule interface"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Class.new(self) do
|
|
54
|
+
singleton_class.class_eval { undef define }
|
|
55
|
+
unless nil.equal?(compare_by_identity)
|
|
56
|
+
class_eval "def self.compare_by_identity? = #{(!!compare_by_identity).inspect}", __FILE__, __LINE__ - 1
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
atoms = []
|
|
60
|
+
members = fields.map do |field|
|
|
61
|
+
define_member(field)
|
|
62
|
+
atoms << :"#{field}_atom"
|
|
63
|
+
field
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@atoms = Ractor.make_shareable(atoms.freeze)
|
|
67
|
+
@members = Ractor.make_shareable(members.freeze)
|
|
68
|
+
|
|
69
|
+
set_temporary_name("#{superclass.name}#{@members.inspect}")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @api private
|
|
74
|
+
def self.[](...) = define(...)
|
|
75
|
+
|
|
76
|
+
# @return [Boolean] the default comparison policy for new records
|
|
77
|
+
def self.compare_by_identity? = false
|
|
78
|
+
|
|
79
|
+
# @!visibility private
|
|
80
|
+
def self.define_member(field)
|
|
81
|
+
raise ArgumentError, "#{field.inspect} is not a valid field name" if field == :compare_by_identity
|
|
82
|
+
if field =~ /\A[a-z_]\w*\z/i
|
|
83
|
+
attr_accessor :"#{field}_atom"
|
|
84
|
+
private :"#{field}_atom="
|
|
85
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
86
|
+
def #{field} = self.#{field}_atom.value
|
|
87
|
+
|
|
88
|
+
def #{field}=(value)
|
|
89
|
+
self.#{field}_atom.value = value
|
|
90
|
+
end
|
|
91
|
+
RUBY
|
|
92
|
+
else
|
|
93
|
+
define_method(:"#{field}_atom", ACCESSORS.instance_method(:atom))
|
|
94
|
+
define_method(:"#{field}_atom=", ACCESSORS.instance_method(:atom=))
|
|
95
|
+
define_method(field, ACCESSORS.instance_method(:get))
|
|
96
|
+
define_method(:"#{field}=", ACCESSORS.instance_method(:set))
|
|
97
|
+
private :"#{field}_atom="
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
private_class_method :define_member
|
|
101
|
+
|
|
102
|
+
# @return [Array<Symbol>] the atom accessor names in declaration order
|
|
103
|
+
def self.atoms
|
|
104
|
+
return @atoms if defined?(@atoms) && @atoms
|
|
105
|
+
return superclass.atoms if superclass.respond_to?(:atoms)
|
|
106
|
+
EMPTY_ARRAY
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @return [Array<Symbol>] the field names in declaration order
|
|
110
|
+
def self.members
|
|
111
|
+
return @members if defined?(@members) && @members
|
|
112
|
+
return superclass.members if superclass.respond_to?(:members)
|
|
113
|
+
EMPTY_ARRAY
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Initialize fields by position or name. A field may only be supplied once.
|
|
117
|
+
# Existing {Atom} instances are retained directly, preserving their policy.
|
|
118
|
+
# @param input [Array<BasicObject>] values in declaration order
|
|
119
|
+
# @param attributes [Hash{Symbol => BasicObject}] values by field name
|
|
120
|
+
# @param compare_by_identity [Boolean, nil] the comparison policy, or nil for the class default
|
|
121
|
+
# @raise [ArgumentError] for unknown, repeated, or excess values
|
|
122
|
+
def initialize(*input, compare_by_identity: nil, **attributes)
|
|
123
|
+
raise ArgumentError, "too many positional values" if input.length > members.length
|
|
124
|
+
@compare_by_identity = compare_by_identity.nil? ? self.class.compare_by_identity? : !!compare_by_identity # rubocop:disable Style/DoubleNegation
|
|
125
|
+
@molecule_atoms = {}
|
|
126
|
+
input.each_with_index { initialize_atom(members[_2], _1) }
|
|
127
|
+
attributes.each { initialize_atom(_1, _2) }
|
|
128
|
+
members.each { initialize_atom(it, nil) unless public_send(:"#{it}_atom") }
|
|
129
|
+
@molecule_atoms.freeze
|
|
130
|
+
super()
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# @api private
|
|
134
|
+
def marshal_dump
|
|
135
|
+
options = { compare_by_identity: compare_by_identity? }
|
|
136
|
+
options[:mode] = mode if respond_to?(:mode)
|
|
137
|
+
options[:scope] = scope if respond_to?(:scope)
|
|
138
|
+
fields = members.map { |member| [member, public_send(:"#{member}_atom")] }
|
|
139
|
+
[1, fields, options, frozen?]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @api private
|
|
143
|
+
def marshal_load(data)
|
|
144
|
+
fields, options, frozen = Internal::MarshalSupport.payload(data, 3)
|
|
145
|
+
initialize(**fields.to_h, **options)
|
|
146
|
+
Internal::MarshalSupport.freeze(self, frozen)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# @api private
|
|
150
|
+
def transaction_wrapper(transaction) = Transaction::Molecule.new(transaction, self)
|
|
151
|
+
|
|
152
|
+
# Whether newly created atoms compare by identity instead of equality.
|
|
153
|
+
# Explicitly supplied atoms retain their own comparison policy.
|
|
154
|
+
# @return [Boolean]
|
|
155
|
+
def compare_by_identity? = @compare_by_identity
|
|
156
|
+
|
|
157
|
+
# (see .atoms)
|
|
158
|
+
def atoms = self.class.atoms
|
|
159
|
+
|
|
160
|
+
# (see .members)
|
|
161
|
+
def members = self.class.members
|
|
162
|
+
|
|
163
|
+
# Yield field names and current values in declaration order.
|
|
164
|
+
# @yieldparam member [Symbol] the field name
|
|
165
|
+
# @yieldparam value [BasicObject] its current value
|
|
166
|
+
# @return [Array<Symbol>, Enumerator]
|
|
167
|
+
def each
|
|
168
|
+
return enum_for(:each) unless block_given?
|
|
169
|
+
members.each { yield it, public_send(it) }
|
|
170
|
+
end
|
|
171
|
+
alias each_pair each
|
|
172
|
+
|
|
173
|
+
# Yield atom accessor names and atomic references in declaration order.
|
|
174
|
+
# @yieldparam name [Symbol] the atom accessor name
|
|
175
|
+
# @yieldparam atom [Atom] the field's atomic reference
|
|
176
|
+
# @return [Array<Symbol>, Enumerator]
|
|
177
|
+
def each_atom
|
|
178
|
+
return enum_for(:each_atom) unless block_given?
|
|
179
|
+
atoms.each { yield it, public_send(it) }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Yield field names in declaration order.
|
|
183
|
+
# @return [Array<Symbol>, Enumerator]
|
|
184
|
+
def each_member
|
|
185
|
+
return enum_for(:each_member) unless block_given?
|
|
186
|
+
members.each { yield it }
|
|
187
|
+
end
|
|
188
|
+
alias each_key each_member
|
|
189
|
+
|
|
190
|
+
# Yield current field values in declaration order.
|
|
191
|
+
# @return [Array<Symbol>, Enumerator]
|
|
192
|
+
def each_value
|
|
193
|
+
return enum_for(:each_value) unless block_given?
|
|
194
|
+
members.each { yield public_send(it) }
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Prevent field replacement and atom updates without freezing stored values.
|
|
198
|
+
# Coordinate with writers before freezing. This is not a snapshot operation.
|
|
199
|
+
# @return [self]
|
|
200
|
+
def freeze
|
|
201
|
+
return self if frozen?
|
|
202
|
+
each_atom { |_, atom| atom.freeze }
|
|
203
|
+
super
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# @api private
|
|
207
|
+
def inspect_with(inspector)
|
|
208
|
+
super do
|
|
209
|
+
yield if block_given?
|
|
210
|
+
each_member do |member|
|
|
211
|
+
inspector.breakable
|
|
212
|
+
inspector.text("#{member}=")
|
|
213
|
+
atom = public_send(:"#{member}_atom")
|
|
214
|
+
atom.__send__(:inspect_value, inspector, nil)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
private
|
|
220
|
+
|
|
221
|
+
# @abstract Build the atomic reference for one field.
|
|
222
|
+
# @param key [Symbol] the field name
|
|
223
|
+
# @param value [BasicObject] its initial value
|
|
224
|
+
# @return [Atom]
|
|
225
|
+
def create_atom(_key, _value) = raise NoMethodError, "create_atom must be implemented in the subclass"
|
|
226
|
+
|
|
227
|
+
def initialize_atom(key, value)
|
|
228
|
+
getter = :"#{key}_atom"
|
|
229
|
+
setter = :"#{key}_atom="
|
|
230
|
+
|
|
231
|
+
raise ArgumentError, "#{key.inspect} is not a valid member" unless respond_to?(getter)
|
|
232
|
+
current = public_send(:"#{key}_atom")
|
|
233
|
+
|
|
234
|
+
if respond_to?(setter, true)
|
|
235
|
+
raise ArgumentError, "#{key} has already been initialized" if current
|
|
236
|
+
value = create_atom(key, value) unless Atom === value
|
|
237
|
+
__send__(:"#{key}_atom=", value)
|
|
238
|
+
else
|
|
239
|
+
raise TypeError, "expected #{getter.inspect} to return an Atom" unless current.is_a?(Atom)
|
|
240
|
+
current.value = value
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Common interface and ownership tracking for Farce ports.
|
|
8
|
+
# @note
|
|
9
|
+
# This is a module so both implementations can inherit directly from the runtime's port backend.
|
|
10
|
+
#
|
|
11
|
+
# @!method send(message)
|
|
12
|
+
# Sends a message through the port.
|
|
13
|
+
# @param message [BasicObject] the message to send
|
|
14
|
+
# @return [self]
|
|
15
|
+
# @raise [Farce::Ractor::ClosedError] if the port is closed
|
|
16
|
+
#
|
|
17
|
+
# @!method receive(timeout: nil)
|
|
18
|
+
# Waits for a message or the timeout. Only the owning Ractor can receive.
|
|
19
|
+
# @param timeout [Numeric, nil] the maximum seconds to wait, or nil to wait indefinitely
|
|
20
|
+
# @return [BasicObject, nil] the received message, or nil on timeout
|
|
21
|
+
# @raise [Farce::Ractor::ClosedError] if the port is closed
|
|
22
|
+
#
|
|
23
|
+
# @!method close
|
|
24
|
+
# Closes the port. Only the owning Ractor can close it.
|
|
25
|
+
# @return [self]
|
|
26
|
+
#
|
|
27
|
+
# @!method closed?
|
|
28
|
+
# @return [Boolean] whether the port is closed
|
|
29
|
+
module Port
|
|
30
|
+
include Internal::MarshalSupport::Reject
|
|
31
|
+
include Internal::Noncopyable
|
|
32
|
+
include Shareable::Native
|
|
33
|
+
include Shareable::Unfreezable
|
|
34
|
+
|
|
35
|
+
# @api private
|
|
36
|
+
def initialize(...)
|
|
37
|
+
# Native Ractor ports cannot hold Ruby instance variables.
|
|
38
|
+
Internal::Storage.ractor[self] = true
|
|
39
|
+
super
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Checks whether the current Ractor created this port.
|
|
43
|
+
# @return [Boolean] whether the current Ractor owns the port
|
|
44
|
+
def owned? = !!Internal::Storage.ractor[self]
|
|
45
|
+
|
|
46
|
+
# Forwards all arguments to {#send}.
|
|
47
|
+
# @return [self]
|
|
48
|
+
def <<(...) = send(...)
|
|
49
|
+
|
|
50
|
+
# Forwards all arguments to {#send}.
|
|
51
|
+
# @return [self]
|
|
52
|
+
def push(...) = send(...)
|
|
53
|
+
|
|
54
|
+
# Forwards all arguments to {#receive}.
|
|
55
|
+
# @return [BasicObject, nil] the received message, or nil on timeout
|
|
56
|
+
def pop(...) = receive(...)
|
|
57
|
+
|
|
58
|
+
# @api private
|
|
59
|
+
def pretty_print(pp)
|
|
60
|
+
string = inspect
|
|
61
|
+
return pp.text(string) unless match = string.match(/\A#<([\w:]+)((?: \w+:#?\w+)+)>\z/)
|
|
62
|
+
|
|
63
|
+
pp.group(1, "#<#{match[1]}", ">") do
|
|
64
|
+
match[2].split.each do |pair|
|
|
65
|
+
pp.breakable " "
|
|
66
|
+
key, value = pair.split(":", 2)
|
|
67
|
+
pp.text "#{key}:"
|
|
68
|
+
pp.text value
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|