Module: Kobako::Codec::ExtTypes

Defined in:
lib/kobako/codec/ext_types.rb,
sig/kobako/codec/ext_types.rbs

Overview

The kobako wire ext-type conversions (docs/wire-codec.md § Ext Types) as pure functions: per-operation decode state is threaded in as an argument, so the module itself holds nothing. #build_factory assembles the one MessagePack::Factory these conversions are registered on.

Constant Summary collapse

EXT_SYMBOL =

MessagePack ext type code reserved for Symbol (docs/wire-codec.md § Ext Types → ext 0x00). Module-private — mirrors codec::EXT_SYMBOL on the Rust side.

Returns:

  • (Integer)
0x00
EXT_HANDLE =

MessagePack ext type code reserved for Capability Handle (docs/wire-codec.md § Ext Types → ext 0x01). Module-private — mirrors codec::EXT_HANDLE on the Rust side.

Returns:

  • (Integer)
0x01
EXT_ERRENV =

MessagePack ext type code reserved for Exception envelope (docs/wire-codec.md § Ext Types → ext 0x02). Module-private — mirrors codec::EXT_ERRENV on the Rust side.

Returns:

  • (Integer)
0x02

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.build_factoryObject

Assemble a MessagePack::Factory with the three kobako ext types registered, frozen because registration is its only mutation and happens exactly once. The stateful conversions resolve their per-operation state at call time, so one registered factory serves every thread.



43
44
45
46
47
48
49
# File 'lib/kobako/codec/ext_types.rb', line 43

def build_factory
  factory = MessagePack::Factory.new
  register_symbol(factory)
  register_handle(factory)
  register_fault(factory)
  factory.freeze
end

.pack_fault(fault, state) ⇒ Object

Encode the inner ext-0x02 map via Encoder (not the raw factory) so the embedded payload flows through the same boundary as a top-level encode — nested kobako values (Handle, nested Fault) reach the registered ext-type packers. A details chain nested past the state depth cap has no wire representation and surfaces as UnsupportedType. In a payload position (+state+ inside a forbid_faults bracket) the envelope has no wire representation at all, so the refusal routes the value into the position's non-representable handling — the Dispatcher's auto-wrap rescue, or a raise at the yield site.



102
103
104
105
106
107
108
109
110
# File 'lib/kobako/codec/ext_types.rb', line 102

def pack_fault(fault, state)
  if state.faults_forbidden?
    raise UnsupportedType, "Kobako::Fault has no wire representation in a payload position"
  end

  state.within_ext_frame(UnsupportedType) do
    Encoder.encode("type" => fault.type, "message" => fault.message, "details" => fault.details)
  end
end

.pack_handle(handle) ⇒ Object

Handle-id packer for the ext-0x01 registration: the fixext-4 big-endian id frame.



72
73
74
# File 'lib/kobako/codec/ext_types.rb', line 72

def pack_handle(handle)
  [handle.id].pack("N")
end

.pack_symbol(symbol) ⇒ Object

Symbol-to-name packer for the ext-0x00 registration.



52
53
54
# File 'lib/kobako/codec/ext_types.rb', line 52

def pack_symbol(symbol)
  symbol.name
end

.register_fault(factory) ⇒ Object



153
154
155
156
157
158
159
# File 'lib/kobako/codec/ext_types.rb', line 153

def register_fault(factory)
  factory.register_type(
    EXT_ERRENV, Kobako::Fault,
    packer: ->(fault) { ExtTypes.pack_fault(fault, State.current) },
    unpacker: ->(payload) { ExtTypes.unpack_fault(payload, State.current) }
  )
end

.register_handle(factory) ⇒ Object



145
146
147
148
149
150
151
# File 'lib/kobako/codec/ext_types.rb', line 145

def register_handle(factory)
  factory.register_type(
    EXT_HANDLE, Kobako::Handle,
    packer: ->(handle) { ExtTypes.pack_handle(handle) },
    unpacker: ->(payload) { ExtTypes.unpack_handle(payload, State.current) }
  )
end

.register_symbol(factory) ⇒ Object



137
138
139
140
141
142
143
# File 'lib/kobako/codec/ext_types.rb', line 137

def register_symbol(factory)
  factory.register_type(
    EXT_SYMBOL, Symbol,
    packer: ->(symbol) { ExtTypes.pack_symbol(symbol) },
    unpacker: ->(payload) { ExtTypes.unpack_symbol(payload) }
  )
end

.unpack_fault(payload, state) ⇒ Object

Peel the embedded msgpack map and hand it to Kobako::Fault.new inside Decoder.decode's block form, so the value-object's ArgumentError invariants surface as InvalidType through the decoder boundary. Inner decode goes through Decoder (not the raw factory) so the embedded str payloads flow through the same UTF-8 validation as a top-level decode. A nested ext 0x02 in details re-enters this method, so the state ext-frame guard bounds the chain depth to keep it from exhausting the native stack. In a payload position (+state+ inside a forbid_faults bracket) the envelope is a wire violation outright — its sole legal position is the Response fault field.



