farce 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -1
  3. data/README.md +111 -17
  4. data/docs/gems/dry-types.md +8 -8
  5. data/docs/modes.md +75 -15
  6. data/docs/scopes.md +3 -1
  7. data/docs/variants.md +18 -0
  8. data/ext/farce/atom.c +37 -22
  9. data/ext/farce/bounded_map.c +17 -13
  10. data/ext/farce/containers.h +15 -0
  11. data/ext/farce/counter.c +13 -18
  12. data/ext/farce/exchanger.c +5 -1
  13. data/ext/farce/farce.c +1 -1
  14. data/ext/farce/flag.c +39 -3
  15. data/ext/farce/io.c +3 -3
  16. data/ext/farce/lock.c +17 -23
  17. data/ext/farce/map.c +88 -66
  18. data/ext/farce/priority_queue.c +55 -43
  19. data/ext/farce/queue.c +10 -4
  20. data/ext/farce/reactor.c +52 -25
  21. data/ext/farce/reactor.h +1 -1
  22. data/ext/farce/signal.c +5 -1
  23. data/ext/farce/transaction.c +20 -24
  24. data/ext/farce/tree_map.c +33 -18
  25. data/ext/farce/trie.c +81 -43
  26. data/ext/farce/unshareable.c +168 -19
  27. data/ext/farce/unshared_io_pool.h +21 -12
  28. data/ext/farce/unshared_signal.c +13 -2
  29. data/ext/farce/unshared_wait.h +3 -0
  30. data/ext/farce/vector.c +82 -18
  31. data/ext/farce/weak_map.c +75 -63
  32. data/lib/farce/_yard/macros.rb +18 -3
  33. data/lib/farce/abstract/executor.rb +130 -0
  34. data/lib/farce/abstract/flag.rb +73 -0
  35. data/lib/farce/abstract/pool.rb +334 -0
  36. data/lib/farce/abstract/queue.rb +4 -3
  37. data/lib/farce/abstract/scheduler.rb +539 -93
  38. data/lib/farce/abstract/set.rb +17 -5
  39. data/lib/farce/abstract/sorted_set.rb +2 -2
  40. data/lib/farce/abstract/timer_queue.rb +49 -10
  41. data/lib/farce/abstract/vector.rb +510 -28
  42. data/lib/farce/atom.rb +1 -1
  43. data/lib/farce/class_mirror.rb +20 -7
  44. data/lib/farce/config.rb +7 -1
  45. data/lib/farce/engine/jruby/signal.rb +7 -4
  46. data/lib/farce/engine/jvm/flag.rb +15 -3
  47. data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
  48. data/lib/farce/engine/ruby.rb +7 -0
  49. data/lib/farce/engine/shared/main_scheduler.rb +2 -2
  50. data/lib/farce/engine/shared/parallel_scheduler.rb +1 -1
  51. data/lib/farce/engine/shared/proxy_owner.rb +1 -1
  52. data/lib/farce/engine/shared/unshared_atom.rb +9 -8
  53. data/lib/farce/engine/shared/unshared_vector.rb +31 -4
  54. data/lib/farce/engine/shared/vector.rb +8 -0
  55. data/lib/farce/engine/shared/weak_map/index.rb +14 -1
  56. data/lib/farce/engine/shared.rb +9 -0
  57. data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
  58. data/lib/farce/envelope.rb +54 -7
  59. data/lib/farce/exchanger.rb +1 -1
  60. data/lib/farce/flag.rb +2 -0
  61. data/lib/farce/integrations/active_support.rb +1 -1
  62. data/lib/farce/integrations/bson.rb +1 -1
  63. data/lib/farce/integrations/cbor.rb +1 -1
  64. data/lib/farce/integrations/concurrent.rb +3 -3
  65. data/lib/farce/integrations/date.rb +8 -0
  66. data/lib/farce/integrations/dry_types.rb +7 -4
  67. data/lib/farce/integrations/json.rb +2 -2
  68. data/lib/farce/integrations/msgpack.rb +1 -1
  69. data/lib/farce/integrations/oj.rb +3 -4
  70. data/lib/farce/integrations/psych.rb +1 -1
  71. data/lib/farce/integrations/ractor_sharing.rb +1 -1
  72. data/lib/farce/integrations/sorted_set.rb +1 -1
  73. data/lib/farce/integrations/weakref.rb +9 -1
  74. data/lib/farce/integrations/yajl.rb +3 -3
  75. data/lib/farce/integrations.rb +33 -23
  76. data/lib/farce/internal/flag_waiting.rb +30 -0
  77. data/lib/farce/internal/freeze.rb +8 -3
  78. data/lib/farce/internal/lease_initialization.rb +1 -1
  79. data/lib/farce/internal/local_executor_methods.rb +33 -0
  80. data/lib/farce/internal/local_scheduled_task.rb +27 -0
  81. data/lib/farce/internal/map_value_modes.rb +1 -1
  82. data/lib/farce/internal/scheduled_task.rb +1 -1
  83. data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
  84. data/lib/farce/internal/thread_pool_supervisor.rb +45 -0
  85. data/lib/farce/internal/unshared_pool_worker.rb +14 -0
  86. data/lib/farce/internal.rb +14 -0
  87. data/lib/farce/lazy.rb +4 -4
  88. data/lib/farce/lazy_ref.rb +3 -3
  89. data/lib/farce/lfu_map.rb +1 -1
  90. data/lib/farce/local/flag.rb +4 -0
  91. data/lib/farce/local/pool.rb +111 -0
  92. data/lib/farce/local/scheduler.rb +219 -0
  93. data/lib/farce/local/scoped.rb +1 -1
  94. data/lib/farce/lru_map.rb +1 -1
  95. data/lib/farce/map.rb +2 -2
  96. data/lib/farce/mode_manager/smart_rule.rb +138 -0
  97. data/lib/farce/mode_manager.rb +12 -3
  98. data/lib/farce/molecule.rb +2 -2
  99. data/lib/farce/pool.rb +2 -290
  100. data/lib/farce/port.rb +4 -4
  101. data/lib/farce/priority_queue.rb +1 -1
  102. data/lib/farce/proxy/register.rb +6 -0
  103. data/lib/farce/proxy/supervisor.rb +1 -1
  104. data/lib/farce/proxy.rb +9 -4
  105. data/lib/farce/queue.rb +1 -1
  106. data/lib/farce/scheduler.rb +1 -502
  107. data/lib/farce/set.rb +1 -1
  108. data/lib/farce/sorted_set.rb +1 -1
  109. data/lib/farce/task.rb +285 -0
  110. data/lib/farce/{thread_scheduler.rb → thread_executor.rb} +7 -7
  111. data/lib/farce/timer_queue.rb +20 -6
  112. data/lib/farce/transaction/vector.rb +43 -9
  113. data/lib/farce/transaction/wrapper.rb +14 -0
  114. data/lib/farce/tree_map.rb +1 -1
  115. data/lib/farce/unsafe/lfu_map.rb +2 -0
  116. data/lib/farce/unsafe/lru_map.rb +2 -0
  117. data/lib/farce/unsafe/tree_map.rb +2 -0
  118. data/lib/farce/unshareable.rb +8 -19
  119. data/lib/farce/unshared/atom.rb +3 -0
  120. data/lib/farce/unshared/lfu_map.rb +2 -0
  121. data/lib/farce/unshared/lru_map.rb +2 -0
  122. data/lib/farce/unshared/map.rb +3 -0
  123. data/lib/farce/unshared/pool.rb +44 -0
  124. data/lib/farce/unshared/scheduler.rb +89 -0
  125. data/lib/farce/unshared/set.rb +1 -0
  126. data/lib/farce/unshared/sorted_set.rb +1 -0
  127. data/lib/farce/unshared/tree_map.rb +5 -1
  128. data/lib/farce/unshared/vector.rb +3 -0
  129. data/lib/farce/unshared/weak_atom.rb +5 -1
  130. data/lib/farce/unshared/weak_key_map.rb +3 -0
  131. data/lib/farce/unshared/weak_map.rb +3 -0
  132. data/lib/farce/unshared/weak_set.rb +1 -0
  133. data/lib/farce/unshared/weak_value_map.rb +3 -0
  134. data/lib/farce/vector.rb +44 -19
  135. data/lib/farce/version.rb +1 -1
  136. data/lib/farce.rb +20 -25
  137. metadata +17 -2
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Unshared
7
+ # An elastic pool of thread workers within one Ractor.
8
+ #
9
+ # Uses the same scaling and fiber schedulers as {Farce::Pool}. Tasks keep their
10
+ # blocks and argument references. `auto_local: true` ignores `mode`. With
11
+ # `auto_local: false`, only `:local` and smart modes are accepted.
12
+ # The pool cannot be copied or moved to another Ractor.
13
+ # A scheduler constructor may capture objects from this Ractor.
14
+ #
15
+ # @example Submit work using local state
16
+ # results = Farce::Unshared::Queue.new
17
+ # pool = Farce::Unshared::Pool.new(max_size: 2)
18
+ # pool.schedule { results.push(:done) }
19
+ # results.pop # => :done
20
+ # pool.close
21
+ class Pool < Abstract::Pool
22
+ include Unshareable
23
+ include Internal::LocalExecutorMethods
24
+
25
+ private
26
+
27
+ def publish_pool = pin_unshareable
28
+ def prepare_constructor(constructor) = constructor
29
+ def new_queue(capacity:) = Internal::UnsharedQueue.new(capacity:, track_age: true)
30
+ def new_worker = Internal::UnsharedPoolWorker.new(self)
31
+ def new_scheduler(**, &) = Scheduler.new(**, &)
32
+ def launch_scheduler(scheduler) = scheduler.launch_thread
33
+
34
+ def prepare_task(args, block, mode, auto_local)
35
+ validate_local_mode(mode, auto_local)
36
+ Internal::LocalScheduledTask.new(args, block)
37
+ end
38
+
39
+ def schedule_scaler(started, delay = @grow_after)
40
+ Internal::ThreadPoolSupervisor.current.schedule(self, started, delay)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Unshared
7
+ # A task scheduler that runs work within its creating Ractor.
8
+ #
9
+ # Use {.create} to start a background thread, or install an instance with
10
+ # `Fiber.set_scheduler` on the current thread. Tasks retain their blocks and
11
+ # argument references. The scheduler cannot be copied or moved to another Ractor.
12
+ #
13
+ # `auto_local: true` ignores `mode`. With `auto_local: false`, only `:local`
14
+ # and smart modes are accepted. All accepted modes keep tasks local.
15
+ #
16
+ # @example Run tasks with captured local state
17
+ # results = Farce::Unshared::Queue.new
18
+ # scheduler = Farce::Unshared::Scheduler.create
19
+ # scheduler.schedule { results.push(:done) }
20
+ # results.pop # => :done
21
+ # scheduler.close
22
+ #
23
+ # @!method schedule(*args, mode: :smart, auto_local: true)
24
+ # Enqueue a task while retaining its block and argument references.
25
+ # `mode` is ignored when `auto_local` is true. Otherwise, only local and
26
+ # smart modes are accepted.
27
+ # @param (see Farce::Abstract::Executor#schedule)
28
+ # @return [self]
29
+ class Scheduler < Abstract::Scheduler
30
+ include Unshareable
31
+ include Internal::LocalExecutorMethods
32
+
33
+ # Start a worker thread in this Ractor. Returns the running scheduler.
34
+ # Additional options and the block are forwarded to {#initialize}.
35
+ # @param executor [Class, nil] Thread or a custom executor that stays in this Ractor.
36
+ # @param name [String, nil] Optional worker name.
37
+ # @param priority [Integer, nil] Optional worker thread priority.
38
+ # @yieldreturn [Object] Fiber scheduler to install in the worker.
39
+ # @return [Scheduler]
40
+ def self.create(executor = Thread, name: nil, priority: nil, **, &) = super
41
+
42
+ # Create a scheduler without starting a worker.
43
+ # A constructor block builds the fiber scheduler when launched or installed.
44
+ # It may capture objects from this Ractor.
45
+ #
46
+ # @overload initialize(capacity: 1024, backend: Farce.config.io_backend, &constructor)
47
+ # @param capacity [Integer, nil] Pending-task capacity, or nil for an unbounded queue.
48
+ # @param backend [Symbol] IO backend for the built-in scheduler.
49
+ # @yieldreturn [Object] Fiber scheduler to install in the worker.
50
+ def initialize(...)
51
+ super
52
+ self.owner = Ractor.current
53
+ end
54
+
55
+ # Start dispatching tasks in a new thread or a custom executor in this Ractor.
56
+ # Rejects Ractor executors before changing the scheduler's state.
57
+ # @param executor [Class, nil] Thread or a custom executor that stays in this Ractor.
58
+ # @param name [String, nil] Optional worker name.
59
+ # @param priority [Integer, nil] Optional worker thread priority.
60
+ # @return [Thread, Object] The worker.
61
+ # @raise [ArgumentError] If a Ractor executor is supplied.
62
+ def launch(executor = Thread, name: nil, priority: nil)
63
+ raise ArgumentError, "Unshared schedulers cannot launch Ractor workers" if executor && executor <= Ractor
64
+ super(executor || Thread, name:, priority:)
65
+ end
66
+
67
+ # @raise [ArgumentError] Unshared schedulers cannot launch Ractor workers.
68
+ def launch_ractor(...) = launch(Ractor, ...)
69
+
70
+ # @param value [Ractor] The creating Ractor.
71
+ # @raise [ArgumentError] If another Ractor is supplied or the assigned owner changes.
72
+ def owner=(value)
73
+ raise ArgumentError, "owner must be the current Ractor" unless value == Ractor.current
74
+ super
75
+ end
76
+
77
+ private
78
+
79
+ def prepare_constructor(constructor) = constructor
80
+ def new_queue(capacity:) = Internal::UnsharedQueue.new(capacity:)
81
+ def launch_callback = ->(_scheduler, priority, name) { launch!(name, priority) }
82
+
83
+ def prepare_task(args, block, mode, auto_local)
84
+ validate_local_mode(mode, auto_local)
85
+ Internal::LocalScheduledTask.new(args, block)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -7,6 +7,7 @@ module Farce
7
7
  # A thread-safe set for mutable elements used within one Ractor.
