farce 0.1.0-arm-linux-gnu → 0.2.0-arm-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 +4 -4
- data/CHANGELOG.md +80 -1
- data/README.md +72 -16
- data/docs/gems/dry-types.md +8 -8
- data/docs/modes.md +67 -10
- data/ext/farce/atom.c +37 -22
- data/ext/farce/bounded_map.c +17 -13
- data/ext/farce/containers.h +15 -0
- data/ext/farce/counter.c +13 -18
- data/ext/farce/exchanger.c +5 -1
- data/ext/farce/farce.c +1 -1
- data/ext/farce/flag.c +39 -3
- data/ext/farce/io.c +3 -3
- data/ext/farce/lock.c +17 -23
- data/ext/farce/map.c +88 -66
- data/ext/farce/priority_queue.c +55 -43
- data/ext/farce/queue.c +10 -4
- data/ext/farce/reactor.c +52 -25
- data/ext/farce/reactor.h +1 -1
- data/ext/farce/signal.c +5 -1
- data/ext/farce/transaction.c +20 -24
- data/ext/farce/tree_map.c +33 -18
- data/ext/farce/trie.c +81 -43
- data/ext/farce/unshareable.c +168 -19
- data/ext/farce/unshared_io_pool.h +21 -12
- data/ext/farce/unshared_signal.c +13 -2
- data/ext/farce/unshared_wait.h +3 -0
- data/ext/farce/vector.c +82 -18
- data/ext/farce/weak_map.c +75 -63
- data/lib/farce/_yard/macros.rb +18 -3
- data/lib/farce/abstract/flag.rb +73 -0
- data/lib/farce/abstract/queue.rb +4 -3
- data/lib/farce/abstract/scheduler.rb +3 -3
- data/lib/farce/abstract/set.rb +17 -5
- data/lib/farce/abstract/sorted_set.rb +2 -2
- data/lib/farce/abstract/timer_queue.rb +49 -10
- data/lib/farce/abstract/vector.rb +510 -28
- data/lib/farce/atom.rb +1 -1
- data/lib/farce/class_mirror.rb +20 -7
- data/lib/farce/config.rb +7 -1
- data/lib/farce/engine/jvm/flag.rb +15 -3
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/unshared_vector.rb +31 -4
- data/lib/farce/engine/shared/vector.rb +8 -0
- data/lib/farce/engine/shared/weak_map/index.rb +14 -1
- data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
- data/lib/farce/envelope.rb +54 -7
- data/lib/farce/exchanger.rb +1 -1
- data/lib/farce/flag.rb +2 -0
- data/lib/farce/integrations/active_support.rb +1 -1
- data/lib/farce/integrations/bson.rb +1 -1
- data/lib/farce/integrations/cbor.rb +1 -1
- data/lib/farce/integrations/concurrent.rb +3 -3
- data/lib/farce/integrations/date.rb +8 -0
- data/lib/farce/integrations/dry_types.rb +7 -4
- data/lib/farce/integrations/json.rb +2 -2
- data/lib/farce/integrations/msgpack.rb +1 -1
- data/lib/farce/integrations/oj.rb +3 -4
- data/lib/farce/integrations/psych.rb +1 -1
- data/lib/farce/integrations/ractor_sharing.rb +1 -1
- data/lib/farce/integrations/sorted_set.rb +1 -1
- data/lib/farce/integrations/weakref.rb +9 -1
- data/lib/farce/integrations/yajl.rb +3 -3
- data/lib/farce/integrations.rb +33 -23
- data/lib/farce/internal/flag_waiting.rb +30 -0
- data/lib/farce/internal/freeze.rb +8 -3
- data/lib/farce/internal/map_value_modes.rb +1 -1
- data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
- data/lib/farce/lazy.rb +4 -4
- data/lib/farce/lazy_ref.rb +3 -3
- data/lib/farce/lfu_map.rb +1 -1
- data/lib/farce/local/flag.rb +4 -0
- data/lib/farce/local/scoped.rb +1 -1
- data/lib/farce/lru_map.rb +1 -1
- data/lib/farce/map.rb +2 -2
- data/lib/farce/mode_manager/smart_rule.rb +138 -0
- data/lib/farce/mode_manager.rb +12 -3
- data/lib/farce/molecule.rb +2 -2
- data/lib/farce/pool.rb +1 -1
- data/lib/farce/port.rb +4 -4
- data/lib/farce/priority_queue.rb +1 -1
- data/lib/farce/proxy/register.rb +6 -0
- data/lib/farce/proxy/supervisor.rb +1 -1
- data/lib/farce/proxy.rb +7 -2
- data/lib/farce/queue.rb +1 -1
- data/lib/farce/scheduler.rb +2 -2
- data/lib/farce/set.rb +1 -1
- data/lib/farce/sorted_set.rb +1 -1
- data/lib/farce/timer_queue.rb +20 -6
- data/lib/farce/transaction/vector.rb +43 -9
- data/lib/farce/transaction/wrapper.rb +14 -0
- data/lib/farce/tree_map.rb +1 -1
- data/lib/farce/unsafe/lfu_map.rb +2 -0
- data/lib/farce/unsafe/lru_map.rb +2 -0
- data/lib/farce/unsafe/tree_map.rb +2 -0
- data/lib/farce/unshareable.rb +8 -19
- data/lib/farce/unshared/atom.rb +3 -0
- data/lib/farce/unshared/lfu_map.rb +2 -0
- data/lib/farce/unshared/lru_map.rb +2 -0
- data/lib/farce/unshared/map.rb +3 -0
- data/lib/farce/unshared/set.rb +1 -0
- data/lib/farce/unshared/sorted_set.rb +1 -0
- data/lib/farce/unshared/tree_map.rb +5 -1
- data/lib/farce/unshared/vector.rb +3 -0
- data/lib/farce/unshared/weak_atom.rb +5 -1
- data/lib/farce/unshared/weak_key_map.rb +3 -0
- data/lib/farce/unshared/weak_map.rb +3 -0
- data/lib/farce/unshared/weak_set.rb +1 -0
- data/lib/farce/unshared/weak_value_map.rb +3 -0
- data/lib/farce/vector.rb +44 -19
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +11 -8
- metadata +5 -1
data/lib/farce/config.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Farce
|
|
|
24
24
|
class Config
|
|
25
25
|
# Automatically load integrations when their dependencies are loaded. Defaults to true.
|
|
26
26
|
# Can also be set via `FARCE_AUTOLOAD_INTEGRATIONS` (`true`/`false` or `1`/`0`).
|
|
27
|
-
# Set before requiring Farce to
|
|
27
|
+
# Set before requiring Farce to disable startup integration loading and require hooks.
|
|
28
28
|
# @return [Boolean]
|
|
29
29
|
attr_reader :autoload_integrations
|
|
30
30
|
|
|
@@ -63,6 +63,7 @@ module Farce
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# Enable or disable automatic integration loading. Already loaded integrations remain active.
|
|
66
|
+
# Enabling this option installs require hooks if they are not already installed.
|
|
66
67
|
# @param value [Boolean, String] true, false, or their environment variable representations.
|
|
67
68
|
# @raise [ArgumentError] If the value is not a supported boolean.
|
|
68
69
|
def autoload_integrations=(value)
|
|
@@ -71,6 +72,11 @@ module Farce
|
|
|
71
72
|
when false, "false", "0" then false
|
|
72
73
|
else raise ArgumentError, "autoload_integrations must be a boolean"
|
|
73
74
|
end
|
|
75
|
+
if @autoload_integrations && Farce.const_defined?(:Integrations, false) &&
|
|
76
|
+
!Farce.autoload?(:Integrations) && Farce.config.equal?(self)
|
|
77
|
+
Integrations.install_require_hooks
|
|
78
|
+
end
|
|
79
|
+
@autoload_integrations
|
|
74
80
|
end
|
|
75
81
|
|
|
76
82
|
# Default fiber scheduler for Pool and Scheduler.
|
|
@@ -8,23 +8,30 @@ module Farce
|
|
|
8
8
|
# @!visibility private
|
|
9
9
|
module Internal # :nodoc: all
|
|
10
10
|
class Flag
|
|
11
|
+
include FlagWaiting
|
|
12
|
+
|
|
11
13
|
def initialize(value = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
12
14
|
raise "Flag is already initialized" if defined?(@reference)
|
|
13
15
|
check_frozen!
|
|
16
|
+
@signal = Signal.new
|
|
14
17
|
@reference = JVMContainers::AtomicBoolean.new(validate_boolean(value, "initial value"))
|
|
15
18
|
end
|
|
16
19
|
|
|
20
|
+
def change_signal = @signal
|
|
21
|
+
|
|
17
22
|
def value = @reference.get
|
|
18
23
|
|
|
19
24
|
def set # rubocop:disable Naming/PredicateMethod
|
|
20
25
|
check_frozen!
|
|
21
26
|
@reference.set(true)
|
|
27
|
+
@signal.broadcast
|
|
22
28
|
true
|
|
23
29
|
end
|
|
24
30
|
|
|
25
31
|
def unset # rubocop:disable Naming/PredicateMethod
|
|
26
32
|
check_frozen!
|
|
27
33
|
@reference.set(false)
|
|
34
|
+
@signal.broadcast
|
|
28
35
|
false
|
|
29
36
|
end
|
|
30
37
|
|
|
@@ -32,20 +39,21 @@ module Farce
|
|
|
32
39
|
check_frozen!
|
|
33
40
|
value = validate_boolean(value, "value")
|
|
34
41
|
@reference.set(value)
|
|
42
|
+
@signal.broadcast
|
|
35
43
|
value
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
def swap(value)
|
|
39
47
|
check_frozen!
|
|
40
48
|
value = validate_boolean(value, "value")
|
|
41
|
-
@reference.getAndSet(value)
|
|
49
|
+
@reference.getAndSet(value).tap { @signal.broadcast }
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
def compare_and_set(expected_value, replacement_value)
|
|
45
53
|
check_frozen!
|
|
46
54
|
expected_value = validate_boolean(expected_value, "expected value")
|
|
47
55
|
replacement_value = validate_boolean(replacement_value, "replacement value")
|
|
48
|
-
@reference.compareAndSet(expected_value, replacement_value)
|
|
56
|
+
@reference.compareAndSet(expected_value, replacement_value).tap { |changed| @signal.broadcast if changed }
|
|
49
57
|
end
|
|
50
58
|
|
|
51
59
|
def toggle
|
|
@@ -53,7 +61,10 @@ module Farce
|
|
|
53
61
|
loop do
|
|
54
62
|
current = @reference.get
|
|
55
63
|
replacement = !current
|
|
56
|
-
|
|
64
|
+
if @reference.compareAndSet(current, replacement)
|
|
65
|
+
@signal.broadcast
|
|
66
|
+
return replacement
|
|
67
|
+
end
|
|
57
68
|
end
|
|
58
69
|
end
|
|
59
70
|
|
|
@@ -72,6 +83,7 @@ module Farce
|
|
|
72
83
|
end
|
|
73
84
|
|
|
74
85
|
def initialize_copy(other)
|
|
86
|
+
@signal = Signal.new
|
|
75
87
|
@reference = JVMContainers::AtomicBoolean.new(other.value)
|
|
76
88
|
end
|
|
77
89
|
end
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
# Ruby 3.4.11 and 4.0 prepend a Ractor-aware require to Kernel on activation.
|
|
6
|
+
# Detect that wrapper so versions that install it on Object need no relocation.
|
|
7
|
+
# A later Kernel alias captures that wrapper and loses its super target.
|
|
8
|
+
# Keep the original implementation above Object so aliases capture Kernel's
|
|
9
|
+
# underlying require while secondary Ractors still use Ruby's loader service.
|
|
10
|
+
ractor_require = Kernel.ancestors.find { it.name == "<RactorRequire>" }
|
|
11
|
+
if ractor_require
|
|
12
|
+
replacement = Module.new
|
|
13
|
+
replacement.set_temporary_name("<FarceRactorRequire>")
|
|
14
|
+
replacement.define_method(:require, ractor_require.instance_method(:require))
|
|
15
|
+
replacement.send(:private, :require)
|
|
16
|
+
Object.prepend(replacement)
|
|
17
|
+
ractor_require.remove_method(:require)
|
|
18
|
+
end
|
data/lib/farce/engine/ruby.rb
CHANGED
|
@@ -14,6 +14,13 @@ module Farce
|
|
|
14
14
|
ENGINE_PATH = "farce/engine/ruby/#{RUBY_VERSION[/^\d+\.\d+/]}".freeze
|
|
15
15
|
private_constant :ENGINE_PATH
|
|
16
16
|
|
|
17
|
+
require "farce/engine/ruby/shared/require_hook"
|
|
18
|
+
# Older Ractor activation defines a public Object#require. Keep Ruby's
|
|
19
|
+
# ordinary private visibility even when integration hooks are disabled.
|
|
20
|
+
if Object.instance_method(:require).source_location&.first == "<internal:ractor>"
|
|
21
|
+
Object.class_eval { private :require }
|
|
22
|
+
end
|
|
23
|
+
|
|
17
24
|
begin
|
|
18
25
|
require "#{ENGINE_PATH}/rebind"
|
|
19
26
|
require "#{ENGINE_PATH}/farce"
|
|
@@ -252,6 +252,28 @@ module Farce
|
|
|
252
252
|
finish_update if reservation
|
|
253
253
|
end
|
|
254
254
|
|
|
255
|
+
# Yield private storage and publish it only after the block finishes.
|
|
256
|
+
# The yielded Array is never retained. Callbacks run outside the mutex.
|
|
257
|
+
def batch_update(timeout: nil)
|
|
258
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
259
|
+
check_frozen!
|
|
260
|
+
completed, values = reserve(timeout_deadline(timeout)) do
|
|
261
|
+
snapshot = @values.dup
|
|
262
|
+
@updating = true
|
|
263
|
+
snapshot
|
|
264
|
+
end
|
|
265
|
+
return false unless completed
|
|
266
|
+
yield values
|
|
267
|
+
replacement = values.dup
|
|
268
|
+
@mutex.synchronize do
|
|
269
|
+
check_frozen_locked!
|
|
270
|
+
@values = replacement
|
|
271
|
+
end
|
|
272
|
+
true
|
|
273
|
+
ensure
|
|
274
|
+
finish_update if completed
|
|
275
|
+
end
|
|
276
|
+
|
|
255
277
|
def wait_until_changed(index, expected, timeout: nil)
|
|
256
278
|
wait_for_value(convert_index(index), expected, timeout_deadline(timeout), non_nil: false)
|
|
257
279
|
end
|
|
@@ -272,11 +294,16 @@ module Farce
|
|
|
272
294
|
|
|
273
295
|
def with_available(deadline)
|
|
274
296
|
while true
|
|
275
|
-
generation
|
|
276
|
-
|
|
277
|
-
@updating
|
|
297
|
+
generation = nil
|
|
298
|
+
result = @mutex.synchronize do
|
|
299
|
+
if @updating
|
|
300
|
+
generation = @signal.generation
|
|
301
|
+
nil
|
|
302
|
+
else
|
|
303
|
+
[true, yield]
|
|
304
|
+
end
|
|
278
305
|
end
|
|
279
|
-
return
|
|
306
|
+
return result if result
|
|
280
307
|
return [false, nil] unless wait_for_signal(generation, deadline)
|
|
281
308
|
end
|
|
282
309
|
end
|
|
@@ -184,7 +184,20 @@ module Farce
|
|
|
184
184
|
|
|
185
185
|
def data_for(key) = Internal.garbage_collectable?(key) ? @data : @immediate
|
|
186
186
|
def key_reference(key) = UnsharedWeakMapWeakReference.for(key)
|
|
187
|
-
|
|
187
|
+
|
|
188
|
+
def registry_enumerator
|
|
189
|
+
entries = @entries
|
|
190
|
+
Enumerator.new do |yielder|
|
|
191
|
+
# Compaction can rehash a weak registry and repeat earlier entries.
|
|
192
|
+
# Tokens have no back-reference to cells, keys, or values.
|
|
193
|
+
seen = {}.compare_by_identity
|
|
194
|
+
entries.each_value do |entry|
|
|
195
|
+
next if seen.key?(entry.token)
|
|
196
|
+
seen[entry.token] = true
|
|
197
|
+
yielder << entry
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
188
201
|
|
|
189
202
|
def register(entry)
|
|
190
203
|
@registry_mutex.synchronize do
|
|
@@ -6,23 +6,30 @@ module Farce
|
|
|
6
6
|
# @!visibility private
|
|
7
7
|
module Internal # :nodoc: all
|
|
8
8
|
class Flag
|
|
9
|
+
include FlagWaiting
|
|
10
|
+
|
|
9
11
|
def initialize(value = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
10
12
|
raise "Flag is already initialized" if defined?(@reference)
|
|
11
13
|
check_frozen!
|
|
14
|
+
@signal = Signal.new
|
|
12
15
|
@reference = TruffleRuby::AtomicReference.new(validate_boolean(value, "initial value"))
|
|
13
16
|
end
|
|
14
17
|
|
|
18
|
+
def change_signal = @signal
|
|
19
|
+
|
|
15
20
|
def value = @reference.get
|
|
16
21
|
|
|
17
22
|
def set # rubocop:disable Naming/PredicateMethod
|
|
18
23
|
check_frozen!
|
|
19
24
|
@reference.set(true)
|
|
25
|
+
@signal.broadcast
|
|
20
26
|
true
|
|
21
27
|
end
|
|
22
28
|
|
|
23
29
|
def unset # rubocop:disable Naming/PredicateMethod
|
|
24
30
|
check_frozen!
|
|
25
31
|
@reference.set(false)
|
|
32
|
+
@signal.broadcast
|
|
26
33
|
false
|
|
27
34
|
end
|
|
28
35
|
|
|
@@ -30,20 +37,21 @@ module Farce
|
|
|
30
37
|
check_frozen!
|
|
31
38
|
value = validate_boolean(value, "value")
|
|
32
39
|
@reference.set(value)
|
|
40
|
+
@signal.broadcast
|
|
33
41
|
value
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
def swap(value)
|
|
37
45
|
check_frozen!
|
|
38
46
|
value = validate_boolean(value, "value")
|
|
39
|
-
@reference.get_and_set(value)
|
|
47
|
+
@reference.get_and_set(value).tap { @signal.broadcast }
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
def compare_and_set(expected_value, replacement_value)
|
|
43
51
|
check_frozen!
|
|
44
52
|
expected_value = validate_boolean(expected_value, "expected value")
|
|
45
53
|
replacement_value = validate_boolean(replacement_value, "replacement value")
|
|
46
|
-
@reference.compare_and_set(expected_value, replacement_value)
|
|
54
|
+
@reference.compare_and_set(expected_value, replacement_value).tap { |changed| @signal.broadcast if changed }
|
|
47
55
|
end
|
|
48
56
|
|
|
49
57
|
def toggle
|
|
@@ -51,7 +59,10 @@ module Farce
|
|
|
51
59
|
loop do
|
|
52
60
|
current = @reference.get
|
|
53
61
|
replacement = !current
|
|
54
|
-
|
|
62
|
+
if @reference.compare_and_set(current, replacement)
|
|
63
|
+
@signal.broadcast
|
|
64
|
+
return replacement
|
|
65
|
+
end
|
|
55
66
|
end
|
|
56
67
|
end
|
|
57
68
|
|
|
@@ -70,6 +81,7 @@ module Farce
|
|
|
70
81
|
end
|
|
71
82
|
|
|
72
83
|
def initialize_copy(other)
|
|
84
|
+
@signal = Signal.new
|
|
73
85
|
@reference = TruffleRuby::AtomicReference.new(other.value)
|
|
74
86
|
end
|
|
75
87
|
end
|
data/lib/farce/envelope.rb
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
module Farce
|
|
6
6
|
# An envelope can be used to wrap an unshareable value in a shareable object.
|
|
7
7
|
#
|
|
8
|
-
# Once created, the envelope can be shared between Ractors
|
|
9
|
-
# envelope is opened.
|
|
8
|
+
# Once created, the envelope can be shared between Ractors. Its payload is retrieved when the envelope is opened.
|
|
10
9
|
#
|
|
11
10
|
# When a Ractor attempts to open an envelope, it attempts "claim" it. Some envelopes may only be claimed by a single
|
|
12
11
|
# Ractor, others can be claimed by any Ractor. Claims cannot be taken back.
|
|
@@ -111,6 +110,53 @@ module Farce
|
|
|
111
110
|
def vault_key = defined?(@vault_key) ? @vault_key : self
|
|
112
111
|
end
|
|
113
112
|
|
|
113
|
+
# An envelope that serializes its contents with Ruby's Marshal protocol.
|
|
114
|
+
# The snapshot is created immediately and reconstructed once per Ractor that opens it.
|
|
115
|
+
# Farce containers rebuild their storage from logical snapshots.
|
|
116
|
+
# Contents must support Marshal. Nested shareable values may be reconstructed too.
|
|
117
|
+
#
|
|
118
|
+
# @example Transfer an Unshared map
|
|
119
|
+
# source = Farce::Unshared::Map.new({ jobs: [] })
|
|
120
|
+
# envelope = Farce::Envelope.new(source, mode: :marshal)
|
|
121
|
+
# envelope.value[:jobs] << :ready
|
|
122
|
+
# source[:jobs] # => []
|
|
123
|
+
class Marshal < Farce::Envelope
|
|
124
|
+
include Copyable
|
|
125
|
+
|
|
126
|
+
# @param value [BasicObject] the value to serialize
|
|
127
|
+
# @param auto_unwrap [ModeManager, nil] the manager that may automatically open this envelope
|
|
128
|
+
# @raise [TypeError] if the value cannot be marshaled
|
|
129
|
+
def initialize(value, auto_unwrap = nil)
|
|
130
|
+
@dump = ::Marshal.dump(value).freeze
|
|
131
|
+
super
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# @api private
|
|
135
|
+
def marshal_dump = [1, value, auto_unwrap]
|
|
136
|
+
|
|
137
|
+
# @api private
|
|
138
|
+
def marshal_load(data)
|
|
139
|
+
value, manager = Internal::MarshalSupport.payload(data, 2)
|
|
140
|
+
initialize(value, manager)
|
|
141
|
+
Internal::Storage.ractor[self] = value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# (see Envelope#claim)
|
|
145
|
+
def claim = self
|
|
146
|
+
|
|
147
|
+
# (see Envelope#claimed?)
|
|
148
|
+
def claimed? = true
|
|
149
|
+
|
|
150
|
+
# (see Envelope#owned?)
|
|
151
|
+
def owned? = true
|
|
152
|
+
|
|
153
|
+
protected
|
|
154
|
+
|
|
155
|
+
# The bytes are created by this envelope from its caller's value.
|
|
156
|
+
# rubocop:disable-next Security/MarshalLoad
|
|
157
|
+
def retrieve = ::Marshal.load(@dump)
|
|
158
|
+
end
|
|
159
|
+
|
|
114
160
|
# An envelope that moves its contents. Can only be opened by a single Ractor.
|
|
115
161
|
# The value will be moved once when the envelope is created, and then once when the envelope is opened.
|
|
116
162
|
#
|
|
@@ -253,7 +299,7 @@ module Farce
|
|
|
253
299
|
#
|
|
254
300
|
# @overload new(value, mode:)
|
|
255
301
|
# @param value [BasicObject] The value to wrap in the envelope.
|
|
256
|
-
# @param mode [Symbol, nil] The type of envelope to create. Can be `:move`, `:copy`, or `:local`.
|
|
302
|
+
# @param mode [Symbol, nil] The type of envelope to create. Can be `:move`, `:copy`, `:marshal`, or `:local`.
|
|
257
303
|
# @return [Envelope] A new envelope wrapping the given value.
|
|
258
304
|
#
|
|
259
305
|
# @return [Envelope] A new envelope wrapping the given value.
|
|
@@ -265,10 +311,11 @@ module Farce
|
|
|
265
311
|
|
|
266
312
|
def self.subclass_for(move: false, local: false, mode: nil)
|
|
267
313
|
case mode
|
|
268
|
-
when :move
|
|
269
|
-
when :copy
|
|
270
|
-
when :
|
|
271
|
-
when
|
|
314
|
+
when :move then Move
|
|
315
|
+
when :copy then Copy
|
|
316
|
+
when :marshal then Marshal
|
|
317
|
+
when :local then Local
|
|
318
|
+
when nil then local ? Local : (move ? Move : Copy)
|
|
272
319
|
else raise ArgumentError, "invalid mode: #{mode.inspect}"
|
|
273
320
|
end
|
|
274
321
|
end
|
data/lib/farce/exchanger.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Farce
|
|
|
15
15
|
|
|
16
16
|
# @!macro modes
|
|
17
17
|
# @param mode [Symbol] the default mode used to transfer values between Ractors
|
|
18
|
-
def initialize(mode: :
|
|
18
|
+
def initialize(mode: :smart)
|
|
19
19
|
@manager = ModeManager.new(mode:)
|
|
20
20
|
@exchanger = Internal::Exchanger.new
|
|
21
21
|
super()
|
data/lib/farce/flag.rb
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
# warn_indent: true
|
|
4
4
|
|
|
5
5
|
# @!group concurrent-ruby Integration
|
|
6
|
-
require "farce"
|
|
7
|
-
require "concurrent/map"
|
|
8
|
-
require "concurrent/tvar"
|
|
6
|
+
require "farce" unless defined?(Farce::Abstract)
|
|
7
|
+
require "concurrent/map" unless defined?(Concurrent::Map)
|
|
8
|
+
require "concurrent/tvar" unless defined?(Concurrent::TVar)
|
|
9
9
|
|
|
10
10
|
module Farce
|
|
11
11
|
module Integrations
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
# @!group Date Integration
|
|
6
|
+
require "farce" unless defined?(Farce::ModeManager)
|
|
7
|
+
require "date" unless defined?(Date)
|
|
8
|
+
Farce::ModeManager::SmartRule.define(Date, :make_shareable)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# warn_indent: true
|
|
4
4
|
|
|
5
5
|
# @!group Dry Types Integration
|
|
6
|
-
require "farce"
|
|
6
|
+
require "farce" unless defined?(Farce::Abstract)
|
|
7
7
|
require "dry/types"
|
|
8
8
|
|
|
9
9
|
module Farce
|
|
@@ -70,7 +70,7 @@ module Farce
|
|
|
70
70
|
when :shared
|
|
71
71
|
return {} unless %i[vector map set atom].include?(kind)
|
|
72
72
|
|
|
73
|
-
{ mode: UNDEFINED.equal?(mode) ? :
|
|
73
|
+
{ mode: UNDEFINED.equal?(mode) ? :smart : mode }
|
|
74
74
|
when :local then { scope: UNDEFINED.equal?(scope) ? :ractor : scope }
|
|
75
75
|
else {}
|
|
76
76
|
end
|
|
@@ -101,8 +101,11 @@ module Farce
|
|
|
101
101
|
|
|
102
102
|
if variant == :shared
|
|
103
103
|
raise ArgumentError, "scope is only supported by the local variant" unless UNDEFINED.equal?(scope)
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
if %i[move smart_move].include?(mode)
|
|
105
|
+
raise ArgumentError, "mode #{mode.inspect} is not supported by dry-types constructors"
|
|
106
|
+
end
|
|
107
|
+
allowed = %i[smart smart_raise smart_copy copy local make_shareable raise shareable_copy]
|
|
108
|
+
return if UNDEFINED.equal?(mode) || allowed.include?(mode)
|
|
106
109
|
|
|
107
110
|
raise ArgumentError, "invalid mode: #{mode.inspect}"
|
|
108
111
|
end
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
# warn_indent: true
|
|
4
4
|
|
|
5
5
|
# @!group Oj Integration
|
|
6
|
-
require "farce"
|
|
7
|
-
require "oj"
|
|
8
|
-
|
|
9
|
-
require "json" unless [].respond_to?(:to_json)
|
|
6
|
+
require "farce" unless defined?(Farce::Abstract)
|
|
7
|
+
require "oj" unless defined?(Oj::VERSION)
|
|
8
|
+
require "json" unless [].respond_to?(:to_json)
|
|
10
9
|
require_relative "shared/to_json"
|
|
11
10
|
|
|
12
11
|
module Farce
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# warn_indent: true
|
|
4
4
|
|
|
5
5
|
# @!group WeakRef Integration
|
|
6
|
-
require "farce" unless defined?(Farce::
|
|
6
|
+
require "farce" unless defined?(Farce::Abstract)
|
|
7
7
|
require "weakref" unless defined?(WeakRef)
|
|
8
8
|
|
|
9
9
|
module Farce
|
|
@@ -21,6 +21,14 @@ module Farce
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
Farce::ModeManager::SmartRule.define(::WeakRef) do |value, mode_manager, mode|
|
|
25
|
+
ref = value.__getobj__
|
|
26
|
+
value = Farce::WeakRef.new(ref)
|
|
27
|
+
super(value, mode_manager, mode)
|
|
28
|
+
rescue ::WeakRef::RefError
|
|
29
|
+
Farce::WeakRef::RECYCLED
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
Internal::Converter.define(::WeakRef, WeakRef) do
|
|
25
33
|
def convert!(ref)
|
|
26
34
|
@seen.fetch(ref) do
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# @!group Yajl Integration
|
|
6
6
|
# Yajl 1.4.3 cannot encode or parse inside non-main native Ractors.
|
|
7
|
-
require "farce"
|
|
8
|
-
require "yajl"
|
|
9
|
-
require "json"
|
|
7
|
+
require "farce" unless defined?(Farce::Abstract)
|
|
8
|
+
require "yajl" unless defined?(Yajl::Encoder)
|
|
9
|
+
require "json" unless [].respond_to?(:to_json)
|
|
10
10
|
require_relative "shared/to_json"
|