Class: Cordis::Fiber
- Inherits:
-
Object
- Object
- Cordis::Fiber
- Defined in:
- lib/cordis/fiber.rb
Overview
Fiber (upstream 4.0's new name for EffectScope): the lifecycle unit of a plugin, and also the collector of revertible effects (the paper's phi accumulator). Note: the clash with Ruby core's ::Fiber is deliberate, to match upstream naming; Cordis never uses core Fiber directly.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- INACTIVE =
:__inactive__
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#ctx ⇒ Object
readonly
Returns the value of attribute ctx.
-
#error ⇒ Object
readonly
Returns the value of attribute error.
-
#inject ⇒ Object
readonly
Returns the value of attribute inject.
-
#parent_ctx ⇒ Object
readonly
Returns the value of attribute parent_ctx.
-
#parent_fiber ⇒ Object
readonly
Returns the value of attribute parent_fiber.
-
#provided ⇒ Object
readonly
Returns the value of attribute provided.
-
#runtime ⇒ Object
readonly
Returns the value of attribute runtime.
-
#state ⇒ Object
readonly
Returns the value of attribute state.
-
#store ⇒ Object
readonly
Returns the value of attribute store.
-
#uid ⇒ Object
readonly
Returns the value of attribute uid.
Instance Method Summary collapse
- #assert_active ⇒ Object
-
#await ⇒ Object
Wait for all in-flight transitions to finish (while, not if: transitions chain).
-
#check_impl(name) ⇒ Object
-- coeffect machinery (dependency-graph updates are fully synchronous; only load/unload execution is async) --.
- #dispose ⇒ Object
- #disposed? ⇒ Boolean
-
#effect(label = nil, &block) ⇒ Object
Apply a side effect and collect its inverse.
-
#initialize(parent_ctx, config: nil, inject: {}, runtime: nil) ⇒ Fiber
constructor
A new instance of Fiber.
- #name ⇒ Object
- #refresh ⇒ Object
- #restart ⇒ Object
- #root? ⇒ Boolean
- #update(config) ⇒ Object
Constructor Details
#initialize(parent_ctx, config: nil, inject: {}, runtime: nil) ⇒ Fiber
Returns a new instance of Fiber.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/cordis/fiber.rb', line 18 def initialize(parent_ctx, config: nil, inject: {}, runtime: nil) @config = config @inject = inject @runtime = runtime @disposables = [] @provided = {} # name => isolate key (for boundary-crossing notify on state change) @internal_store = {} # currently satisfied dependencies (name => Impl), continuously updated @store = nil # snapshot taken while loading; nil means unloaded @current_epoch = INACTIVE @target_epoch = INACTIVE @inertia = nil # in-flight load/unload transition task @error = nil @state = :pending if runtime.nil? # root fiber @uid = 0 @ctx = parent_ctx @parent_fiber = nil @current_epoch = @target_epoch = '' @store = {} @state = :active return end @uid = parent_ctx.root.registry.next_uid @parent_fiber = parent_ctx.fiber @parent_ctx = parent_ctx @ctx = parent_ctx.extend(fiber: self) # inject with a Hash config doubles as an intercept entry on the plugin's ctx # (mirrors upstream fiber.ts:139) inject.each { |dep, cfg| @ctx = @ctx.intercept(dep, cfg) if cfg.is_a?(Hash) } runtime.fibers << self @ctx.events.emit('internal/plugin', self) inject.each_key { |name| check_impl(name) } # a plugin is itself a revertible effect on the parent fiber (mirrors upstream fiber.ts:170) @entry = parent_ctx.fiber.effect('ctx.plugin()') do refresh -> { terminate } end end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def config @config end |
#ctx ⇒ Object (readonly)
Returns the value of attribute ctx.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def ctx @ctx end |
#error ⇒ Object (readonly)
Returns the value of attribute error.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def error @error end |
#inject ⇒ Object (readonly)
Returns the value of attribute inject.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def inject @inject end |
#parent_ctx ⇒ Object (readonly)
Returns the value of attribute parent_ctx.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def parent_ctx @parent_ctx end |
#parent_fiber ⇒ Object (readonly)
Returns the value of attribute parent_fiber.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def parent_fiber @parent_fiber end |
#provided ⇒ Object (readonly)
Returns the value of attribute provided.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def provided @provided end |
#runtime ⇒ Object (readonly)
Returns the value of attribute runtime.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def runtime @runtime end |
#state ⇒ Object (readonly)
Returns the value of attribute state.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def state @state end |
#store ⇒ Object (readonly)
Returns the value of attribute store.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def store @store end |
#uid ⇒ Object (readonly)
Returns the value of attribute uid.
15 16 17 |
# File 'lib/cordis/fiber.rb', line 15 def uid @uid end |
Instance Method Details
#assert_active ⇒ Object
84 85 86 87 88 |
# File 'lib/cordis/fiber.rb', line 84 def assert_active return if @store && %i[loading active].include?(@state) raise InactiveEffectError, 'cannot create effect on inactive context' end |
#await ⇒ Object
Wait for all in-flight transitions to finish (while, not if: transitions chain).
91 92 93 94 95 96 97 98 |
# File 'lib/cordis/fiber.rb', line 91 def await while (task = @inertia) task.wait end raise @error if @error self end |
#check_impl(name) ⇒ Object
-- coeffect machinery (dependency-graph updates are fully synchronous; only load/unload execution is async) --
123 124 125 126 127 128 129 130 |
# File 'lib/cordis/fiber.rb', line 123 def check_impl(name) impl = @ctx.root.services[@ctx.isolate_key(name)] if impl && impl.fiber.state == :active @internal_store[name] = impl else @internal_store.delete(name) end end |
#dispose ⇒ Object
100 101 102 103 104 105 |
# File 'lib/cordis/fiber.rb', line 100 def dispose return restart if root? @entry.call nil end |
#disposed? ⇒ Boolean
60 |
# File 'lib/cordis/fiber.rb', line 60 def disposed? = @uid.nil? |
#effect(label = nil, &block) ⇒ Object
Apply a side effect and collect its inverse. The block returns: nil (nothing), a callable (single disposer), or an Array/Enumerator of callables (multi-step disposers, reverted in reverse order — upstream's function* effects). If setup raises midway, already-collected disposers are rolled back in reverse, then re-raised.
72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/cordis/fiber.rb', line 72 def effect(label = nil, &block) assert_active disposers = collect_disposers(block, rollback: true) entry = Entry.new(disposers, label) @disposables << entry lambda do next unless @disposables.reject! { |e| e.equal?(entry) } entry.disposers.reverse_each(&:call) end end |
#name ⇒ Object
62 63 64 65 66 |
# File 'lib/cordis/fiber.rb', line 62 def name return 'root' if root? @runtime.name || 'plugin' end |
#refresh ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/cordis/fiber.rb', line 132 def refresh epoch = '' @inject.each_key do |name| impl = @internal_store[name] if impl.nil? epoch = INACTIVE break end epoch = "#{epoch}:#{impl.fiber.uid}" end set_epoch(epoch) end |
#restart ⇒ Object
107 108 109 110 111 112 113 |
# File 'lib/cordis/fiber.rb', line 107 def restart set_epoch(INACTIVE) await # wait for the unload first (refreshing right away would set the target back # to the original epoch and coalesce the unload intent away) refresh await end |
#root? ⇒ Boolean
59 |
# File 'lib/cordis/fiber.rb', line 59 def root? = @runtime.nil? |
#update(config) ⇒ Object
115 116 117 118 |
# File 'lib/cordis/fiber.rb', line 115 def update(config) @config = config restart end |