Class: Kobako::HandleTable

Inherits:
Object
  • Object
show all
Defined in:
lib/kobako/handle_table.rb

Overview

Host-side mapping from opaque integer Handle IDs to Ruby objects. The table is owned by Kobako::Sandbox (docs/behavior.md B-19) and injected into the per-Sandbox Kobako::RPC::Server so guest→host RPC dispatch resolves Handle targets and arguments against the same table that host→guest wire encoding allocates into (docs/behavior.md B-14, B-34).

Lifecycle invariants (docs/behavior.md):

- {docs/behavior.md B-15}[link:../../docs/behavior.md] — Handle IDs are
  allocated by a monotonically increasing counter scoped to a single
  invocation. The first ID issued in an invocation is 1; ID 0 is reserved
  as the invalid sentinel and is never returned by +#alloc+.

- {docs/behavior.md B-19}[link:../../docs/behavior.md] — At every
  invocation boundary (via +#reset!+), every Handle issued under the
  old state becomes invalid. Reset applies uniformly regardless of
  allocation source (B-14 Service return or B-34 host-injected
  argument).

- {docs/behavior.md B-21}[link:../../docs/behavior.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

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 Kobako::Handle::MAX_ID to exercise the cap-exhaustion path without 2³¹ allocations.



34
35
36
37
# File 'lib/kobako/handle_table.rb', line 34

def initialize(next_id: 1)
  @entries = {} # : Hash[Integer, untyped]
  @next_id = next_id
end

Instance Method Details

#alloc(object) ⇒ Object

Bind object in the table and return a Kobako::Handle token for it. object is any host-side Ruby object to bind. Returns a freshly-allocated Kobako::Handle whose #id falls in [Kobako::Handle::MIN_ID, Kobako::Handle::MAX_ID]. Raises Kobako::HandleTableExhausted if the next ID would exceed the cap. The cap is anchored on Kobako::Handle — the wire codec and the allocator share the same invariant (docs/behavior.md B-21).

Returning a Handle (rather than a bare Integer id) keeps the allocator’s output a domain entity; Kobako::Handle.from_wire is reserved for the codec’s wire-decode path, where the id is the only thing the bytes carry.



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/kobako/handle_table.rb', line 52

def alloc(object)
  id = @next_id
  cap = Kobako::Handle::MAX_ID
  if id > cap
    raise HandleTableExhausted,
          "Handle id space exhausted: allocation would assign id #{id}, exceeding the cap (#{cap})"
  end

  @entries[id] = object
  @next_id = id + 1
  Kobako::Handle.from_wire(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.



68
69
70
71
# File 'lib/kobako/handle_table.rb', line 68

def fetch(id)
  require_bound!(id)
  @entries[id]
end

#include?(id) ⇒ Boolean

Returns true when id is currently bound, false otherwise.

Returns:

  • (Boolean)


104
105
106
# File 'lib/kobako/handle_table.rb', line 104

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!.



93
94
95
96
# File 'lib/kobako/handle_table.rb', line 93

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.



76
77
78
79
# File 'lib/kobako/handle_table.rb', line 76

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-invocation boundary by Kobako::Sandbox — see docs/behavior.md B-19. Returns self.



84
85
86
87
88
# File 'lib/kobako/handle_table.rb', line 84

def reset!
  @entries.clear
  @next_id = 1
  self
end

#sizeObject

Returns the number of currently-bound entries.



99
100
101
# File 'lib/kobako/handle_table.rb', line 99

def size
  @entries.size
end