Module: Kobako::Codec::Utils
- Defined in:
- lib/kobako/codec/utils.rb
Overview
Codec helpers shared by the host-side encoders and decoders. Three concerns live here today:
- UTF-8 assertion at the codec 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.
- +ArgumentError+ translation at the codec boundary
({with_boundary}) so the public taxonomy stays
{Kobako::Codec::Error}.
- Representability predicate ({representable?}) and the symmetric
host→guest +#run+ argument walk ({deep_wrap}) used by
+Kobako::Transport::Run#encode+ to route non-representable leaves
through the Sandbox's +Kobako::Catalog::Handles+
({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_type? stays a single dispatch line. This is the codec’s 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_representable?(value) ⇒ Boolean
Predicate split out of Utils.representable? for cyclomatic budget — the container branch.
-
.deep_wrap(value, handler) ⇒ Object
Deep-walk Array / Hash containers in
valueand replace every leaf that fails Utils.representable? with aKobako::Handleallocated fromhandler(docs/behavior.md B-34). -
.primitive_type?(value) ⇒ Boolean
Predicate split out of Utils.representable? for cyclomatic budget — the closed-set non-container branch.
-
.representable?(value) ⇒ Boolean
Codec-type predicate (docs/wire-codec.md § Type Mapping).
-
.with_boundary ⇒ Object
Run
blockat the codec boundary: a value object raisesArgumentErrorwhen an invariant is violated at construction, and this helper surfaces that as InvalidType so the public taxonomy stays Error and never leaksArgumentErrorfrom the Ruby standard library.
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”).
34 35 36 37 38 |
# File 'lib/kobako/codec/utils.rb', line 34 def assert_utf8!(string, label) return if string.valid_encoding? raise InvalidEncoding, "#{label} is not valid UTF-8" end |
.container_representable?(value) ⇒ Boolean
Predicate split out of representable? for cyclomatic budget — the container branch. Recurses into Array elements and Hash key+value pairs through the public representable?. Not part of the public surface; reach for representable? instead.
136 137 138 139 140 141 142 |
# File 'lib/kobako/codec/utils.rb', line 136 def container_representable?(value) case value when ::Array then value.all? { |element| Utils.representable?(element) } when ::Hash then value.all? { |key, val| Utils.representable?(key) && Utils.representable?(val) } else false end end |
.deep_wrap(value, handler) ⇒ Object
Deep-walk Array / Hash containers in value and replace every leaf that fails representable? with a Kobako::Handle allocated from handler (docs/behavior.md B-34). The walk only descends through representable container shapes (Array, Hash) one structural level at a time; a non-representable leaf is wrapped as-is without inspecting its internal structure. An existing Kobako::Handle is representable and passes through unchanged — auto-wrap never re-wraps a Handle.
value may be any Ruby value; handler must respond to #alloc(object) -> Kobako::Handle (a host-side Kobako::Catalog::Handles). Returns a structurally equivalent value whose leaves are either 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).
110 111 112 113 114 115 116 117 |
# File 'lib/kobako/codec/utils.rb', line 110 def deep_wrap(value, handler) case value when ::Array then value.map { |element| Utils.deep_wrap(element, handler) } when ::Hash then value.transform_values { |val| Utils.deep_wrap(val, handler) } else representable?(value) ? value : handler.alloc(value) end end |
.primitive_type?(value) ⇒ Boolean
Predicate split out of representable? for cyclomatic budget — the closed-set non-container branch. Returns true for the scalar leaves and an existing Handle. Not part of the public surface; reach for representable? instead.
123 124 125 126 127 128 129 |
# File 'lib/kobako/codec/utils.rb', line 123 def primitive_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 |
.representable?(value) ⇒ Boolean
Codec-type predicate (docs/wire-codec.md § Type Mapping). Returns true when value belongs to the closed 12-entry codec type set — nil, TrueClass, FalseClass, Integer (in the i64..u64 value domain), Float, String, Symbol, Kobako::Handle, Array whose every element is itself representable, or Hash whose every key and value are 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.
83 84 85 |
# File 'lib/kobako/codec/utils.rb', line 83 def representable?(value) primitive_type?(value) || container_representable?(value) end |
.with_boundary ⇒ Object
Run block at the codec boundary: a value object raises ArgumentError when an invariant is violated at construction, and this helper surfaces that as InvalidType so the public taxonomy stays Error and never leaks ArgumentError from the Ruby standard library.
Most construction sites no longer reach for this directly: a value object built inside a Decoder.decode block has its ArgumentError mapped to InvalidType by the decoder’s own rescue. The lone remaining caller is Factory#unpack_handle, which builds Handle.restore from a raw 4-byte fixext payload without a Decoder.decode call. Do not use it for general-purpose validation outside the codec boundary — host-layer ArgumentError values should propagate unchanged.
54 55 56 57 58 |
# File 'lib/kobako/codec/utils.rb', line 54 def with_boundary yield rescue ::ArgumentError => e raise InvalidType, e. end |