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,694 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
# @!group Dry Types Integration
|
|
6
|
+
require "farce"
|
|
7
|
+
require "dry/types"
|
|
8
|
+
|
|
9
|
+
module Farce
|
|
10
|
+
module Internal # :nodoc: all
|
|
11
|
+
# Implements the optional dry-types collection import.
|
|
12
|
+
module DryTypes
|
|
13
|
+
# Farce output configuration shared by the imported collection types.
|
|
14
|
+
class Configuration
|
|
15
|
+
VARIANTS = {
|
|
16
|
+
shared: Farce,
|
|
17
|
+
strict: Farce::Strict,
|
|
18
|
+
unshared: Farce::Unshared,
|
|
19
|
+
local: Farce::Local,
|
|
20
|
+
}.freeze
|
|
21
|
+
private_constant :VARIANTS
|
|
22
|
+
|
|
23
|
+
# The Farce collection family produced by the imported types.
|
|
24
|
+
# @return [Symbol] :shared, :strict, :unshared, or :local.
|
|
25
|
+
# @api private
|
|
26
|
+
attr_reader :variant
|
|
27
|
+
|
|
28
|
+
# The transfer mode for shared collections.
|
|
29
|
+
# @return [Symbol, Object] The selected mode or Farce's undefined sentinel.
|
|
30
|
+
# @api private
|
|
31
|
+
attr_reader :mode
|
|
32
|
+
|
|
33
|
+
# The storage scope for local collections.
|
|
34
|
+
# @return [Symbol, Object] The selected scope or Farce's undefined sentinel.
|
|
35
|
+
# @api private
|
|
36
|
+
attr_reader :scope
|
|
37
|
+
|
|
38
|
+
# Create validated Farce output configuration.
|
|
39
|
+
# @param variant [Symbol] The Farce collection family to construct.
|
|
40
|
+
# @param mode [Symbol, Object] The shared transfer mode or the undefined sentinel.
|
|
41
|
+
# @param scope [Symbol, Object] The local storage scope or the undefined sentinel.
|
|
42
|
+
# @return [Configuration] The frozen configuration.
|
|
43
|
+
# @api private
|
|
44
|
+
def initialize(variant:, mode: UNDEFINED, scope: UNDEFINED)
|
|
45
|
+
@variant = variant
|
|
46
|
+
@mode = mode
|
|
47
|
+
@scope = scope
|
|
48
|
+
validate!
|
|
49
|
+
freeze
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Resolve the configured Farce collection class.
|
|
53
|
+
# @param kind [Symbol] The lowercase Farce type name.
|
|
54
|
+
# @return [Class] The Farce class for the configured variant.
|
|
55
|
+
# @api private
|
|
56
|
+
def target(kind) = VARIANTS.fetch(variant).const_get(kind.to_s.capitalize, false)
|
|
57
|
+
|
|
58
|
+
# Report whether the configured Farce family defines a public type.
|
|
59
|
+
# @param kind [Symbol] The Farce type name in lowercase.
|
|
60
|
+
# @return [Boolean] Whether the variant supports that type.
|
|
61
|
+
# @api private
|
|
62
|
+
def target?(kind) = VARIANTS.fetch(variant).const_defined?(kind.to_s.capitalize, false)
|
|
63
|
+
|
|
64
|
+
# Return keywords accepted by the configured Farce constructor.
|
|
65
|
+
# @param kind [Symbol] The Farce value kind being constructed.
|
|
66
|
+
# @return [Hash] The mode or scope keywords for construction.
|
|
67
|
+
# @api private
|
|
68
|
+
def constructor_options(kind)
|
|
69
|
+
case variant
|
|
70
|
+
when :shared
|
|
71
|
+
return {} unless %i[vector map set atom].include?(kind)
|
|
72
|
+
|
|
73
|
+
{ mode: UNDEFINED.equal?(mode) ? :copy : mode }
|
|
74
|
+
when :local then { scope: UNDEFINED.equal?(scope) ? :ractor : scope }
|
|
75
|
+
else {}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Copy the configuration with output options replaced.
|
|
80
|
+
# @param kind [Symbol] The Farce value kind being configured.
|
|
81
|
+
# @param mode [Symbol, Object] The shared transfer mode or the undefined sentinel.
|
|
82
|
+
# @param scope [Symbol, Object] The local storage scope or the undefined sentinel.
|
|
83
|
+
# @return [Configuration] A validated configuration.
|
|
84
|
+
# @api private
|
|
85
|
+
def with(kind:, mode: UNDEFINED, scope: UNDEFINED)
|
|
86
|
+
if %i[counter flag].include?(kind) && !UNDEFINED.equal?(mode)
|
|
87
|
+
raise ArgumentError, "mode is not supported by Farce::#{kind.to_s.capitalize}"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
mode = @mode if UNDEFINED.equal?(mode)
|
|
91
|
+
scope = @scope if UNDEFINED.equal?(scope)
|
|
92
|
+
self.class.new(variant:, mode:, scope:)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def validate!
|
|
98
|
+
unless %i[shared strict unshared local].include?(variant)
|
|
99
|
+
raise ArgumentError, "unknown Farce collection variant: #{variant.inspect}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if variant == :shared
|
|
103
|
+
raise ArgumentError, "scope is only supported by the local variant" unless UNDEFINED.equal?(scope)
|
|
104
|
+
raise ArgumentError, "mode :move is not supported by dry-types constructors" if mode == :move
|
|
105
|
+
return if UNDEFINED.equal?(mode) || %i[copy local make_shareable raise shareable_copy].include?(mode)
|
|
106
|
+
|
|
107
|
+
raise ArgumentError, "invalid mode: #{mode.inspect}"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
raise ArgumentError, "mode is only supported by the shared variant" unless UNDEFINED.equal?(mode)
|
|
111
|
+
if variant == :local
|
|
112
|
+
selected_scope = UNDEFINED.equal?(scope) ? :ractor : scope
|
|
113
|
+
unless Farce::SCOPES.include?(selected_scope)
|
|
114
|
+
raise ArgumentError, "invalid scope: #{selected_scope.inspect}"
|
|
115
|
+
end
|
|
116
|
+
return
|
|
117
|
+
end
|
|
118
|
+
return if UNDEFINED.equal?(scope)
|
|
119
|
+
|
|
120
|
+
raise ArgumentError, "scope is only supported by the local variant"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# A regular dry type that constructs a Farce value.
|
|
125
|
+
#
|
|
126
|
+
# @!method [](input = Dry::Types::Undefined)
|
|
127
|
+
# Apply this type using dry-types bracket syntax.
|
|
128
|
+
# @param input [Object] The input value.
|
|
129
|
+
# @yield [partial] Handle a coercion or construction failure.
|
|
130
|
+
# @yieldparam partial [Object] The partial value supplied by dry-types.
|
|
131
|
+
# @yieldreturn [Object] The fallback returned instead of a Farce value.
|
|
132
|
+
# @return [Object, nil] The Farce value, nil for an optional type, or the failure block result.
|
|
133
|
+
#
|
|
134
|
+
# @!method ===(input)
|
|
135
|
+
# Test whether input can produce a valid Farce value.
|
|
136
|
+
# @param input [Object] The value to test.
|
|
137
|
+
# @return [Boolean] Whether applying the type succeeds.
|
|
138
|
+
class CollectionType
|
|
139
|
+
include ::Dry::Types::Type
|
|
140
|
+
include ::Dry::Types::Builder
|
|
141
|
+
|
|
142
|
+
# The dry type evaluated before Farce construction.
|
|
143
|
+
# @return [Dry::Types::Type] The source type.
|
|
144
|
+
attr_reader :source
|
|
145
|
+
|
|
146
|
+
# The Farce value kind produced by this type.
|
|
147
|
+
# @return [Symbol] The lowercase Farce type name.
|
|
148
|
+
# @api private
|
|
149
|
+
attr_reader :kind
|
|
150
|
+
|
|
151
|
+
# The Farce output configuration.
|
|
152
|
+
# @return [Configuration] The variant and ownership settings.
|
|
153
|
+
# @api private
|
|
154
|
+
attr_reader :configuration
|
|
155
|
+
|
|
156
|
+
# Wrap a dry type with Farce construction.
|
|
157
|
+
# @param source [Dry::Types::Type] The source type.
|
|
158
|
+
# @param kind [Symbol] The lowercase Farce type name.
|
|
159
|
+
# @param configuration [Configuration] The Farce output configuration.
|
|
160
|
+
# @return [CollectionType] The configured dry type.
|
|
161
|
+
# @api private
|
|
162
|
+
def initialize(source, kind:, configuration:)
|
|
163
|
+
@source = source
|
|
164
|
+
@kind = kind
|
|
165
|
+
@configuration = configuration
|
|
166
|
+
@type = DryTypes.build_type(source, kind, configuration)
|
|
167
|
+
freeze
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Apply validation, coercion, and Farce construction to input.
|
|
171
|
+
# @param input [Object] The input value.
|
|
172
|
+
# @yield [partial] Handle a coercion or construction failure.
|
|
173
|
+
# @yieldparam partial [Object] The partial value supplied by dry-types.
|
|
174
|
+
# @yieldreturn [Object] The fallback returned instead of a Farce value.
|
|
175
|
+
# @return [Object, nil] The Farce value, nil for an optional type, or the failure block result.
|
|
176
|
+
def call(input = ::Dry::Types::Undefined, &) = @type.call(input, &)
|
|
177
|
+
alias [] call
|
|
178
|
+
|
|
179
|
+
# Apply the wrapped constructor without a failure callback.
|
|
180
|
+
# @param input [Object] The value to process.
|
|
181
|
+
# @return [Object, nil] The Farce value or nil for an optional type.
|
|
182
|
+
# @api private
|
|
183
|
+
def call_unsafe(input) = @type.call_unsafe(input)
|
|
184
|
+
|
|
185
|
+
# Apply the wrapped constructor with dry-types safe-call behavior.
|
|
186
|
+
# @param input [Object] The value to process.
|
|
187
|
+
# @yield [partial] Handle a coercion or construction failure.
|
|
188
|
+
# @yieldparam partial [Object] The partial value supplied by dry-types.
|
|
189
|
+
# @yieldreturn [Object] The fallback result.
|
|
190
|
+
# @return [Object, nil] The Farce value, nil for an optional type, or the failure block result.
|
|
191
|
+
# @api private
|
|
192
|
+
def call_safe(input, &) = @type.call_safe(input, &)
|
|
193
|
+
|
|
194
|
+
# Try to construct a Farce value and return a dry-types result.
|
|
195
|
+
# @param input [Object] The value to process.
|
|
196
|
+
# @yield [failure] Handle a failed attempt.
|
|
197
|
+
# @yieldparam failure [Dry::Types::Result::Failure] The failure result.
|
|
198
|
+
# @yieldreturn [Object] The fallback result.
|
|
199
|
+
# @return [Dry::Types::Result, Object] The result or failure block value.
|
|
200
|
+
def try(input, &) = @type.try(input, &)
|
|
201
|
+
|
|
202
|
+
# Test whether input can produce a valid Farce value.
|
|
203
|
+
# @param input [Object] The value to test.
|
|
204
|
+
# @return [Boolean] Whether applying the type succeeds.
|
|
205
|
+
def valid?(input = ::Dry::Types::Undefined) = @type.valid?(input)
|
|
206
|
+
alias === valid?
|
|
207
|
+
|
|
208
|
+
# Return the output primitive used by a non-optional type.
|
|
209
|
+
# @return [Class] The configured Farce collection class.
|
|
210
|
+
# @api private
|
|
211
|
+
def primitive = @type.primitive
|
|
212
|
+
|
|
213
|
+
# Test whether a value is accepted by the output type.
|
|
214
|
+
# @param input [Object] The value to test.
|
|
215
|
+
# @return [Boolean] Whether the value is a configured Farce object or accepted nil.
|
|
216
|
+
def primitive?(input) = @type.primitive?(input)
|
|
217
|
+
|
|
218
|
+
# Return the inherited namespace for a non-optional source type.
|
|
219
|
+
# @return [String, nil] The source namespace when one is configured.
|
|
220
|
+
# @api private
|
|
221
|
+
def namespace = @type.namespace
|
|
222
|
+
|
|
223
|
+
# Return the output type name.
|
|
224
|
+
# @return [String] The Farce class or optional union name.
|
|
225
|
+
def name = @type.name
|
|
226
|
+
|
|
227
|
+
# Report whether this is a default type.
|
|
228
|
+
# @return [Boolean] Whether a default is configured.
|
|
229
|
+
def default? = @type.default?
|
|
230
|
+
|
|
231
|
+
# Report whether this type contains constraints.
|
|
232
|
+
# @return [Boolean] Whether constraints are present.
|
|
233
|
+
def constrained? = @type.constrained?
|
|
234
|
+
|
|
235
|
+
# Report whether this type accepts nil.
|
|
236
|
+
# @return [Boolean] Whether the type is optional.
|
|
237
|
+
def optional? = @type.optional?
|
|
238
|
+
|
|
239
|
+
# Build a successful dry-types result.
|
|
240
|
+
# @param input [Object] The successful value.
|
|
241
|
+
# @return [Dry::Types::Result::Success] The success result.
|
|
242
|
+
# @api private
|
|
243
|
+
def success(input) = @type.success(input)
|
|
244
|
+
|
|
245
|
+
# Build a failed dry-types result.
|
|
246
|
+
# @param input [Object] The failed input.
|
|
247
|
+
# @param error [Dry::Types::CoercionError] The coercion error.
|
|
248
|
+
# @return [Dry::Types::Result::Failure] The failure result.
|
|
249
|
+
# @api private
|
|
250
|
+
def failure(input, error) = @type.failure(input, error)
|
|
251
|
+
|
|
252
|
+
# Return the dry-types abstract syntax tree.
|
|
253
|
+
# @param meta [Boolean] Whether metadata is included.
|
|
254
|
+
# @return [Array] The type AST.
|
|
255
|
+
def to_ast(meta: true) = @type.to_ast(meta:)
|
|
256
|
+
|
|
257
|
+
# Convert this type to a callable object.
|
|
258
|
+
# @return [Proc] A proc that applies the type.
|
|
259
|
+
def to_proc = proc { call(it) }
|
|
260
|
+
|
|
261
|
+
# Return the wrapped dry type representation.
|
|
262
|
+
# @return [String] The printable type representation.
|
|
263
|
+
def inspect = @type.inspect
|
|
264
|
+
|
|
265
|
+
# Return the dry-types constructor implementation.
|
|
266
|
+
# @return [Class] Dry::Types::Constructor.
|
|
267
|
+
# @api private
|
|
268
|
+
def constructor_type = ::Dry::Types::Constructor
|
|
269
|
+
|
|
270
|
+
# Read or extend this type's metadata.
|
|
271
|
+
# @overload meta
|
|
272
|
+
# @return [Hash] The current metadata.
|
|
273
|
+
# @overload meta(data)
|
|
274
|
+
# @param data [Hash] Metadata to merge into the source type.
|
|
275
|
+
# @return [CollectionType] A collection type carrying the metadata.
|
|
276
|
+
def meta(data = ::Dry::Types::Undefined)
|
|
277
|
+
return @type.meta if ::Dry::Types::Undefined.equal?(data)
|
|
278
|
+
|
|
279
|
+
self.class.new(source.meta(data), kind:, configuration:)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Return a new type without source metadata.
|
|
283
|
+
# @return [CollectionType] A new type with pristine source metadata.
|
|
284
|
+
def pristine = self.class.new(source.pristine, kind:, configuration:)
|
|
285
|
+
|
|
286
|
+
# Return a new Farce type with different output or source options.
|
|
287
|
+
# @param mode [Symbol] The transfer mode for the shared variant.
|
|
288
|
+
# @param scope [Symbol] The storage scope for the local variant.
|
|
289
|
+
# @param source_options [Hash] Options forwarded to the source dry type.
|
|
290
|
+
# @return [CollectionType] A new configured type.
|
|
291
|
+
# @raise [ArgumentError] If the Farce type does not support the requested output option.
|
|
292
|
+
def with(mode: UNDEFINED, scope: UNDEFINED, **source_options)
|
|
293
|
+
configured = configuration.with(kind:, mode:, scope:)
|
|
294
|
+
next_source = source_options.empty? ? source : source.with(**source_options)
|
|
295
|
+
self.class.new(next_source, kind:, configuration: configured)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
private
|
|
299
|
+
|
|
300
|
+
# Select post-construction constraint behavior.
|
|
301
|
+
# @return [Class] The coercible constrained type class.
|
|
302
|
+
# @api private
|
|
303
|
+
def constrained_type = ::Dry::Types::Constrained::Coercible
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# A Vector or Set type that applies a member type to every input value.
|
|
307
|
+
class SequenceType < CollectionType
|
|
308
|
+
# Apply a dry type to every member before Farce construction.
|
|
309
|
+
# @param member [Dry::Types::Type, #call] The member type.
|
|
310
|
+
# @return [SequenceType] The typed collection.
|
|
311
|
+
def of(member)
|
|
312
|
+
typed = DryTypes.collection_source(source).of(member)
|
|
313
|
+
typed = DryTypes.restore_optional_source(source, typed)
|
|
314
|
+
self.class.new(typed, kind:, configuration:)
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# An Atom type that validates or coerces its initial contents.
|
|
319
|
+
class AtomType < CollectionType
|
|
320
|
+
# Apply a dry type to the initial value before Atom construction.
|
|
321
|
+
#
|
|
322
|
+
# Later writes use the ordinary Farce Atom API and are not checked by
|
|
323
|
+
# this type.
|
|
324
|
+
# @param value_type [Dry::Types::Type] The initial value type.
|
|
325
|
+
# @return [AtomType] A new typed Atom constructor.
|
|
326
|
+
# @raise [ArgumentError] If value_type is not a dry type.
|
|
327
|
+
def of(value_type)
|
|
328
|
+
raise ArgumentError, "Atom.of requires a dry type" unless value_type.is_a?(::Dry::Types::Type)
|
|
329
|
+
|
|
330
|
+
self.class.new(value_type, kind:, configuration:)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# A Map type that supports dry-types homogeneous maps and schemas.
|
|
335
|
+
class MapType < CollectionType
|
|
336
|
+
# Apply dry types to every key and value before Farce construction.
|
|
337
|
+
# @param key_type [Dry::Types::Type] The key type.
|
|
338
|
+
# @param value_type [Dry::Types::Type] The value type.
|
|
339
|
+
# @return [MapType] The homogeneous map type.
|
|
340
|
+
def map(key_type, value_type)
|
|
341
|
+
typed = DryTypes.collection_source(source).map(key_type, value_type)
|
|
342
|
+
typed = DryTypes.restore_optional_source(source, typed)
|
|
343
|
+
self.class.new(typed, kind:, configuration:)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# Define or extend fixed keys and their dry types before Farce construction.
|
|
347
|
+
# @overload schema(keys_or_map, meta = {})
|
|
348
|
+
# Create a schema from the imported Hash source.
|
|
349
|
+
# @param keys_or_map [Hash, Array<Dry::Types::Schema::Key>] The schema definition.
|
|
350
|
+
# @param meta [Hash] Metadata applied while creating the schema.
|
|
351
|
+
# @return [MapType] The schema-backed map type.
|
|
352
|
+
# @overload schema(keys_or_map)
|
|
353
|
+
# Extend an existing schema.
|
|
354
|
+
# @param keys_or_map [Hash, Array<Dry::Types::Schema::Key>] Additional schema keys.
|
|
355
|
+
# @return [MapType] The schema-backed map type.
|
|
356
|
+
def schema(...)
|
|
357
|
+
typed = DryTypes.collection_source(source).schema(...)
|
|
358
|
+
typed = DryTypes.restore_optional_source(source, typed)
|
|
359
|
+
self.class.new(typed, kind:, configuration:)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Return a schema that rejects unknown keys.
|
|
363
|
+
# @param strict [Boolean] Whether unknown keys are rejected.
|
|
364
|
+
# @return [MapType] The configured map type.
|
|
365
|
+
def strict(strict = true) = rebuild_map_source(:strict, strict) # rubocop:disable Style/OptionalBooleanParameter
|
|
366
|
+
|
|
367
|
+
# Transform input keys before schema lookup.
|
|
368
|
+
# @param transform [#call, nil] The key transform.
|
|
369
|
+
# @yield [key] Transform an input key when no callable argument is given.
|
|
370
|
+
# @yieldparam key [Object] An input key.
|
|
371
|
+
# @yieldreturn [Object] The transformed key.
|
|
372
|
+
# @return [MapType] The configured map type.
|
|
373
|
+
def with_key_transform(transform = nil, &) = rebuild_map_source(:with_key_transform, transform, &)
|
|
374
|
+
|
|
375
|
+
# Transform schema key types when defining a schema.
|
|
376
|
+
# @param transform [#call, nil] The type transform.
|
|
377
|
+
# @yield [type] Transform a schema key type when no callable argument is given.
|
|
378
|
+
# @yieldparam type [Dry::Types::Schema::Key] A schema key type.
|
|
379
|
+
# @yieldreturn [Dry::Types::Schema::Key] The transformed key type.
|
|
380
|
+
# @return [MapType] The configured map type.
|
|
381
|
+
def with_type_transform(transform = nil, &) = rebuild_map_source(:with_type_transform, transform, &)
|
|
382
|
+
|
|
383
|
+
private
|
|
384
|
+
|
|
385
|
+
# Explicit arguments avoid losing keyword calls inside JRuby forwarding methods.
|
|
386
|
+
# rubocop:disable-next Style/ArgumentsForwarding
|
|
387
|
+
def rebuild_map_source(method, *arguments, **options, &)
|
|
388
|
+
typed = DryTypes.collection_source(source).public_send(method, *arguments, **options, &)
|
|
389
|
+
typed = DryTypes.restore_optional_source(source, typed)
|
|
390
|
+
self.class.new(typed, kind:, configuration:)
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# Import module installed by Farce.DryTypes().
|
|
395
|
+
class Import < Module
|
|
396
|
+
# Create a deferred Farce dry-types import.
|
|
397
|
+
# @param namespaces [Array<Symbol>] Explicit dry-types namespaces.
|
|
398
|
+
# @param default [Symbol, Object] The default namespace or Farce's undefined sentinel.
|
|
399
|
+
# @param aliases [Hash{Symbol => Symbol}] Dry-types namespace aliases.
|
|
400
|
+
# @param configuration [Configuration] The Farce output configuration.
|
|
401
|
+
# @return [Import] The import module.
|
|
402
|
+
# @api private
|
|
403
|
+
def initialize(namespaces, default:, aliases:, configuration:)
|
|
404
|
+
super()
|
|
405
|
+
@namespaces = namespaces.freeze
|
|
406
|
+
@default = default
|
|
407
|
+
@aliases = aliases.freeze
|
|
408
|
+
@configuration = configuration
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Install Farce types when this import is included.
|
|
412
|
+
# @param base [Module] The application type module.
|
|
413
|
+
# @return [void]
|
|
414
|
+
# @api private
|
|
415
|
+
def included(base)
|
|
416
|
+
source = source_import(base)
|
|
417
|
+
install_root(base, source)
|
|
418
|
+
install_namespaces(base, source)
|
|
419
|
+
super
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
private
|
|
423
|
+
|
|
424
|
+
def source_import(base)
|
|
425
|
+
return configured_import if explicitly_configured?
|
|
426
|
+
|
|
427
|
+
base.ancestors.find { it.is_a?(::Dry::Types::Module) } || ::Dry.Types()
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def explicitly_configured?
|
|
431
|
+
!@namespaces.empty? || !@aliases.empty? || !UNDEFINED.equal?(@default)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def configured_import
|
|
435
|
+
if UNDEFINED.equal?(@default)
|
|
436
|
+
::Dry.Types(*@namespaces, **@aliases)
|
|
437
|
+
else
|
|
438
|
+
::Dry.Types(*@namespaces, default: @default, **@aliases)
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def install_root(base, source)
|
|
443
|
+
install_collection_constants(base, source)
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def install_namespaces(base, source)
|
|
447
|
+
source.constants(false).each do |name|
|
|
448
|
+
namespace = source.const_get(name, false)
|
|
449
|
+
next unless namespace.is_a?(Module)
|
|
450
|
+
next unless relevant_namespace?(namespace)
|
|
451
|
+
|
|
452
|
+
existing = base.const_get(name) if base.const_defined?(name)
|
|
453
|
+
ensure_available!(base, name)
|
|
454
|
+
base.const_set(name, namespace_overlay(namespace, existing))
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def install_collection_constants(target, source)
|
|
459
|
+
if (array = usable_array_type(source))
|
|
460
|
+
install_constant(target, :Vector, SequenceType.new(array, kind: :vector, configuration: @configuration))
|
|
461
|
+
install_constant(target, :Set, SequenceType.new(array, kind: :set, configuration: @configuration))
|
|
462
|
+
end
|
|
463
|
+
if (hash = usable_hash_type(source))
|
|
464
|
+
install_constant(target, :Map, MapType.new(hash, kind: :map, configuration: @configuration))
|
|
465
|
+
end
|
|
466
|
+
install_scalar_constants(target, source)
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def install_scalar_constants(target, source)
|
|
470
|
+
if @configuration.target?(:counter) && (integer = usable_type(source, :Integer))
|
|
471
|
+
type = CollectionType.new(integer, kind: :counter, configuration: @configuration)
|
|
472
|
+
install_constant(target, :Counter, type)
|
|
473
|
+
end
|
|
474
|
+
if @configuration.target?(:flag) && (bool = usable_type(source, :Bool))
|
|
475
|
+
install_constant(target, :Flag, CollectionType.new(bool, kind: :flag, configuration: @configuration))
|
|
476
|
+
end
|
|
477
|
+
return unless @configuration.target?(:atom) && dry_namespace?(source)
|
|
478
|
+
|
|
479
|
+
any = ::Dry::Types["any"]
|
|
480
|
+
install_constant(target, :Atom, AtomType.new(any, kind: :atom, configuration: @configuration))
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def usable_array_type(source)
|
|
484
|
+
type = source.const_get(:Array, false) if source.const_defined?(:Array, false)
|
|
485
|
+
collection = DryTypes.collection_source(type) if type
|
|
486
|
+
type if valid_source?(collection, ::Array) && collection.respond_to?(:of)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
def usable_hash_type(source)
|
|
490
|
+
type = source.const_get(:Hash, false) if source.const_defined?(:Hash, false)
|
|
491
|
+
collection = DryTypes.collection_source(type) if type
|
|
492
|
+
type if valid_source?(collection, ::Hash) && collection.respond_to?(:map) && collection.respond_to?(:schema)
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def valid_source?(type, primitive)
|
|
496
|
+
return false unless type.is_a?(::Dry::Types::Type) && type.respond_to?(:primitive)
|
|
497
|
+
|
|
498
|
+
actual = type.primitive
|
|
499
|
+
actual.is_a?(Class) && actual <= primitive
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def usable_type(source, name)
|
|
503
|
+
type = source.const_get(name, false) if source.const_defined?(name, false)
|
|
504
|
+
type if type.is_a?(::Dry::Types::Type)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
def dry_namespace?(source)
|
|
508
|
+
source.constants(false).any? do |name|
|
|
509
|
+
source.const_get(name, false).is_a?(::Dry::Types::Type)
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def install_constant(target, name, value)
|
|
514
|
+
ensure_available!(target, name)
|
|
515
|
+
target.const_set(name, value)
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
def relevant_namespace?(namespace)
|
|
519
|
+
return true if usable_array_type(namespace) || usable_hash_type(namespace)
|
|
520
|
+
return true if scalar_namespace?(namespace)
|
|
521
|
+
|
|
522
|
+
namespace.constants(false).any? do |name|
|
|
523
|
+
child = namespace.const_get(name, false)
|
|
524
|
+
child.is_a?(Module) && relevant_namespace?(child)
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
def scalar_namespace?(namespace)
|
|
529
|
+
(@configuration.target?(:counter) && usable_type(namespace, :Integer)) ||
|
|
530
|
+
(@configuration.target?(:flag) && usable_type(namespace, :Bool)) ||
|
|
531
|
+
(@configuration.target?(:atom) && dry_namespace?(namespace))
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
def namespace_overlay(namespace, existing = nil)
|
|
535
|
+
overlay = Module.new
|
|
536
|
+
overlay.include(namespace)
|
|
537
|
+
overlay.include(existing) if existing.is_a?(Module) && !existing.equal?(namespace)
|
|
538
|
+
install_collection_constants(overlay, namespace)
|
|
539
|
+
namespace.constants(false).each do |name|
|
|
540
|
+
child = namespace.const_get(name, false)
|
|
541
|
+
next unless child.is_a?(Module) && relevant_namespace?(child)
|
|
542
|
+
|
|
543
|
+
prior = existing.const_get(name) if existing.is_a?(Module) && existing.const_defined?(name)
|
|
544
|
+
overlay.const_set(name, namespace_overlay(child, prior))
|
|
545
|
+
end
|
|
546
|
+
overlay
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def ensure_available!(target, name)
|
|
550
|
+
return unless target.const_defined?(name, false)
|
|
551
|
+
|
|
552
|
+
raise ArgumentError, "cannot import Farce dry type over #{target}::#{name}"
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
extend self
|
|
557
|
+
|
|
558
|
+
# Create the import module used by Farce.DryTypes().
|
|
559
|
+
# @param namespaces [Array<Symbol>] Explicit dry-types namespaces.
|
|
560
|
+
# @param default [Symbol, Object] The default namespace or Farce's undefined sentinel.
|
|
561
|
+
# @param aliases [Hash{Symbol => Symbol}] Dry-types namespace aliases.
|
|
562
|
+
# @param variant [Symbol] The Farce collection family.
|
|
563
|
+
# @param mode [Symbol, Object] The shared transfer mode or the undefined sentinel.
|
|
564
|
+
# @param scope [Symbol, Object] The local scope or the undefined sentinel.
|
|
565
|
+
# @return [Import] The import module.
|
|
566
|
+
# @api private
|
|
567
|
+
def import(namespaces, default:, aliases:, variant:, mode:, scope:)
|
|
568
|
+
configuration = Configuration.new(variant:, mode:, scope:)
|
|
569
|
+
Import.new(namespaces, default:, aliases:, configuration:)
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
# Build the delegated dry constructor for a Farce value.
|
|
573
|
+
# @param source [Dry::Types::Type] The source type.
|
|
574
|
+
# @param kind [Symbol] The lowercase Farce type name.
|
|
575
|
+
# @param configuration [Configuration] The Farce output configuration.
|
|
576
|
+
# @return [Dry::Types::Type] The constructor type.
|
|
577
|
+
# @api private
|
|
578
|
+
def build_type(source, kind, configuration)
|
|
579
|
+
target = configuration.target(kind)
|
|
580
|
+
constructor = lambda do |input, &failure|
|
|
581
|
+
values = source.call(materialize(input, kind), &failure)
|
|
582
|
+
reject_structural_key_collisions!(values) if kind == :map
|
|
583
|
+
optional_nil = kind != :atom && values.nil? && source.optional?
|
|
584
|
+
optional_nil ? nil : target.new(values, **configuration.constructor_options(kind))
|
|
585
|
+
rescue Farce::Ractor::IsolationError, ArgumentError, TypeError, NoMethodError, RangeError => e
|
|
586
|
+
::Dry::Types::CoercionError.handle(e, &failure)
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
output_type(target, source, kind).constructor(constructor)
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
# Unwrap the collection branch of an optional source type.
|
|
593
|
+
# @param source [Dry::Types::Type] The possibly optional source.
|
|
594
|
+
# @return [Dry::Types::Type] The Array or Hash branch.
|
|
595
|
+
# @api private
|
|
596
|
+
def collection_source(source)
|
|
597
|
+
source.respond_to?(:optional?) && source.optional? ? source.right : source
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
# Restore the nil branch after configuring an optional collection.
|
|
601
|
+
# @param original [Dry::Types::Type] The original source type.
|
|
602
|
+
# @param typed [Dry::Types::Type] The configured collection branch.
|
|
603
|
+
# @return [Dry::Types::Type] The configured type with optionality restored.
|
|
604
|
+
# @api private
|
|
605
|
+
def restore_optional_source(original, typed)
|
|
606
|
+
original.respond_to?(:optional?) && original.optional? ? original.left | typed : typed
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
private
|
|
610
|
+
|
|
611
|
+
def output_type(target, source, kind)
|
|
612
|
+
type = ::Dry.Types().Nominal(target)
|
|
613
|
+
type = type.with(namespace: source.namespace) if source.respond_to?(:namespace) && source.namespace
|
|
614
|
+
type = type.meta(source.meta) if source.respond_to?(:meta) && !source.meta.empty?
|
|
615
|
+
type = type.constrained(type: target)
|
|
616
|
+
kind != :atom && source.respond_to?(:optional?) && source.optional? ? type.optional : type
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
def materialize(input, kind)
|
|
620
|
+
case kind
|
|
621
|
+
when :vector then vector_input(input)
|
|
622
|
+
when :map then map_input(input)
|
|
623
|
+
when :set then materialize_set(input)
|
|
624
|
+
else input
|
|
625
|
+
end
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
def vector_input(input)
|
|
629
|
+
return input unless input.is_a?(Farce::Abstract::Vector)
|
|
630
|
+
|
|
631
|
+
reject_mode_backed_input!(input)
|
|
632
|
+
input.to_a
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def map_input(input)
|
|
636
|
+
return input unless input.is_a?(Farce::Abstract::Map)
|
|
637
|
+
|
|
638
|
+
reject_mode_backed_input!(input)
|
|
639
|
+
input.to_h
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
def materialize_set(input)
|
|
643
|
+
if input.is_a?(Farce::Abstract::Set)
|
|
644
|
+
reject_mode_backed_input!(input)
|
|
645
|
+
input.to_a
|
|
646
|
+
elsif input.is_a?(::Set)
|
|
647
|
+
input.to_a
|
|
648
|
+
else
|
|
649
|
+
input
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
def reject_mode_backed_input!(input)
|
|
654
|
+
return unless input.respond_to?(:mode)
|
|
655
|
+
|
|
656
|
+
raise ArgumentError, "mode-backed Farce collections must be materialized before dry-types processing"
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
def reject_structural_key_collisions!(hash)
|
|
660
|
+
return unless hash.is_a?(::Hash) && hash.compare_by_identity?
|
|
661
|
+
|
|
662
|
+
structural = {}
|
|
663
|
+
hash.each_key do |key|
|
|
664
|
+
raise ArgumentError, "duplicate structural hash key #{key.inspect}" if structural.key?(key)
|
|
665
|
+
|
|
666
|
+
structural[key] = true
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
# @note This methods is only available if dry-types has been loaded.
|
|
673
|
+
#
|
|
674
|
+
# Build a dry-types import for Farce types.
|
|
675
|
+
#
|
|
676
|
+
# With no dry namespace options, the import uses the nearest Dry.Types()
|
|
677
|
+
# import already included in the receiving module. Without one, it uses the
|
|
678
|
+
# same strict defaults as Dry.Types(). Dry namespace arguments, `default:`,
|
|
679
|
+
# and aliases select an independent source import using Dry.Types() rules.
|
|
680
|
+
#
|
|
681
|
+
# @param namespaces [Array<Symbol>] Dry type namespaces to import Farce counterparts for.
|
|
682
|
+
# @param default [Symbol] The Dry namespace used for root Farce type constants.
|
|
683
|
+
# @param variant [Symbol] The output variant: :shared, :strict, :unshared, or :local.
|
|
684
|
+
# @param mode [Symbol] The transfer mode for the shared variant.
|
|
685
|
+
# @param scope [Symbol] The storage scope for the local variant.
|
|
686
|
+
# @param aliases [Hash{Symbol => Symbol}] Dry namespace aliases.
|
|
687
|
+
# @return [Module] A module for inclusion beside Dry.Types().
|
|
688
|
+
def self.DryTypes( # rubocop:disable Naming/MethodName
|
|
689
|
+
*namespaces, default: UNDEFINED, variant: :shared, mode: UNDEFINED, scope: UNDEFINED, **aliases
|
|
690
|
+
)
|
|
691
|
+
internal = const_get(:Internal, false).const_get(:DryTypes, false)
|
|
692
|
+
internal.import(namespaces, default:, aliases:, variant:, mode:, scope:)
|
|
693
|
+
end
|
|
694
|
+
end
|