8
8
  class Set < Farce::Abstract::Set
9
9
  include Unshareable
10
+ include Internal::Freeze::Delegated
10
11
 
11
12
  private def new_map(...) = Farce::Unshared::Map.new(...)
12
13
  end
@@ -7,6 +7,7 @@ module Farce
7
7
  # A thread-safe set maintained in ascending order within one Ractor.
8
8
  class SortedSet < Farce::Abstract::SortedSet
9
9
  include Unshareable
10
+ include Internal::Freeze::Delegated
10
11
 
11
12
  class MutableTreeMap < Farce::Unshared::TreeMap # :nodoc:
12
13
  private
@@ -14,8 +14,12 @@ module Farce
14
14
  # map[2].equal?(value) # => true
15
15
  class TreeMap < Abstract::TreeMap
16
16
  include Unshareable
17
+ include Internal::Freeze::Delegated
17
18
 
18
- private def new_tree_map(...) = Internal::TreeMap.new(...)
19
+ private
20
+
21
+ def new_tree_map(...) = Internal::TreeMap.new(...)
22
+ def freeze_backend = @map
19
23
  end
20
24
  end
21
25
  end
@@ -7,6 +7,7 @@ module Farce
7
7
  # A thread-safe vector for mutable values used within one Ractor.
8
8
  class Vector < Abstract::Vector
