farce 0.0.1.alpha2-java
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/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 +420 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# Mixin that makes sure instances are shareable between Ractors.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# class MyClass
|
|
10
|
+
# include Farce::Shareable
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# object = MyClass.new
|
|
14
|
+
# Ractor.shareable?(object) # => true
|
|
15
|
+
module Shareable
|
|
16
|
+
# A structurally frozen wrapper whose logical frozen state is owned by its backend.
|
|
17
|
+
# The including class must implement a private `freeze_backend` method.
|
|
18
|
+
#
|
|
19
|
+
# @example Delegate freezing to a counter
|
|
20
|
+
# class Tally
|
|
21
|
+
# include Farce::Shareable::Delegated
|
|
22
|
+
#
|
|
23
|
+
# def initialize
|
|
24
|
+
# @counter = Farce::Counter.new
|
|
25
|
+
# super
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# def increment = @counter.increment
|
|
29
|
+
# private def freeze_backend = @counter
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# tally = Tally.new
|
|
33
|
+
# tally.frozen? # => false
|
|
34
|
+
# tally.freeze
|
|
35
|
+
# tally.increment # raises FrozenError in the counter
|
|
36
|
+
module Delegated
|
|
37
|
+
include Shareable
|
|
38
|
+
include Internal::Freeze::Delegated
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# A structurally frozen wrapper with one shared logical freeze-state flag.
|
|
42
|
+
# Mutating methods must call `check_frozen!` before changing state.
|
|
43
|
+
#
|
|
44
|
+
# @example Track freezing separately from storage
|
|
45
|
+
# class Tally
|
|
46
|
+
# include Farce::Shareable::Tracked
|
|
47
|
+
#
|
|
48
|
+
# def initialize
|
|
49
|
+
# @counter = Farce::Counter.new
|
|
50
|
+
# super
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# def increment
|
|
54
|
+
# check_frozen!
|
|
55
|
+
# @counter.increment
|
|
56
|
+
# end
|
|
57
|
+
# end
|
|
58
|
+
#
|
|
59
|
+
# tally = Tally.new
|
|
60
|
+
# tally.frozen? # => false
|
|
61
|
+
# tally.freeze
|
|
62
|
+
# tally.increment # raises FrozenError for the tally
|
|
63
|
+
module Tracked
|
|
64
|
+
include Shareable
|
|
65
|
+
include Internal::Freeze::Tracked
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# A structurally frozen service object that does not support logical freezing.
|
|
69
|
+
#
|
|
70
|
+
# @example Publish a service that must remain mutable
|
|
71
|
+
# class Inbox
|
|
72
|
+
# include Farce::Shareable::Unfreezable
|
|
73
|
+
#
|
|
74
|
+
# def initialize
|
|
75
|
+
# @queue = Farce::Queue.new
|
|
76
|
+
# super
|
|
77
|
+
# end
|
|
78
|
+
#
|
|
79
|
+
# def push(value) = @queue.push(value)
|
|
80
|
+
# end
|
|
81
|
+
#
|
|
82
|
+
# inbox = Inbox.new
|
|
83
|
+
# inbox.frozen? # => false
|
|
84
|
+
# inbox.freeze # raises TypeError
|
|
85
|
+
module Unfreezable
|
|
86
|
+
include Shareable
|
|
87
|
+
include Internal::Freeze::Unfreezable
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# A native object that publishes its initialized payload without structural freezing.
|
|
91
|
+
# Requires a backend that already implements safe publication and frozen checks.
|
|
92
|
+
# Including this module alone cannot make an ordinary Ruby object shareable.
|
|
93
|
+
# Native subclasses must not add Ruby instance variables on CRuby.
|
|
94
|
+
#
|
|
95
|
+
# @example Extend a counter while preserving native publication
|
|
96
|
+
# class Tally < Farce::Counter
|
|
97
|
+
# include Farce::Shareable::Native
|
|
98
|
+
#
|
|
99
|
+
# def increment_twice = increment(2)
|
|
100
|
+
# end
|
|
101
|
+
#
|
|
102
|
+
# tally = Tally.new
|
|
103
|
+
# tally.frozen? # => false
|
|
104
|
+
# Ractor.shareable?(tally) # => true
|
|
105
|
+
# tally.freeze
|
|
106
|
+
# tally.increment_twice # raises FrozenError
|
|
107
|
+
module Native
|
|
108
|
+
include Shareable
|
|
109
|
+
include Internal::Freeze::Native
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# An immutable object whose structural and logical frozen states are the same.
|
|
113
|
+
# Set instance variables before calling `super` from `initialize`.
|
|
114
|
+
#
|
|
115
|
+
# @example Publish an immutable value
|
|
116
|
+
# class Point
|
|
117
|
+
# include Farce::Shareable::Immutable
|
|
118
|
+
# attr_reader :x, :y
|
|
119
|
+
#
|
|
120
|
+
# def initialize(x, y)
|
|
121
|
+
# @x, @y = x, y
|
|
122
|
+
# super()
|
|
123
|
+
# end
|
|
124
|
+
# end
|
|
125
|
+
#
|
|
126
|
+
# point = Point.new(1, 2)
|
|
127
|
+
# point.frozen? # => true
|
|
128
|
+
# Ractor.shareable?(point) # => true
|
|
129
|
+
module Immutable
|
|
130
|
+
include Shareable
|
|
131
|
+
include Internal::Freeze::Immutable
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Make sure to call `super` if you include this module.
|
|
135
|
+
# Accepts any arguments and passes them on to the superclass initializer.
|
|
136
|
+
def initialize(...)
|
|
137
|
+
super
|
|
138
|
+
publish_shareable
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @return [Boolean] true
|
|
142
|
+
# @see Unshareable#ractor_shareable?
|
|
143
|
+
def ractor_shareable? = true
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
# Publish a Ruby facade without dispatching its logical `freeze` method.
|
|
148
|
+
def publish_shareable = Internal::Freeze.publish(self)
|
|
149
|
+
end
|
|
150
|
+
end
|
data/lib/farce/signal.rb
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable notification signal for changes to separately synchronized state.
|
|
7
|
+
# Broadcast after updating the state. Waiters check that state again after each notification.
|
|
8
|
+
# A broadcast wakes all current waiters and advances the signal's generation.
|
|
9
|
+
#
|
|
10
|
+
# @example Waiting for a resource
|
|
11
|
+
# signal = Farce::Signal.new
|
|
12
|
+
# resources = Farce::Strict::Queue.new
|
|
13
|
+
# producer = Thread.new do
|
|
14
|
+
# resources.push(:resource)
|
|
15
|
+
# signal.broadcast
|
|
16
|
+
# end
|
|
17
|
+
# resource = signal.wait_until(timeout: 1.0) { resources.try_pop }
|
|
18
|
+
# producer.join
|
|
19
|
+
# resource # => :resource, or nil if the timeout expires
|
|
20
|
+
#
|
|
21
|
+
class Signal
|
|
22
|
+
include Internal::Noncopyable
|
|
23
|
+
include Internal::Inspect
|
|
24
|
+
include Shareable::Unfreezable
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@signal = Internal::Signal.new
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Read the current generation. Take this snapshot before checking external state.
|
|
32
|
+
# @return [Integer] the current generation, initially zero
|
|
33
|
+
def generation = @signal.generation
|
|
34
|
+
|
|
35
|
+
# Advance the generation and wake all current waiters.
|
|
36
|
+
# @return [Integer] the new generation
|
|
37
|
+
def broadcast = @signal.broadcast
|
|
38
|
+
|
|
39
|
+
# @return [Integer] the number of callers currently waiting
|
|
40
|
+
def num_waiting = @signal.num_waiting
|
|
41
|
+
|
|
42
|
+
# Wait for the generation to change. Without a snapshot, wait for the next broadcast.
|
|
43
|
+
# Return immediately if the supplied generation has already changed.
|
|
44
|
+
# @param observed [Integer, nil] a generation snapshot, or nil to take a snapshot now
|
|
45
|
+
# @param timeout [Numeric, nil] the maximum seconds to wait, or nil to wait indefinitely
|
|
46
|
+
# @yield called without arguments when the timeout expires
|
|
47
|
+
# @return [Integer, BasicObject, nil] the changed generation, or the fallback result or nil on timeout
|
|
48
|
+
def wait(observed = nil, timeout: nil, &) = @signal.wait(observed, timeout:, &)
|
|
49
|
+
|
|
50
|
+
# Check a condition immediately, then after broadcasts while it remains truthy.
|
|
51
|
+
# Uses the same timeout budget and notification handling as {#wait_until}.
|
|
52
|
+
# @param timeout [Numeric, nil] the total seconds available, or nil to wait indefinitely
|
|
53
|
+
# @yield checks the condition
|
|
54
|
+
# @yieldreturn [BasicObject] a truthy value to keep waiting, or nil or false to stop
|
|
55
|
+
# @return [true, nil] true when the condition becomes false, or nil on timeout
|
|
56
|
+
# @raise [LocalJumpError] if no block is given
|
|
57
|
+
def wait_while(timeout: nil)
|
|
58
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
59
|
+
wait_until(timeout:) { !yield }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Check a condition immediately, then check again after broadcasts until it succeeds.
|
|
63
|
+
# Take a generation snapshot before every check so a broadcast during the check is not missed.
|
|
64
|
+
# The block runs in the caller without holding a signal lock. Synchronize access to shared state
|
|
65
|
+
# inside the block, and claim the resource there if another waiter could consume it.
|
|
66
|
+
#
|
|
67
|
+
# One timeout budget covers all checks and waits. The block is not interrupted when time expires.
|
|
68
|
+
# A timeout of zero checks once without waiting. Exceptions from the block propagate to the caller.
|
|
69
|
+
#
|
|
70
|
+
# @param timeout [Numeric, nil] the total seconds available, or nil to wait indefinitely
|
|
71
|
+
# @yield checks or claims the resource
|
|
72
|
+
# @yieldreturn [BasicObject, nil, false] a truthy result on success, or nil or false to keep waiting
|
|
73
|
+
# @return [BasicObject, nil] the first truthy block result, or nil on timeout
|
|
74
|
+
# @raise [LocalJumpError] if no block is given
|
|
75
|
+
# @raise [ArgumentError] if the timeout is negative or not finite
|
|
76
|
+
def wait_until(timeout: nil)
|
|
77
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
78
|
+
Internal.with_timeout(timeout) do |_, deadline|
|
|
79
|
+
observed = generation
|
|
80
|
+
result = yield
|
|
81
|
+
return result if result
|
|
82
|
+
|
|
83
|
+
remaining = deadline - Clock.now if deadline
|
|
84
|
+
return if remaining && !remaining.positive?
|
|
85
|
+
return unless wait(observed, timeout: remaining)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @api private
|
|
90
|
+
def inspect_with(inspector)
|
|
91
|
+
super do
|
|
92
|
+
inspector.attributes({ generation:, num_waiting: })
|
|
93
|
+
yield if block_given?
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable concurrent set maintained in ascending order.
|
|
7
|
+
# Membership uses `<=>`. Comparator-equivalent elements occupy one slot.
|
|
8
|
+
# Transfer modes have the same behavior and restrictions as Farce::Set.
|
|
9
|
+
#
|
|
10
|
+
# @example Traverse priorities in order
|
|
11
|
+
# priorities = Farce::SortedSet[30, 10, 20]
|
|
12
|
+
# priorities.to_a # => [10, 20, 30]
|
|
13
|
+
class SortedSet < Farce::Abstract::SortedSet
|
|
14
|
+
include Shareable::Delegated
|
|
15
|
+
|
|
16
|
+
# The default transfer mode for elements.
|
|
17
|
+
# @return [Symbol] The configured transfer mode.
|
|
18
|
+
def mode = @manager.mode
|
|
19
|
+
|
|
20
|
+
protected
|
|
21
|
+
|
|
22
|
+
def value_modes? = true
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def initialize_value_mode(mode)
|
|
27
|
+
mode = :copy if UNDEFINED.equal?(mode)
|
|
28
|
+
@manager = ModeManager.new(mode:)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def new_map(entries = nil, compare_keys_by_identity: false, **)
|
|
32
|
+
raise ArgumentError, "sorted sets do not support identity comparison" if compare_keys_by_identity
|
|
33
|
+
Farce::Strict::TreeMap.new(entries)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable atomic reference that strongly retains shareable values directly.
|
|
8
|
+
# Values are stored without envelope wrapping or transfer modes.
|
|
9
|
+
#
|
|
10
|
+
# @example Updating a counter atomically
|
|
11
|
+
# counter = Farce::Strict::Atom.new(0)
|
|
12
|
+
# counter.update { |count| count + 1 } # => 1
|
|
13
|
+
# counter.compare_and_set(1, 2) # => true
|
|
14
|
+
# counter.value # => 2
|
|
15
|
+
#
|
|
16
|
+
# @example Keeping an immutable snapshot
|
|
17
|
+
# snapshot = [1, 2, 3].freeze
|
|
18
|
+
# atom = Farce::Strict::Atom.new(snapshot)
|
|
19
|
+
# atom.value.equal?(snapshot) # => true
|
|
20
|
+
# atom.update { |items| (items + [4]).freeze } # => [1, 2, 3, 4]
|
|
21
|
+
class Atom < Abstract::Atom
|
|
22
|
+
include Shareable::Delegated
|
|
23
|
+
|
|
24
|
+
# @param value [BasicObject, nil] the initial shareable value
|
|
25
|
+
# @param compare_by_identity [Boolean] whether comparisons use object identity instead of equality
|
|
26
|
+
def initialize(value = nil, compare_by_identity: false)
|
|
27
|
+
@atom = Internal::StrictAtom.new(value, compare_by_identity:)
|
|
28
|
+
super()
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private def freeze_backend = @atom
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable rendezvous that exchanges shareable values directly.
|
|
8
|
+
# Values retain their identity and envelopes are returned unopened.
|
|
9
|
+
class Exchanger < Abstract::Exchanger
|
|
10
|
+
include Shareable::Unfreezable
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@exchanger = Internal::Exchanger.new
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# (see Abstract::Exchanger#exchange)
|
|
18
|
+
# @raise [Ractor::IsolationError] if the offered value is not Ractor-shareable
|
|
19
|
+
def exchange(offered, timeout: nil, &)
|
|
20
|
+
raise Ractor::IsolationError, "value must be Ractor-shareable" unless Ractor.shareable?(offered)
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
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 Strict
|
|
7
|
+
# A shareable lazy value that retains its shareable result directly.
|
|
8
|
+
# The factory runs once, even when threads or Ractors access it concurrently.
|
|
9
|
+
# A failed factory or an unshareable result can be retried on the next access.
|
|
10
|
+
#
|
|
11
|
+
# @example Compute one shared snapshot
|
|
12
|
+
# lazy = Farce::Strict::Lazy.new { [:ready].freeze }
|
|
13
|
+
# lazy.value # => [:ready]
|
|
14
|
+
class Lazy < Abstract::Lazy
|
|
15
|
+
include Shareable::Tracked
|
|
16
|
+
|
|
17
|
+
# Resolve and freeze the slot without freezing the result.
|
|
18
|
+
# @return [self]
|
|
19
|
+
def freeze
|
|
20
|
+
value
|
|
21
|
+
internal_atom.freeze
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
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 Strict
|
|
7
|
+
# @!parse
|
|
8
|
+
# # A {Reference} for a {Strict::Lazy} value.
|
|
9
|
+
# # Delegates to the result after computing it on first access.
|
|
10
|
+
# # Calling `freeze` resolves and freezes the target.
|
|
11
|
+
# #
|
|
12
|
+
# # @example
|
|
13
|
+
# # reference = Farce::Strict::LazyRef.new { [:ready].freeze }
|
|
14
|
+
# # reference.first # => :ready
|
|
15
|
+
# class LazyRef < Farce::Reference
|
|
16
|
+
# # @overload initialize(factory)
|
|
17
|
+
# # @param factory [Class, Proc, #call] the factory for the lazy value, which must be shareable
|
|
18
|
+
# # @overload initialize(self: nil)
|
|
19
|
+
# # @param self [BasicObject] the receiver to bind to the block, which must be shareable
|
|
20
|
+
# # @yield computes the value on first access
|
|
21
|
+
# # @yieldreturn [BasicObject] the computed result
|
|
22
|
+
# def initialize(...) = nil
|
|
23
|
+
# end
|
|
24
|
+
LazyRef = Reference[Farce::Strict::Lazy]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable lease that stores a shareable resource directly.
|
|
8
|
+
# Construction and checkin reject non-shareable resources without freezing them.
|
|
9
|
+
# Checkout coordinates callers. Other references remain usable, so callers
|
|
10
|
+
# must honor the checkout when accessing a mutable resource.
|
|
11
|
+
#
|
|
12
|
+
# @example Coordinating several changes to shareable state
|
|
13
|
+
# lease = Farce::Strict::Lease.new { Farce::Strict::Map.new }
|
|
14
|
+
# lease.checkout do |state|
|
|
15
|
+
# state[:status] = :ready
|
|
16
|
+
# state[:generation] = 1
|
|
17
|
+
# end
|
|
18
|
+
# lease.checkout { |state| state[:status] } # => :ready
|
|
19
|
+
class Lease < Abstract::Lease
|
|
20
|
+
include Shareable::Unfreezable
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def new_internal_lease(resource) = Internal::StrictLease.new(resource)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable map that stores independently leased shareable resources directly.
|
|
8
|
+
# Initial resources, insertions, and replacements must be shareable. They are
|
|
9
|
+
# not automatically frozen. Other references remain usable, so callers must
|
|
10
|
+
# honor the checkout when accessing mutable resources.
|
|
11
|
+
#
|
|
12
|
+
# @example Updating shareable resources in an automatic lease scope
|
|
13
|
+
# leases = Farce::Strict::LeaseMap.new do
|
|
14
|
+
# { primary: Farce::Strict::Map.new, replica: Farce::Strict::Map.new }
|
|
15
|
+
# end
|
|
16
|
+
# leases.auto_lease do
|
|
17
|
+
# leases[:primary][:status] = :ready
|
|
18
|
+
# leases[:replica][:status] = :ready
|
|
19
|
+
# end
|
|
20
|
+
# leases.checkout(:primary) { |state| state[:status] } # => :ready
|
|
21
|
+
class LeaseMap < Abstract::LeaseMap
|
|
22
|
+
include Shareable::Unfreezable
|
|
23
|
+
|
|
24
|
+
def shareable_values? = true
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def new_internal_lease_map(mapping)
|
|
29
|
+
Internal::StrictLeaseMap.new(mapping, lease_class: Farce::Strict::Lease, registry_class: Farce::Strict::Map)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable pool that stores shareable resources directly.
|
|
8
|
+
# Factory results and checkin replacements must be shareable. They are not
|
|
9
|
+
# automatically frozen. Other references remain usable during checkout,
|
|
10
|
+
# so callers must honor the checkout when accessing mutable resources.
|
|
11
|
+
#
|
|
12
|
+
# @example Reusing shareable resources with bounded concurrency
|
|
13
|
+
# pool = Farce::Strict::LeasePool.new(max_size: 2) { Farce::Strict::Map.new }
|
|
14
|
+
# pool.checkout { |state| state[:uses] = (state[:uses] || 0) + 1 }
|
|
15
|
+
# pool.checkout { |state| state[:uses] } # => 1
|
|
16
|
+
class LeasePool < Abstract::LeasePool
|
|
17
|
+
include Shareable::Unfreezable
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def prepare_factory(factory)
|
|
22
|
+
Ractor.shareable?(factory) ? factory : Ractor.shareable_proc(&factory)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def new_internal_pool(max_size) = Internal::StrictLeasePool.new(max_size)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable LFU map that stores shareable values directly.
|
|
8
|
+
class LFUMap < Abstract::LFUMap
|
|
9
|
+
include Shareable::Delegated
|
|
10
|
+
|
|
11
|
+
# (see Abstract::Map#shareable_keys?)
|
|
12
|
+
def shareable_keys? = true
|
|
13
|
+
|
|
14
|
+
# (see Abstract::Map#shareable_values?)
|
|
15
|
+
def shareable_values? = true
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def new_bounded_map(...) = Internal::StrictLFUMap.new(...)
|
|
20
|
+
def freeze_backend = internal_map
|
|
21
|
+
|
|
22
|
+
def new_key_locks(compare_keys_by_identity:)
|
|
23
|
+
Internal::KeyLockMap.new(registry_class: Farce::Strict::Map, compare_keys_by_identity:)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable LRU map that stores shareable values directly.
|
|
8
|
+
# Keys must be shareable, except equality-mode mutable strings that can be snapshotted.
|
|
9
|
+
class LRUMap < Abstract::LRUMap
|
|
10
|
+
include Shareable::Delegated
|
|
11
|
+
|
|
12
|
+
# (see Abstract::Map#shareable_keys?)
|
|
13
|
+
def shareable_keys? = true
|
|
14
|
+
|
|
15
|
+
# (see Abstract::Map#shareable_values?)
|
|
16
|
+
def shareable_values? = true
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def new_bounded_map(...) = Internal::StrictLRUMap.new(...)
|
|
21
|
+
def freeze_backend = internal_map
|
|
22
|
+
|
|
23
|
+
def new_key_locks(compare_keys_by_identity:)
|
|
24
|
+
Internal::KeyLockMap.new(registry_class: Farce::Strict::Map, compare_keys_by_identity:)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable concurrent map that stores shareable keys and values directly.
|
|
8
|
+
# Updates on different keys can run concurrently.
|
|
9
|
+
#
|
|
10
|
+
# Clearing the map invalidates unfinished updates so they cannot restore removed entries.
|
|
11
|
+
#
|
|
12
|
+
# `dup` and `clone` copy entries into independent storage while sharing stored values.
|
|
13
|
+
# `dup` and ordinary `clone` remain Ractor-shareable.
|
|
14
|
+
#
|
|
15
|
+
# @example Atomically counting occurrences
|
|
16
|
+
# counts = Farce::Strict::Map.new
|
|
17
|
+
# counts.upsert(:ruby, 1) { |count| count + 1 } # => 1
|
|
18
|
+
# counts.upsert(:ruby, 1) { |count| count + 1 } # => 2
|
|
19
|
+
class Map < Abstract::ConcurrentMap
|
|
20
|
+
include Shareable::Delegated
|
|
21
|
+
|
|
22
|
+
# @!macro map_initialization
|
|
23
|
+
def initialize(
|
|
24
|
+
initial_mapping = nil,
|
|
25
|
+
normalize_keys: nil,
|
|
26
|
+
compare_by_identity: false,
|
|
27
|
+
compare_keys_by_identity: compare_by_identity,
|
|
28
|
+
compare_values_by_identity: compare_by_identity
|
|
29
|
+
)
|
|
30
|
+
initial_mapping = convert_entries(initial_mapping)
|
|
31
|
+
restoring = Internal::KeyNormalizer.restoration?(normalize_keys)
|
|
32
|
+
normalizer = Internal::KeyNormalizer.build(normalize_keys, shareable: true)
|
|
33
|
+
populate = initial_mapping && ((normalizer && !restoring) || !initial_mapping.is_a?(Hash))
|
|
34
|
+
@map = Internal::StrictMap.new(
|
|
35
|
+
populate ? nil : initial_mapping,
|
|
36
|
+
compare_by_identity:,
|
|
37
|
+
compare_keys_by_identity:,
|
|
38
|
+
compare_values_by_identity:,
|
|
39
|
+
)
|
|
40
|
+
Internal::KeyNormalizer.install_concurrent(self, normalizer) unless restoring
|
|
41
|
+
initial_mapping.each { |key, value| self[key] = value } if populate
|
|
42
|
+
Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
|
|
43
|
+
super()
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def shareable_keys? = true
|
|
47
|
+
def shareable_values? = true
|
|
48
|
+
|
|
49
|
+
private def freeze_backend = internal_map
|
|
50
|
+
|
|
51
|
+
Internal.prepare_map_access(self, :strict)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable record whose atoms retain only shareable values.
|
|
8
|
+
# Use {Abstract::Molecule.define} to declare named fields.
|
|
9
|
+
# Explicitly supplied atoms keep their own storage and comparison policies.
|
|
10
|
+
class Molecule < Abstract::Molecule
|
|
11
|
+
include Shareable
|
|
12
|
+
|
|
13
|
+
private def create_atom(_, value) = Atom.new(value, compare_by_identity: compare_by_identity?)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Strict
|
|
7
|
+
# A Ractor-shareable port that accepts shareable messages directly.
|
|
8
|
+
# Messages retain their identity and envelopes are returned unopened.
|
|
9
|
+
# Only the creating Ractor can receive messages or close the port.
|
|
10
|
+
#
|
|
11
|
+
# @example Receive an already prepared message
|
|
12
|
+
# port = Farce::Strict::Port.new
|
|
13
|
+
# message = [:ready, 42].freeze
|
|
14
|
+
# port << message
|
|
15
|
+
# port.receive.equal?(message) # => true
|
|
16
|
+
# port.close
|
|
17
|
+
#
|
|
18
|
+
# @!method initialize
|
|
19
|
+
# Creates a port without transfer modes.
|
|
20
|
+
class Port < Internal::Port
|
|
21
|
+
include Abstract::Port
|
|
22
|
+
|
|
23
|
+
# @!visibility private
|
|
24
|
+
# (see #initialize)
|
|
25
|
+
# CRuby 3.4's backend also accepts an existing port or Ractor.
|
|
26
|
+
# Keep construction argument-free on every runtime.
|
|
27
|
+
def self.new = super # rubocop:disable Lint/UselessMethodDefinition
|
|
28
|
+
|
|
29
|
+
# (see Abstract::Port#send)
|
|
30
|
+
# @raise [Farce::Ractor::IsolationError] if the message is not Ractor-shareable
|
|
31
|
+
def send(message)
|
|
32
|
+
raise Ractor::IsolationError, "value must be Ractor-shareable" unless Ractor.shareable?(message)
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [String] a string representation of the port
|
|
37
|
+
def inspect = super.sub(/\A#<.+? (?=(?:to|id):#?\d+)/, "#<Farce::Strict::Port ")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|