Class: Kobako::Registry::HandleTable
- Inherits:
-
Object
- Object
- Kobako::Registry::HandleTable
- Defined in:
- lib/kobako/registry/handle_table.rb
Overview
Host-side mapping from opaque integer Handle IDs to Ruby objects (capability proxies). One table is owned per Kobako::Registry instance (and therefore per Kobako::Sandbox instance). See SPEC.md B-15.
Lifecycle invariants (SPEC.md):
- {SPEC.md B-15}[link:../../../SPEC.md] — Handle IDs are allocated by
a monotonically increasing counter scoped to a single `#run`. The
first ID issued in a run is 1; ID 0 is reserved as the invalid
sentinel and is never returned by #alloc.
- {SPEC.md B-19}[link:../../../SPEC.md] — When between `#run`
invocations (via `#reset!`), every Handle issued under the old state
becomes invalid.
- {SPEC.md B-21}[link:../../../SPEC.md] — The cap is `0x7fff_ffff`
(2³¹ − 1). Allocation beyond the cap raises immediately — no silent
truncation, no wrap, no ID reuse.
Instance Method Summary collapse
-
#alloc(object) ⇒ Object
Bind
objectin the table and return its newly-allocated Handle ID. -
#fetch(id) ⇒ Object
Resolve a Handle ID to its bound object.
-
#include?(id) ⇒ Boolean
Returns
truewhenidis currently bound,falseotherwise. -
#initialize(next_id: 1) ⇒ HandleTable
constructor
Build a fresh, empty HandleTable.
-
#mark_disconnected(id) ⇒ Object
Mark the entry at
idas disconnected (ABA protection). -
#release(id) ⇒ Object
Remove and return the binding for
id. -
#reset! ⇒ Object
Clear all entries AND reset the counter to 1.
-
#size ⇒ Object
Returns the number of currently-bound entries.
Constructor Details
#initialize(next_id: 1) ⇒ HandleTable
Build a fresh, empty HandleTable. next_id is an internal seam that sets the starting value of the monotonic counter (defaults to 1 per B-15); tests pass a value near Wire::Handle::MAX_ID to exercise the cap-exhaustion path without 2³¹ allocations.
31 32 33 34 |
# File 'lib/kobako/registry/handle_table.rb', line 31 def initialize(next_id: 1) @entries = {} @next_id = next_id end |
Instance Method Details
#alloc(object) ⇒ Object
Bind object in the table and return its newly-allocated Handle ID. object is any host-side Ruby object to bind. Returns a freshly- allocated Handle ID in [1, Wire::Handle::MAX_ID]. Raises Kobako::HandleTableExhausted if the next ID would exceed the cap. The cap is anchored on Wire::Handle — the wire codec and the allocator share the same invariant (SPEC.md B-21).
42 43 44 45 46 47 48 49 50 |
# File 'lib/kobako/registry/handle_table.rb', line 42 def alloc(object) id = @next_id cap = Wire::Handle::MAX_ID raise HandleTableExhausted, "HandleTable exhausted: id #{id} exceeds MAX_ID #{cap}" if id > cap @entries[id] = object @next_id = id + 1 id end |
#fetch(id) ⇒ Object
Resolve a Handle ID to its bound object. id is a Handle ID previously returned by #alloc. Returns the bound object. Raises Kobako::HandleTableError if id is not currently bound.
55 56 57 58 |
# File 'lib/kobako/registry/handle_table.rb', line 55 def fetch(id) require_bound!(id) @entries[id] end |
#include?(id) ⇒ Boolean
Returns true when id is currently bound, false otherwise.
91 92 93 |
# File 'lib/kobako/registry/handle_table.rb', line 91 def include?(id) @entries.key?(id) end |
#mark_disconnected(id) ⇒ Object
Mark the entry at id as disconnected (ABA protection). id is the Handle ID to poison; silently ignored if id is not currently bound. Returns self for chainability, matching the convention of #reset!.
80 81 82 83 |
# File 'lib/kobako/registry/handle_table.rb', line 80 def mark_disconnected(id) @entries[id] = :disconnected if @entries.key?(id) self end |
#release(id) ⇒ Object
Remove and return the binding for id. id is the Handle ID to release. Returns the previously-bound object. Raises Kobako::HandleTableError if id is not currently bound.
63 64 65 66 |
# File 'lib/kobako/registry/handle_table.rb', line 63 def release(id) require_bound!(id) @entries.delete(id) end |
#reset! ⇒ Object
Clear all entries AND reset the counter to 1. Called at the per-run boundary — see SPEC.md B-19. Returns self.
71 72 73 74 75 |
# File 'lib/kobako/registry/handle_table.rb', line 71 def reset! @entries.clear @next_id = 1 self end |
#size ⇒ Object
Returns the number of currently-bound entries.
86 87 88 |
# File 'lib/kobako/registry/handle_table.rb', line 86 def size @entries.size end |