123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/kobako/codec/ext_types.rb', line 123

def unpack_fault(payload, state)
  if state.faults_forbidden?
    raise InvalidType, "Fault envelope (ext 0x02) is not a legal value in a payload position"
  end

  state.within_ext_frame(InvalidType) do
    Decoder.decode(payload) do |map|
      raise InvalidType, "Fault payload must be a map" unless map.is_a?(Hash)

      Kobako::Fault.new(type: map["type"], message: map["message"], details: map["details"])
    end
  end
end

.unpack_handle(payload, state) ⇒ Object

Peel off the fixext-4 frame, hand the bytes to the Host-Gem-internal Kobako::Handle.restore factory, and translate the ArgumentError raised by Handle's invariants into a wire-layer InvalidType via Codec::Utils.with_boundary. The Value Object owns the id-range contract; this method only owns the frame shape. Records the Handle sighting on state so a Handle-free decode can skip the downstream resolution walk.

Raises:



83
84
85
86
87
88
89
90
# File 'lib/kobako/codec/ext_types.rb', line 83

def unpack_handle(payload, state)
  state.record_handle!
  bytes = payload.b
  raise InvalidType, "Handle payload must be 4 bytes, got #{bytes.bytesize}" unless bytes.bytesize == 4

  id = bytes.unpack1("N") # : Integer
  Codec::Utils.with_boundary { Kobako::Handle.restore(id) }
end

.unpack_symbol(payload) ⇒ Object

Validate the ext-0x00 payload as UTF-8 and intern. Raises InvalidEncoding on invalid bytes — SPEC forbids the binary-encoding fallback that msgpack-gem's default unpacker would otherwise apply. The re-tag step lives here because the msgpack ext-type unpacker hands us binary bytes; the assertion itself is shared with Decoder via Utils.assert_utf8!. The "Symbol" label keeps the error message in Ruby vocabulary rather than wire-ext-code vocabulary.



64
65
66
67
68
# File 'lib/kobako/codec/ext_types.rb', line 64

def unpack_symbol(payload)
  name = payload.b.force_encoding(Encoding::UTF_8)
  Utils.assert_utf8!(name, "Symbol payload")
  name.to_sym
end

Instance Method Details

#self?.build_factoryMessagePack::Factory

Returns:

  • (MessagePack::Factory)


8
# File 'sig/kobako/codec/ext_types.rbs', line 8

def self?.build_factory: () -> MessagePack::Factory

#self?.pack_faultString

Parameters:

Returns:

  • (String)


18
# File 'sig/kobako/codec/ext_types.rbs', line 18

def self?.pack_fault: (Kobako::Fault fault, State state) -> String

#self?.pack_handleString

Parameters:

Returns:

  • (String)


14
# File 'sig/kobako/codec/ext_types.rbs', line 14

def self?.pack_handle: (Kobako::Handle handle) -> String

#self?.pack_symbolString

Parameters:

  • symbol (Symbol)

Returns:

  • (String)


10
# File 'sig/kobako/codec/ext_types.rbs', line 10

def self?.pack_symbol: (Symbol symbol) -> String

#self?.register_faultvoid

This method returns an undefined value.

Parameters:

  • factory (MessagePack::Factory)


26
# File 'sig/kobako/codec/ext_types.rbs', line 26

def self?.register_fault: (MessagePack::Factory factory) -> void

#self?.register_handlevoid

This method returns an undefined value.

Parameters:

  • factory (MessagePack::Factory)


24
# File 'sig/kobako/codec/ext_types.rbs', line 24

def self?.register_handle: (MessagePack::Factory factory) -> void

#self?.register_symbolvoid

This method returns an undefined value.

Parameters:

  • factory (MessagePack::Factory)


22
# File 'sig/kobako/codec/ext_types.rbs', line 22

def self?.register_symbol: (MessagePack::Factory factory) -> void

#self?.unpack_faultKobako::Fault

Parameters:

  • payload (String)
  • state (State)

Returns:



20
# File 'sig/kobako/codec/ext_types.rbs', line 20

def self?.unpack_fault: (String payload, State state) -> Kobako::Fault

#self?.unpack_handleKobako::Handle

Parameters:

  • payload (String)
  • state (State)

Returns:



16
# File 'sig/kobako/codec/ext_types.rbs', line 16

def self?.unpack_handle: (String payload, State state) -> Kobako::Handle

#self?.unpack_symbolSymbol

Parameters:

  • payload (String)

Returns:

  • (Symbol)


12
# File 'sig/kobako/codec/ext_types.rbs', line 12

def self?.unpack_symbol: (String payload) -> Symbol