9
9
  include Unshareable
10
+ include Internal::Freeze::Delegated
10
11
 
11
12
  # @param source [Array, nil] Initial values. Values are retained directly.
12
13
  # @param compare_by_identity [Boolean] Whether values are compared by identity.
@@ -14,6 +15,8 @@ module Farce
14
15
  @vector = Internal::UnsharedVector.new(source, compare_by_identity:)
15
16
  super()
16
17
  end
18
+
19
+ private def freeze_backend = @vector
17
20
  end
18
21
  end
19
22
  end
@@ -24,8 +24,12 @@ module Farce
24
24
  # atom.value.equal?(replacement) # => true
25
25
  class WeakAtom < Abstract::WeakAtom
26
26
  include Unshareable
27
+ include Internal::Freeze::Delegated
27
28
 
28
- private def internal_atom_class = Internal::UnsharedWeakAtom
29
+ private
30
+
31
+ def internal_atom_class = Internal::UnsharedWeakAtom
32
+ def freeze_backend = @atom
29
33
  end
30
34
  end
31
35
  end
@@ -16,6 +16,7 @@ module Farce
16
16
  # owner = nil
17
17
  class WeakKeyMap < Abstract::WeakKeyMap
18
18
  include Unshareable
19
+ include Internal::Freeze::Delegated
19
20
 
