Module: Kobako::Codec::Utils
- Defined in:
- lib/kobako/codec/utils.rb
Overview
Wire-codec helpers shared by the host-side encoders and decoders. Three concerns live here today:
- UTF-8 assertion at the wire boundary
({docs/wire-codec.md}[link:../../../docs/wire-codec.md]
§ str/bin Encoding Rules and § Ext Types → ext 0x00). Used by
{Decoder} when walking +str+ family payloads and by {Factory}
when validating the +ext 0x00+ Symbol payload.
- Wire-boundary +ArgumentError+ translation
({wire_boundary}) so the public taxonomy stays
{Kobako::Codec::Error}.
- Wire-representability predicate ({wire_representable?}) and
the symmetric host→guest +#run+ argument walk
({deep_wrap}) used by +Kobako::Invocation#encode+ to route
non-wire-representable leaves through the Sandbox's
+Kobako::HandleTable+
({docs/behavior.md B-34}[link:../../../docs/behavior.md]).
All helpers are pure — they only inspect inputs, never mutate them — except Utils.deep_wrap, whose only side effect is allocating new Handle ids into the supplied table.
Constant Summary collapse
- MSGPACK_INT_RANGE =
Inclusive Integer range the msgpack gem encodes without raising
RangeErrorat encode time — signed int 64 minimum through unsigned uint 64 maximum (docs/wire-codec.md § Type Mapping #3, thefixint/ int 8..64 / uint 8..64 union). Anchored as aRangeso primitive_wire_type? stays a single dispatch line. This is the codec’s wire-encode domain — not to be confused with the Handle id range, which lives onKobako::HandleasMIN_ID/MAX_ID(1..2^31 − 1) and represents a different concept entirely. (-(2**63)..((2**64) - 1))
Class Method Summary collapse
-
.assert_utf8!(string, label) ⇒ Object
Raise InvalidEncoding unless
string‘s bytes are valid under its current encoding tag. -
.container_wire_representable?(value) ⇒ Boolean
Predicate split out of Utils.wire_representable? for cyclomatic budget — the container branch.
-
.deep_wrap(value, handle_table) ⇒ Object
Deep-walk Array / Hash containers in
valueand replace every leaf that fails Utils.wire_representable? with aKobako::Handleallocated fromhandle_table(docs/behavior.md B-34). -
.primitive_wire_type?(value) ⇒ Boolean
Predicate split out of Utils.wire_representable? for cyclomatic budget — the closed-set non-container branch.
-
.wire_boundary ⇒ Object
Run
blockat the wire boundary: every wire Value Object (Handle / Fault / Request / Response / Panic) raisesArgumentErrorwhen an invariant is violated at construction, and the wire boundary surfaces those violations to callers as InvalidType so the public taxonomy stays Error and never leaksArgumentErrorfrom the Ruby standard library. -
.wire_representable?(value) ⇒ Boolean
Wire-type predicate (docs/wire-codec.md § Type Mapping).
Class Method Details
.assert_utf8!(string, label) ⇒ Object
Raise InvalidEncoding unless string‘s bytes are valid under its current encoding tag. label is the caller-supplied prefix for the error message (e.g. “str payload”, “Symbol payload”).
35 36 37 38 39 |
# File 'lib/kobako/codec/utils.rb', line 35 def assert_utf8!(string, label) return if string.valid_encoding? raise InvalidEncoding, "#{label} is not valid UTF-8" end |
.container_wire_representable?(value) ⇒ Boolean
Predicate split out of wire_representable? for cyclomatic budget — the container branch. Recurses into Array elements and Hash key+value pairs through the public wire_representable?. Not part of the public surface; reach for wire_representable? instead.
139 140 141 142 143 144 145 |
# File 'lib/kobako/codec/utils.rb', line 139 def container_wire_representable?(value) case value when ::Array then value.all? { |element| Utils.wire_representable?(element) } when ::Hash then value.all? { |key, val| Utils.wire_representable?(key) && Utils.wire_representable?(val) } else false end end |
.deep_wrap(value, handle_table) ⇒ Object
Deep-walk Array / Hash containers in value and replace every leaf that fails wire_representable? with a Kobako::Handle allocated from handle_table (docs/behavior.md B-34). The walk only descends through wire-representable container shapes (Array, Hash) one structural level at a time; a non- wire-representable leaf is wrapped as-is without inspecting its internal structure. An existing Kobako::Handle is wire- representable and passes through unchanged — auto-wrap never re-wraps a Handle.
value may be any Ruby value; handle_table must respond to #alloc(object) -> Kobako::Handle (a host-side Kobako::HandleTable). Returns a structurally equivalent value whose leaves are either wire-representable or Kobako::Handle tokens.
The block bodies spell Utils.deep_wrap explicitly rather than the unqualified deep_wrap because module_function makes the instance copy of these helpers private; an implicit receiver inside a block would resolve against the enclosing self (still Utils at definition time, but the qualified form keeps the dispatch readable when the recursive call sits inside a Proc captured from elsewhere).
113 114 115 116 117 118 119 120 |
# File 'lib/kobako/codec/utils.rb', line 113 def deep_wrap(value, handle_table) case value when ::Array then value.map { |element| Utils.deep_wrap(element, handle_table) } when ::Hash then value.transform_values { |val| Utils.deep_wrap(val, handle_table) } else wire_representable?(value) ? value : handle_table.alloc(value) end end |
.primitive_wire_type?(value) ⇒ Boolean
Predicate split out of wire_representable? for cyclomatic budget — the closed-set non-container branch. Returns true for the wire scalar leaves and an existing Handle. Not part of the public surface; reach for wire_representable? instead.
126 127 128 129 130 131 132 |
# File 'lib/kobako/codec/utils.rb', line 126 def primitive_wire_type?(value) case value when ::NilClass, ::TrueClass, ::FalseClass, ::Float, ::String, ::Symbol, Kobako::Handle then true when ::Integer then MSGPACK_INT_RANGE.cover?(value) else false end end |
.wire_boundary ⇒ Object
Run block at the wire boundary: every wire Value Object (Handle / Fault / Request / Response / Panic) raises ArgumentError when an invariant is violated at construction, and the wire boundary surfaces those violations to callers as InvalidType so the public taxonomy stays Error and never leaks ArgumentError from the Ruby standard library.
Wrap any block that constructs a wire Value Object from decoded bytes with this helper to keep the five decode sites uniform —Request / Response in Kobako::RPC, Panic map in Kobako::Outcome, and the Handle / Fault ext-type unpackers in Factory. Do not use it for general-purpose validation outside the wire boundary — host-layer ArgumentError values should propagate unchanged.
56 57 58 59 60 |
# File 'lib/kobako/codec/utils.rb', line 56 def wire_boundary yield rescue ::ArgumentError => e raise InvalidType, e. end |
.wire_representable?(value) ⇒ Boolean
Wire-type predicate (docs/wire-codec.md § Type Mapping). Returns true when value belongs to the closed 12-entry wire set — nil, TrueClass, FalseClass, Integer (in the i64..u64 value domain), Float, String, Symbol, Kobako::Handle, Array whose every element is itself wire-representable, or Hash whose every key and value are wire-representable. Integers outside the codec’s signed-64 / unsigned-64 union are rejected so the predicate agrees with the msgpack gem’s encode-time RangeError behaviour the codec already surfaces as Kobako::Codec::UnsupportedType.
85 86 87 |
# File 'lib/kobako/codec/utils.rb', line 85 def wire_representable?(value) primitive_wire_type?(value) || container_wire_representable?(value) end |