20
21
  def initialize(
21
22
  initial_mapping = nil,
@@ -39,6 +40,8 @@ module Farce
39
40
  Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
40
41
  super()
41
42
  end
43
+
44
+ private def freeze_backend = @map
42
45
  end
43
46
  end
44
47
  end
@@ -16,6 +16,7 @@ module Farce
16
16
  # value = nil
17
17
  class WeakMap < Abstract::WeakMap
18
18
  include Unshareable
19
+ include Internal::Freeze::Delegated
19
20
 
20
21
  def initialize(
21
22
  initial_mapping = nil,
@@ -39,6 +40,8 @@ module Farce
39
40
  Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
40
41
  super()
41
42
  end
43
+
44
+ private def freeze_backend = @map
42
45
  end
43
46
  end
44
47
  end
@@ -7,6 +7,7 @@ module Farce
7
7
  # A thread-safe set that retains mutable elements weakly within one Ractor.
8
8
  class WeakSet < Farce::Abstract::WeakSet
9
9
  include Unshareable
10
+ include Internal::Freeze::Delegated
10
11
 
11
12
  private def new_map(...) = Farce::Unshared::WeakMap.new(...)
12
13
  end
@@ -15,6 +15,7 @@ module Farce
15
15
  # value = nil
16
16
  class WeakValueMap < Abstract::WeakValueMap
17
17
  include Unshareable
18
+ include Internal::Freeze::Delegated
18
19
 
19
20
  def initialize(
20
21
  initial_mapping = nil,
@@ -38,6 +39,8 @@ module Farce
38
39
  Internal::KeyNormalizer.install_concurrent(self, normalizer) if restoring
39
40
  super()
40
41
  end
42
+
43
+ private def freeze_backend = @map
41
44
  end
42
45
  end
43
46
  end
data/lib/farce/vector.rb CHANGED
@@ -10,9 +10,9 @@ module Farce
10
10
  # vector = Farce::Vector.new([[]], mode: :make_shareable)
11
11
  # vector.update(0) { |jobs| jobs + [:finished] } # => [:finished]
12
12
  #
13
- # @!method append(value, mode: nil, timeout: nil)
14
- # Append one value using the same options as {#push}.
15
- # @param value [BasicObject] The value to append.
13
+ # @!method append(*values, mode: nil, timeout: nil)
14
+ # Append values using the same options as {#push}.
15
+ # @param values [Array<BasicObject>] The values to append.
16
16
  # @param mode [Symbol, nil] The transfer mode, or nil to use the default.
17
17
  # @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
18
18
  # @return [self, false] Self on success, or false on timeout.
@@ -23,7 +23,7 @@ module Farce
23
23
  # @param source [Array, nil] Initial values. The source array is not retained.
24
24
  # @param mode [Symbol] The default value transfer mode.
25
25
  # @param compare_by_identity [Boolean] Whether values are compared by identity.
26
- def initialize(source = nil, mode: :copy, compare_by_identity: false)
26
+ def initialize(source = nil, mode: :smart, compare_by_identity: false)
27
27
  raise TypeError, "source must be an Array" unless source.nil? || source.is_a?(Array)
28
28
  unless true.equal?(compare_by_identity) || false.equal?(compare_by_identity)
29
29
  raise ArgumentError, "compare_by_identity must be true or false"
@@ -64,13 +64,20 @@ module Farce
64
64
  def shareable_values? = true
65
65
 
66
66
  # (see Farce::Abstract::Vector#[])
67
- def [](index) = @manager.unwrap(@vector[index])
67
+ def [](index, length = UNDEFINED)
68
+ return @manager.unwrap(@vector[index]) if length.equal?(UNDEFINED) && !index.is_a?(Range)
69
+ slice(index, length)
70
+ end
68
71
 
69
72
  # (see Farce::Abstract::Vector#[]=)
70
- def []=(index, value)
71
- check_frozen!
72
- @vector[index] = @manager.wrap(value)
73
- value
73
+ def []=(index, value, replacement = UNDEFINED)
74
+ if replacement.equal?(UNDEFINED) && !index.is_a?(Range)
75
+ check_frozen!
76
+ @vector[index] = @manager.wrap(value)
77
+ value
78
+ else
79
+ assign_vector_slice(index, value, replacement)
80
+ end
74
81
  end
75
82
 
76
83
  # (see Farce::Abstract::Vector#get)
@@ -85,13 +92,21 @@ module Farce
85
92
 
86
93
  # (see Farce::Abstract::Vector#push)
87
94
  # @param mode [Symbol, nil] The transfer mode, or nil to use the default.
88
- def push(value, mode: nil, timeout: nil)
89
- check_frozen!
90
- @vector.push(@manager.wrap(value, mode:), timeout:) ? self : false
95
+ def push(value = UNDEFINED, *rest, mode: nil, timeout: nil)
96
+ if rest.empty? && !value.equal?(UNDEFINED)
97
+ check_frozen!
98
+ stored = mode.nil? ? @manager.wrap(value) : @manager.wrap(value, mode:)
99
+ completed = timeout.nil? ? @vector.push(stored) : @vector.push(stored, timeout:)
100
+ return completed ? self : false
101
+ end
102
+ push_values(value.equal?(UNDEFINED) ? rest : [value, *rest], mode:, timeout:)
91
103
  end
92
104
 
93
105
  # (see Farce::Abstract::Vector#pop)
94
- def pop(timeout: nil) = @manager.unwrap(@vector.pop(timeout:))
106
+ def pop(count = UNDEFINED, timeout: nil)
107
+ return @manager.unwrap(timeout.nil? ? @vector.pop : @vector.pop(timeout:)) if count.equal?(UNDEFINED)
108
+ pop_values(count, timeout:)
109
+ end
95
110
 
96
111
  # (see Farce::Abstract::Vector#swap)
97
112
  # @!macro modes
@@ -183,7 +198,9 @@ module Farce
183
198
 
184
199
  protected
185
200
 
186
- def logical_value(value) = @manager.unwrap(value)
201
+ def logical_value(value) = @manager.unwrap(value)
202
+ def deletion_comparison(value) = wrap_comparison(value)
203
+ def deletion_match?(stored, expected) = values_equal?(stored, expected)
187
204
 
188
205
  def build_derived_vector(values)
189
206
  self.class.allocate.initialize_derived_vector(values, @manager, @compare_by_identity)
@@ -206,11 +223,19 @@ module Farce
206
223
 
207
224
  private
208
225
 
209
- def inspect_value(inspector, value) = super(inspector, value, @manager)
210
- def derived_storage(value) = @manager.wrap(value)
211
- def freeze_backend = @vector
212
- def wrap_comparison(value) = @manager.wrap(value, mode: compare_by_identity? ? :local : :copy)
213
- def values_equal?(left, right) = @manager.same_value?(left, right, identity: compare_by_identity?)
226
+ def inspect_value(inspector, value) = super(inspector, value, @manager)
227
+ def derived_storage(value) = @manager.wrap(value)
228
+ def prepare_vector_value(value, mode: nil) = @manager.wrap(value, mode:)
229
+
230
+ # Expanded descendants have no independent envelope to reuse. Copy them rather than
231
+ # moving them out of a retained parent Array or another sequence's storage.
232
+ def prepare_sequence_value(value)
233
+ @manager.wrap(value, mode: mode == :move ? :copy : nil)
234
+ end
235
+
236
+ def freeze_backend = @vector
237
+ def wrap_comparison(value) = @manager.wrap(value, mode: compare_by_identity? ? :local : :copy)
238
+ def values_equal?(left, right) = @manager.same_value?(left, right, identity: compare_by_identity?)
214
239
 
215
240
  def timeout_deadline(timeout)
216
241
  return if timeout.nil?
data/lib/farce/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
 
5
5
  module Farce
6
6
  # @return [String] the current version of Farce
7
- VERSION = "0.1.0"
7
+ VERSION = "0.3.0"
8
8
  end
data/lib/farce.rb CHANGED
@@ -54,7 +54,10 @@ module Farce
54
54
 
55
55
  # The valid transfer modes for values that are not Ractor-shareable.
56
56
  # @return [::Set<Symbol>]
57
- MODES = ::Set[:copy, :move, :local, :make_shareable, :mutable, :raise, :shareable_copy, :dedup, :proxy].freeze
57
+ MODES = ::Set[
58
+ :copy, :marshal, :move, :local, :make_shareable, :mutable, :raise, :shareable_copy, :dedup, :proxy,
59
+ :smart, :smart_raise, :smart_move, :smart_copy,
60
+ ].freeze
58
61
 
59
62
  UNDEFINED = Internal::Undefined.new("UNDEFINED")
60
63
 
@@ -171,7 +174,7 @@ module Farce
171
174
  DEDUPER.dedup(object, **)
172
175
  end
173
176
 
174
- # @overload enfarce(object, freeze: nil, mode: :copy)
177
+ # @overload enfarce(object, freeze: nil, mode: :smart)
175
178
  # Converts vanilla Ruby objects into their {Farce} equivalents.
176
179
  #
177
180
  # @!macro modes
@@ -357,7 +360,7 @@ module Farce
357
360
  # This allows scheduling without blocking the current thread.
358
361
  #
359
362
  # On JRuby and TruffleRuby, blocks run inline because there is no native Ractor isolation.
360
- # The returned {ThreadScheduler} starts a new thread for each scheduled task.
363
+ # The returned {ThreadExecutor} starts a new thread for each scheduled task.
361
364
  #
362
365
  # @example
363
366
  # $results = []
@@ -396,7 +399,7 @@ module Farce
396
399
  # # Hi from the current ractor!
397
400
  # # Hi again from the main ractor!
398
401
  #
399
- # @overload on_main(*args, mode: :copy)
402
+ # @overload on_main(*args, mode: :smart)
400
403
  # @param args [Array] The arguments to be passed to the block.
401
404
  # @param mode [Symbol] The argument transfer mode when called from another ractor.
402
405
  # @yield [*args] The block to be executed on the main ractor.
@@ -405,9 +408,9 @@ module Farce
405
408
  #
406
409
  # @overload on_main
407
410
  # Returns a scheduler that executes tasks on the main ractor.
408
- # @return [Abstract::Scheduler]
411
+ # @return [Abstract::Executor]
409
412
  #
410
- # @return [Abstract::Scheduler, nil]
413
+ # @return [Abstract::Executor, nil]
411
414
  # @see .in_parallel
412
415
  def self.on_main(*args, mode: UNDEFINED, &)
413
416
  unless block_given?
@@ -418,7 +421,7 @@ module Farce
418
421
  if Ractor.main?
419
422
  yield(*args)
420
423
  else
421
- mode = :copy if UNDEFINED.equal?(mode)
424
+ mode = :smart if UNDEFINED.equal?(mode)
422
425
  Internal::MainScheduler.execute(*args, mode:, auto_local: false, &)
423
426
  end
424
427
 
@@ -438,16 +441,16 @@ module Farce
438
441
  # Farce.in_parallel("hello") { |message| puts message.upcase }
439
442
  # Farce.in_parallel.schedule { puts "another task" }
440
443
  #
441
- # @overload in_parallel(*args, mode: :copy)
444
+ # @overload in_parallel(*args, mode: :smart)
442
445
  # @param args [Array<Object>] Arguments passed to the block.
443
446
  # @param mode [Symbol] Argument transfer mode. Ignored on JRuby and TruffleRuby.
444
447
  # @yield [*args] The task to schedule.
445
448
  # @return [nil]
446
449
  #
447
450
  # @overload in_parallel
448
- # @return [Abstract::Scheduler] The shared scheduler.
451
+ # @return [Abstract::Executor] The shared scheduler.
449
452
  #
450
- # @return [Abstract::Scheduler, nil]
453
+ # @return [Abstract::Executor, nil]
451
454
  # @see .on_main
452
455
  def self.in_parallel(*args, mode: UNDEFINED, &)
453
456
  unless block_given?
@@ -455,12 +458,12 @@ module Farce
455
458
  return Internal::ParallelScheduler
456
459
  end
457
460
 
458
- mode = :copy if UNDEFINED.equal?(mode)
461
+ mode = :smart if UNDEFINED.equal?(mode)
459
462
  Internal::ParallelScheduler.schedule(*args, mode:, &)
460
463
  nil
461
464
  end
462
465
 
463
- # @overload schedule(*args, mode: :copy, auto_local: true, **kwargs)
466
+ # @overload schedule(*args, mode: :smart, auto_local: true, **kwargs)
464
467
  # Schedules work to be executed out of band.
465
468
  #
466
469
  # If the `mode` is set to `:local`, it will use the current thread's fiber scheduler to schedule the task.
@@ -486,26 +489,18 @@ module Farce
486
489
  # @param kwargs [Hash] Additional keyword arguments passed to the scheduler.
487
490
  # @yield [*args] The task to schedule.
488
491
  # @return [nil]
489
- def self.schedule(*, mode: :copy, auto_local: true, **, &)
492
+ def self.schedule(*, mode: :smart, auto_local: true, **, &)
490
493
  raise LocalJumpError, "no block given" unless block_given?
491
494
 
492
495
  if auto_local || mode == :local
493
- if Fiber.respond_to?(:scheduler) && fiber_scheduler = Fiber.scheduler
494
- fiber_scheduler.fiber(**) { yield(*) }
496
+ scheduler = Internal.local_scheduler(create: mode == :local)
497
+ if scheduler && !scheduler.is_a?(Abstract::Executor)
498
+ scheduler.fiber(**) { yield(*) }
495
499
  return
496
500
  end
497
- scheduler = Ractor.main? ? Internal::MainScheduler : Internal::Storage[:local_scheduler]
498
501
  end
499
502
 
500
- scheduler ||=
501
- if mode == :local
502
- Internal::Storage.store_if_absent(:local_scheduler) do
503
- Internal.native_ractors? ? Scheduler.create(Thread) : ThreadScheduler.new
504
- end
505
- else
506
- Internal::ParallelScheduler
507
- end
508
-
503
+ scheduler ||= Internal::ParallelScheduler
509
504
  scheduler.schedule(*, mode:, auto_local:, **, &)
510
505
  nil
511
506
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: farce
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Haase
@@ -85,6 +85,7 @@ files:
85
85
  - lib/farce/abstract/counter.rb
86
86
  - lib/farce/abstract/duplicable_map.rb
87
87
  - lib/farce/abstract/exchanger.rb
88
+ - lib/farce/abstract/executor.rb
88
89
  - lib/farce/abstract/flag.rb
89
90
  - lib/farce/abstract/lazy.rb
90
91
  - lib/farce/abstract/lease.rb
@@ -94,6 +95,7 @@ files:
94
95
  - lib/farce/abstract/lru_map.rb
95
96
  - lib/farce/abstract/map.rb
96
97
  - lib/farce/abstract/molecule.rb
98
+ - lib/farce/abstract/pool.rb
97
99
  - lib/farce/abstract/port.rb
98
100
  - lib/farce/abstract/priority_queue.rb
99
101
  - lib/farce/abstract/queue.rb
@@ -155,6 +157,7 @@ files:
155
157
  - lib/farce/engine/ruby/shared/proxy_owner.rb
156
158
  - lib/farce/engine/ruby/shared/ractor_methods.rb
157
159
  - lib/farce/engine/ruby/shared/ractor_selector.rb
160
+ - lib/farce/engine/ruby/shared/require_hook.rb
158
161
  - lib/farce/engine/ruby/shared/strict_map.rb
159
162
  - lib/farce/engine/ruby/shared/unshared_vector.rb
160
163
  - lib/farce/engine/ruby/shared/vault.rb
@@ -227,6 +230,7 @@ files:
227
230
  - lib/farce/integrations/bson.rb
228
231
  - lib/farce/integrations/cbor.rb
229
232
  - lib/farce/integrations/concurrent.rb
233
+ - lib/farce/integrations/date.rb
230
234
  - lib/farce/integrations/dry-types.rb
231
235
  - lib/farce/integrations/dry_types.rb
232
236
  - lib/farce/integrations/json.rb
@@ -250,6 +254,7 @@ files:
250
254
  - lib/farce/internal/delegation.rb
251
255
  - lib/farce/internal/external_transaction.rb
252
256
  - lib/farce/internal/fake_ractor.rb
257
+ - lib/farce/internal/flag_waiting.rb
253
258
  - lib/farce/internal/freeze.rb
254
259
  - lib/farce/internal/inspect.rb
255
260
  - lib/farce/internal/key_lock_map.rb
@@ -259,6 +264,8 @@ files:
259
264
  - lib/farce/internal/lease_pool_state.rb
260
265
  - lib/farce/internal/lease_state.rb
261
266
  - lib/farce/internal/lease_waiting.rb
267
+ - lib/farce/internal/local_executor_methods.rb
268
+ - lib/farce/internal/local_scheduled_task.rb
262
269
  - lib/farce/internal/managed_queue.rb
263
270
  - lib/farce/internal/map_value_modes.rb
264
271
  - lib/farce/internal/marshal_support.rb
@@ -284,12 +291,14 @@ files:
284
291
  - lib/farce/internal/strict_lease_map.rb
285
292
  - lib/farce/internal/strict_lease_pool.rb
286
293
  - lib/farce/internal/thread_pool.rb
294
+ - lib/farce/internal/thread_pool_supervisor.rb
287
295
  - lib/farce/internal/transaction_conflict.rb
288
296
  - lib/farce/internal/transaction_freeze_guard.rb
289
297
  - lib/farce/internal/transaction_map_snapshot.rb
290
298
  - lib/farce/internal/undefined.rb
291
299
  - lib/farce/internal/unshared_lease.rb
292
300
  - lib/farce/internal/unshared_lease_pool.rb
301
+ - lib/farce/internal/unshared_pool_worker.rb
293
302
  - lib/farce/internal/unshared_queue_waiting.rb
294
303
  - lib/farce/internal/value_serialization.rb
295
304
  - lib/farce/internal/weak_map_value_modes.rb
@@ -313,8 +322,10 @@ files:
313
322
  - lib/farce/local/lru_map.rb
314
323
  - lib/farce/local/map.rb
315
324
  - lib/farce/local/molecule.rb
325
+ - lib/farce/local/pool.rb
316
326
  - lib/farce/local/priority_queue.rb
317
327
  - lib/farce/local/queue.rb
328
+ - lib/farce/local/scheduler.rb
318
329
  - lib/farce/local/scoped.rb
319
330
  - lib/farce/local/set.rb
320
331
  - lib/farce/local/sorted_set.rb
@@ -330,6 +341,7 @@ files:
330
341
  - lib/farce/lru_map.rb
331
342
  - lib/farce/map.rb
332
343
  - lib/farce/mode_manager.rb
344
+ - lib/farce/mode_manager/smart_rule.rb
333
345
  - lib/farce/molecule.rb
334
346
  - lib/farce/mutable.rb
335
347
  - lib/farce/pool.rb
@@ -378,7 +390,8 @@ files:
378
390
  - lib/farce/strict/weak_set.rb
379
391
  - lib/farce/strict/weak_value_map.rb
380
392
  - lib/farce/system.rb
381
- - lib/farce/thread_scheduler.rb
393
+ - lib/farce/task.rb
394
+ - lib/farce/thread_executor.rb
382
395
  - lib/farce/timer_queue.rb
383
396
  - lib/farce/transaction.rb
384
397
  - lib/farce/transaction/atom.rb
@@ -411,8 +424,10 @@ files:
411
424
  - lib/farce/unshared/lru_map.rb
412
425
  - lib/farce/unshared/map.rb
413
426
  - lib/farce/unshared/molecule.rb
427
+ - lib/farce/unshared/pool.rb
414
428
  - lib/farce/unshared/priority_queue.rb
415
429
  - lib/farce/unshared/queue.rb
430
+ - lib/farce/unshared/scheduler.rb
416
431
  - lib/farce/unshared/set.rb
417
432
  - lib/farce/unshared/sorted_set.rb
418
433
  - lib/farce/unshared/timer_queue.rb