kobako 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +71 -0
- data/Cargo.lock +117 -140
- data/README.md +100 -125
- data/ROADMAP.md +23 -22
- data/SECURITY.md +1 -1
- data/crates/kobako-runtime/CHANGELOG.md +31 -0
- data/crates/kobako-runtime/Cargo.toml +2 -2
- data/crates/kobako-runtime/README.md +4 -3
- data/crates/kobako-runtime/src/error.rs +8 -9
- data/crates/kobako-runtime/src/lib.rs +1 -1
- data/crates/kobako-runtime/src/profile.rs +1 -1
- data/crates/kobako-runtime/src/runtime.rs +31 -17
- data/crates/kobako-runtime/src/snapshot.rs +13 -10
- data/crates/kobako-runtime/src/yielder.rs +9 -6
- data/crates/kobako-transport/CHANGELOG.md +28 -0
- data/crates/kobako-transport/Cargo.toml +1 -1
- data/crates/kobako-transport/README.md +21 -12
- data/crates/kobako-transport/src/abi.rs +11 -14
- data/crates/kobako-transport/src/envelope/bytes.rs +18 -6
- data/crates/kobako-transport/src/envelope/compile_reply.rs +139 -0
- data/crates/kobako-transport/src/envelope/outcome.rs +17 -16
- data/crates/kobako-transport/src/envelope/preamble.rs +513 -0
- data/crates/kobako-transport/src/envelope/reply.rs +77 -53
- data/crates/kobako-transport/src/envelope/request.rs +295 -0
- data/crates/kobako-transport/src/envelope/run.rs +1 -2
- data/crates/kobako-transport/src/envelope/tag.rs +49 -0
- data/crates/kobako-transport/src/envelope/unsupported.rs +105 -0
- data/crates/kobako-transport/src/envelope.rs +19 -12
- data/crates/kobako-transport/src/lib.rs +0 -2
- data/crates/kobako-wasmtime/CHANGELOG.md +44 -0
- data/crates/kobako-wasmtime/Cargo.toml +7 -5
- data/crates/kobako-wasmtime/README.md +2 -2
- data/crates/kobako-wasmtime/src/abi.rs +5 -8
- data/crates/kobako-wasmtime/src/ambient.rs +2 -2
- data/crates/kobako-wasmtime/src/cache.rs +25 -59
- data/crates/kobako-wasmtime/src/capture.rs +4 -11
- data/crates/kobako-wasmtime/src/config.rs +11 -14
- data/crates/kobako-wasmtime/src/dispatch.rs +70 -80
- data/crates/kobako-wasmtime/src/driver.rs +133 -86
- data/crates/kobako-wasmtime/src/exports.rs +88 -34
- data/crates/kobako-wasmtime/src/guest_mem.rs +145 -138
- data/crates/kobako-wasmtime/src/instance_pre.rs +11 -22
- data/crates/kobako-wasmtime/src/invocation.rs +55 -372
- data/crates/kobako-wasmtime/src/io.rs +286 -0
- data/crates/kobako-wasmtime/src/lib.rs +3 -24
- data/crates/kobako-wasmtime/src/limiter.rs +253 -0
- data/crates/kobako-wasmtime/src/trap.rs +32 -45
- data/crates/kobako-wasmtime/tests/preamble_flags.rs +69 -0
- data/crates/kobako-wasmtime/tests/snippet_compile.rs +94 -0
- data/crates/kobako-wasmtime/tests/support/mod.rs +34 -0
- data/crates/kobako-wasmtime/tests/unsupported_call.rs +50 -0
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +2 -2
- data/ext/kobako/src/runtime/bridge.rs +38 -47
- data/ext/kobako/src/runtime/errors.rs +26 -32
- data/ext/kobako/src/runtime/gvl.rs +4 -12
- data/ext/kobako/src/runtime.rs +169 -212
- data/lib/kobako/capture.rb +1 -4
- data/lib/kobako/catalog/extensions.rb +21 -59
- data/lib/kobako/catalog/flags.rb +41 -0
- data/lib/kobako/catalog/handles.rb +7 -54
- data/lib/kobako/catalog/services.rb +7 -61
- data/lib/kobako/catalog/snippets.rb +42 -66
- data/lib/kobako/catalog.rb +2 -10
- data/lib/kobako/codec/decoder.rb +9 -28
- data/lib/kobako/codec/encoder.rb +3 -22
- data/lib/kobako/codec/error.rb +6 -27
- data/lib/kobako/codec/ext_types.rb +72 -94
- data/lib/kobako/codec/handle_walk.rb +65 -130
- data/lib/kobako/codec/nesting.rb +3 -8
- data/lib/kobako/codec/state.rb +4 -10
- data/lib/kobako/codec/utils.rb +6 -34
- data/lib/kobako/codec.rb +3 -22
- data/lib/kobako/constant_name.rb +8 -0
- data/lib/kobako/context.rb +51 -112
- data/lib/kobako/errors.rb +51 -127
- data/lib/kobako/execution.rb +16 -21
- data/lib/kobako/extension.rb +23 -40
- data/lib/kobako/handle.rb +7 -12
- data/lib/kobako/outcome.rb +51 -80
- data/lib/kobako/payload/arguments.rb +1 -16
- data/lib/kobako/payload.rb +4 -12
- data/lib/kobako/pool.rb +23 -53
- data/lib/kobako/runtime.rb +7 -21
- data/lib/kobako/sandbox.rb +96 -133
- data/lib/kobako/sandbox_options.rb +38 -84
- data/lib/kobako/snippet/binary.rb +1 -16
- data/lib/kobako/snippet/source.rb +1 -16
- data/lib/kobako/snippet.rb +1 -9
- data/lib/kobako/transport/call.rb +1 -14
- data/lib/kobako/transport/dispatcher.rb +112 -195
- data/lib/kobako/transport/error.rb +6 -20
- data/lib/kobako/transport/exposure.rb +5 -10
- data/lib/kobako/transport/reflection.rb +39 -50
- data/lib/kobako/transport/run.rb +17 -71
- data/lib/kobako/transport/yielder.rb +21 -73
- data/lib/kobako/transport.rb +3 -15
- data/lib/kobako/unresolved.rb +4 -11
- data/lib/kobako/usage.rb +2 -6
- data/lib/kobako/version.rb +1 -1
- data/sig/kobako/catalog/extensions.rbs +2 -2
- data/sig/kobako/catalog/flags.rbs +17 -0
- data/sig/kobako/catalog/services.rbs +0 -6
- data/sig/kobako/catalog/snippets.rbs +4 -4
- data/sig/kobako/codec/ext_types.rbs +10 -8
- data/sig/kobako/codec/handle_walk.rbs +9 -7
- data/sig/kobako/codec/utils.rbs +2 -2
- data/sig/kobako/codec.rbs +2 -2
- data/sig/kobako/constant_name.rbs +3 -0
- data/sig/kobako/context.rbs +2 -3
- data/sig/kobako/errors.rbs +6 -0
- data/sig/kobako/outcome.rbs +6 -8
- data/sig/kobako/runtime.rbs +12 -8
- data/sig/kobako/sandbox.rbs +4 -0
- data/sig/kobako/sandbox_options.rbs +2 -6
- data/sig/kobako/transport/dispatcher.rbs +14 -18
- data/sig/kobako/transport/reflection.rbs +5 -3
- data/sig/kobako/transport/run.rbs +1 -3
- data/sig/kobako/transport/yielder.rbs +3 -3
- data/sig/kobako/transport.rbs +7 -6
- metadata +16 -4
- data/crates/kobako-transport/src/envelope/invocation_frames.rs +0 -241
- data/crates/kobako-wasmtime/src/frames.rs +0 -273
- data/rust-toolchain.toml +0 -15
data/lib/kobako/transport/run.rb
CHANGED
|
@@ -1,44 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../constant_name"
|
|
3
4
|
require_relative "../handle"
|
|
4
5
|
require_relative "../codec"
|
|
5
6
|
require_relative "../payload"
|
|
6
7
|
|
|
7
8
|
module Kobako
|
|
8
|
-
# See lib/kobako/transport.rb for the umbrella module doc; this file
|
|
9
|
-
# owns +Run+, the host-side value object for one +#run+ request — the
|
|
10
|
-
# native side frames it into the envelope +__kobako_run+ consumes.
|
|
11
9
|
module Transport
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# A Run captures the host-layer concept of "a single +#run+
|
|
16
|
-
# call": the entrypoint constant name plus its positional and keyword
|
|
17
|
-
# arguments. Host pre-flight (entrypoint type / name pattern, forged
|
|
18
|
-
# Handle, kwargs-key type) is enforced at construction so the Value
|
|
19
|
-
# Object is the single source of truth — anything that passes
|
|
20
|
-
# +Run.new+ is safe to ship to the guest.
|
|
21
|
-
#
|
|
22
|
-
# +#payload+ takes the invocation's +Catalog::Handles+ and routes any
|
|
23
|
-
# non-wire-representable +args+ / +kwargs+ leaf through it as a
|
|
24
|
-
# +Kobako::Handle+ — the symmetric counterpart of the guest→host wrap
|
|
25
|
-
# path in the dispatcher. A +Kobako::Handle+ that arrives **already
|
|
26
|
-
# constructed** in the caller's +args+ / +kwargs+ is rejected at
|
|
27
|
-
# construction: legitimate Handles only enter Host App code through
|
|
28
|
-
# error fields, so a Handle reaching the call site is by definition
|
|
29
|
-
# smuggled in. +Runtime#run+ frames that payload with the entrypoint
|
|
30
|
-
# into the Run envelope the +__kobako_run+ command buffer carries.
|
|
31
|
-
#
|
|
32
|
-
# Built on the +class X < Data.define(...)+ subclass form (the
|
|
33
|
-
# Steep-friendly shape — see +.rubocop.yml+ for the rationale).
|
|
34
|
-
class Run < Data.define(:entrypoint, :args, :kwargs)
|
|
35
|
-
# Ruby constant-name pattern enforced on the +entrypoint+ Symbol.
|
|
36
|
-
# Parallel to
|
|
37
|
-
# +Kobako::Catalog::Snippets::NAME_PATTERN+; the two constants name the
|
|
38
|
-
# same regex but cover distinct surfaces (snippet identity vs.
|
|
39
|
-
# entrypoint resolution) so a future divergence stays local.
|
|
40
|
-
NAME_PATTERN = /\A[A-Z]\w*\z/
|
|
41
|
-
|
|
10
|
+
# A Handle already in the arguments is refused, since a caller never
|
|
11
|
+
# legitimately holds one.
|
|
12
|
+
class Run < Data.define(:entrypoint, :args, :kwargs) # :nodoc:
|
|
42
13
|
def initialize(entrypoint:, args: [], kwargs: {})
|
|
43
14
|
entrypoint = normalize_entrypoint(entrypoint)
|
|
44
15
|
validate_args!(args)
|
|
@@ -46,61 +17,42 @@ module Kobako
|
|
|
46
17
|
super
|
|
47
18
|
end
|
|
48
19
|
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
# invocation's table, sharing the same allocator the guest→host
|
|
55
|
-
# return path uses. A wrapped leaf rides as ext 0x01 in its
|
|
56
|
-
# original position (docs/wire/payload-msgpack.md § ext 0x01).
|
|
57
|
-
# The walk starts one level down, since +args+ and +kwargs+ ride
|
|
58
|
-
# inside the payload document the wire's nesting bound is counted
|
|
59
|
-
# from.
|
|
60
|
-
def payload(handler)
|
|
20
|
+
# A leaf with no wire form becomes a Capability Handle in the
|
|
21
|
+
# invocation's table. The walk starts one level down, since +args+ and
|
|
22
|
+
# +kwargs+ ride inside the payload document the wire's nesting bound
|
|
23
|
+
# is counted from.
|
|
24
|
+
def payload(handles)
|
|
61
25
|
Payload::Arguments.new(
|
|
62
|
-
args: Codec::HandleWalk.deep_wrap(args,
|
|
63
|
-
kwargs: Codec::HandleWalk.deep_wrap(kwargs,
|
|
26
|
+
args: Codec::HandleWalk.deep_wrap(args, handles, 1),
|
|
27
|
+
kwargs: Codec::HandleWalk.deep_wrap(kwargs, handles, 1)
|
|
64
28
|
).encode
|
|
65
29
|
end
|
|
66
30
|
|
|
67
31
|
private
|
|
68
32
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
# error before the run reaches the guest). After +.to_s+
|
|
72
|
-
# the value must match NAME_PATTERN (ArgumentError), rejecting
|
|
73
|
-
# +::+-segmented names and any non-constant form.
|
|
33
|
+
# A target of the wrong type raises TypeError, a Host App programming
|
|
34
|
+
# error caught before the run reaches the guest.
|
|
74
35
|
def normalize_entrypoint(target)
|
|
75
36
|
unless target.is_a?(Symbol) || target.is_a?(String)
|
|
76
37
|
raise TypeError, "entrypoint must be a Symbol or String, got #{target.class}"
|
|
77
38
|
end
|
|
78
39
|
|
|
79
40
|
target_str = target.to_s
|
|
80
|
-
unless
|
|
41
|
+
unless CONSTANT_NAME.match?(target_str)
|
|
81
42
|
raise ArgumentError,
|
|
82
|
-
"entrypoint must match #{
|
|
43
|
+
"entrypoint must match #{CONSTANT_NAME.inspect} (got #{target.inspect})"
|
|
83
44
|
end
|
|
84
45
|
|
|
85
46
|
target_str.to_sym
|
|
86
47
|
end
|
|
87
48
|
|
|
88
|
-
# +args+ must not contain a +Kobako::Handle+. The Handle
|
|
89
|
-
# allocator lives inside the Host Gem; legitimate paths surface
|
|
90
|
-
# Handle objects only through raised error fields, so a Handle
|
|
91
|
-
# reaching +args+ is a forged or smuggled token. Non-wire-
|
|
92
|
-
# representable arguments that are not Handles are handled by
|
|
93
|
-
# auto-wrap inside +#payload+ — the reject path is reserved
|
|
94
|
-
# for Handle objects specifically.
|
|
95
49
|
def validate_args!(args)
|
|
96
50
|
raise ArgumentError, "arguments must be an Array" unless args.is_a?(Array)
|
|
97
51
|
raise ArgumentError, forged_handle_message("arguments") if args.any?(Kobako::Handle)
|
|
98
52
|
end
|
|
99
53
|
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
# branch). Both checks live here so the Host App sees the
|
|
103
|
-
# host-side error message before any encode / decode boundary.
|
|
54
|
+
# Checked here so the Host App sees the host-side message before any
|
|
55
|
+
# encode boundary.
|
|
104
56
|
def validate_kwargs!(kwargs)
|
|
105
57
|
raise ArgumentError, "keyword arguments must be a Hash" unless kwargs.is_a?(Hash)
|
|
106
58
|
|
|
@@ -112,12 +64,6 @@ module Kobako
|
|
|
112
64
|
raise ArgumentError, forged_handle_message("keyword argument values") if kwargs.each_value.any?(Kobako::Handle)
|
|
113
65
|
end
|
|
114
66
|
|
|
115
|
-
# Single source of truth for the forged-Handle reject message so the
|
|
116
|
-
# args and kwargs branches stay phrased identically. Message stays in
|
|
117
|
-
# caller vocabulary: it names the affected slot and the reason
|
|
118
|
-
# without leaking internal SPEC identifiers or self-referential
|
|
119
|
-
# architecture terms — the error is raised BY kobako, so saying
|
|
120
|
-
# "allocated by the Host Gem" reads as third-person about self.
|
|
121
67
|
def forged_handle_message(slot)
|
|
122
68
|
"#{slot} must not contain a Kobako::Handle — " \
|
|
123
69
|
"Handles are created internally by the Sandbox and cannot be passed in"
|
|
@@ -4,51 +4,19 @@ require_relative "../codec"
|
|
|
4
4
|
require_relative "../errors"
|
|
5
5
|
|
|
6
6
|
module Kobako
|
|
7
|
-
# See lib/kobako/transport.rb for the umbrella module doc; this file
|
|
8
|
-
# owns the host-side object that materialises a guest-supplied block as
|
|
9
|
-
# a Ruby callable the Service method can yield into.
|
|
10
7
|
module Transport
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# that the Dispatcher hands to the Service method as +&block+. The
|
|
15
|
-
# Service method observes it as an ordinary Ruby Proc through
|
|
16
|
-
# #to_proc; +yield val+ / +block.call(val)+ invokes #yield, which
|
|
17
|
-
# serialises the positional args, re-enters the guest via the injected
|
|
18
|
-
# +yield_to_guest+ lambda, and reifies the Yield Reply into Ruby
|
|
19
|
-
# control flow:
|
|
20
|
-
#
|
|
21
|
-
# * ok — return the decoded value to +yield+'s caller
|
|
22
|
-
# * break — +throw break_tag, value+ so the Dispatcher's +catch+
|
|
23
|
-
# frame unwinds the Service method
|
|
24
|
-
# * error — raise a BlockError at the Service's yield site,
|
|
25
|
-
# carrying the guest's class on +#klass+
|
|
26
|
-
#
|
|
27
|
-
# The Dispatcher calls #invalidate! from its +ensure+ block once
|
|
28
|
-
# dispatch completes; any later call to a stashed Yielder then raises
|
|
29
|
-
# +LocalJumpError+ — the observable shape of an escaped Yielder.
|
|
30
|
-
class Yielder
|
|
31
|
-
# +yield_to_guest+ is the ext's per-dispatch
|
|
32
|
-
# +Kobako::Runtime::GuestYielder+, which #yield invokes to re-enter
|
|
33
|
-
# the guest: it takes the argument payload and answers the reply
|
|
34
|
-
# already split into +[arm, body, class]+. +break_tag+ is the
|
|
35
|
-
# +catch+ throw tag the Dispatcher matches against to unwind the
|
|
36
|
-
# Service on a break. +handler+ is the invocation's +Kobako::Catalog::Handles+,
|
|
37
|
-
# used to restore a Capability Handle in the block's ok value back to
|
|
38
|
-
# its host object before it reaches the Service +yield+ site.
|
|
39
|
-
def initialize(yield_to_guest, break_tag, handler)
|
|
40
|
-
@yield_to_guest = yield_to_guest
|
|
8
|
+
class Yielder # :nodoc:
|
|
9
|
+
def initialize(guest_yielder, break_tag, handles)
|
|
10
|
+
@guest_yielder = guest_yielder
|
|
41
11
|
@break_tag = break_tag
|
|
42
|
-
@
|
|
12
|
+
@handles = handles
|
|
43
13
|
@active = true
|
|
44
14
|
@raised = nil
|
|
45
15
|
end
|
|
46
16
|
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# raised its own has reported something else, and the guest must
|
|
51
|
-
# hear about that instead.
|
|
17
|
+
# Identity rather than class: a Service that rescued the block's
|
|
18
|
+
# failure and raised its own has reported something else, and the
|
|
19
|
+
# guest must hear about that instead.
|
|
52
20
|
#
|
|
53
21
|
# The class travels with the message because not every block failure
|
|
54
22
|
# is an exception the guest holds — a block value the guest refused
|
|
@@ -60,17 +28,15 @@ module Kobako
|
|
|
60
28
|
"#{raised.klass}: #{raised.message}"
|
|
61
29
|
end
|
|
62
30
|
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
# The break value unwinds past the Service back to the guest
|
|
68
|
-
# bound-constant call, so it passes through verbatim — a Handle stays a
|
|
69
|
-
# Handle and rides back on the same id rather than churning a new one.
|
|
31
|
+
# The ok value is consumed by the host Service, so a Capability Handle
|
|
32
|
+
# in it is restored. The break value unwinds back to the guest, so it
|
|
33
|
+
# passes through verbatim and rides back on the same id rather than
|
|
34
|
+
# churning a new one.
|
|
70
35
|
def yield(*args)
|
|
71
36
|
raise LocalJumpError, "guest block invoked after host dispatch frame returned" unless @active
|
|
72
37
|
|
|
73
|
-
arm, body, klass = @
|
|
38
|
+
arm, body, klass = @guest_yielder.call(encode_args(args))
|
|
39
|
+
raise UnsupportedError, "the Sandbox runtime does not support yielding to a block" if arm == :unsupported
|
|
74
40
|
raise remember(BlockError.new(body, klass: klass)) if arm == :error
|
|
75
41
|
|
|
76
42
|
value, carried_handle = decode_body(body)
|
|
@@ -79,26 +45,18 @@ module Kobako
|
|
|
79
45
|
restore(value, carried_handle)
|
|
80
46
|
end
|
|
81
47
|
|
|
82
|
-
# The Proc the Dispatcher passes as +&block+, binding #yield so a
|
|
83
|
-
# Service method's +yield+ / +block.call+ drives the round-trip.
|
|
84
48
|
def to_proc
|
|
85
49
|
method(:yield).to_proc
|
|
86
50
|
end
|
|
87
51
|
|
|
88
|
-
# Mark this Yielder dead. Called by the Dispatcher's +ensure+ block
|
|
89
|
-
# when the originating dispatch frame returns; any later #yield
|
|
90
|
-
# call then raises +LocalJumpError+.
|
|
91
52
|
def invalidate!
|
|
92
53
|
@active = false
|
|
93
54
|
end
|
|
94
55
|
|
|
95
56
|
private
|
|
96
57
|
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
# before the guest is re-entered, and are restated so the Service
|
|
100
|
-
# reads a refusal of its own argument rather than a codec class it
|
|
101
|
-
# never named.
|
|
58
|
+
# Restated so the Service reads a refusal of its own argument rather
|
|
59
|
+
# than a codec class it never named.
|
|
102
60
|
def encode_args(args)
|
|
103
61
|
Kobako::Codec::Nesting.assert_within_bound!(args)
|
|
104
62
|
Kobako::Codec::Encoder.encode(args)
|
|
@@ -106,33 +64,23 @@ module Kobako
|
|
|
106
64
|
raise YieldValueError, "Service yielded a value the block cannot receive: #{e.message}"
|
|
107
65
|
end
|
|
108
66
|
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
# as one statement. Only the newest is kept: a Service that rescued
|
|
112
|
-
# an earlier one and yielded again has already handled it.
|
|
67
|
+
# Only the newest is kept: a Service that rescued an earlier one and
|
|
68
|
+
# yielded again has already handled it.
|
|
113
69
|
def remember(error)
|
|
114
70
|
@raised = error
|
|
115
71
|
end
|
|
116
72
|
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
# nested dispatches whose own brackets would otherwise pollute the
|
|
121
|
-
# signal.
|
|
73
|
+
# The tracking bracket opens only around this decode: the guest
|
|
74
|
+
# re-entry may run nested dispatches whose own brackets would
|
|
75
|
+
# otherwise pollute the signal.
|
|
122
76
|
def decode_body(body)
|
|
123
77
|
Kobako::Codec.track_handles { Kobako::Codec::Decoder.decode(body) }
|
|
124
78
|
end
|
|
125
79
|
|
|
126
|
-
# Restore any Capability Handle in a block's ok value to its host
|
|
127
|
-
# object via the injected +Catalog::Handles+. Only the
|
|
128
|
-
# ok path calls this — host code consumes the ok value, whereas a
|
|
129
|
-
# break value returns to the guest and stays a Handle. A response
|
|
130
|
-
# whose decode carried no Handle resolves to itself, so the walk is
|
|
131
|
-
# skipped entirely.
|
|
132
80
|
def restore(value, carried_handle)
|
|
133
81
|
return value unless carried_handle
|
|
134
82
|
|
|
135
|
-
Kobako::Codec::HandleWalk.deep_restore(value, @
|
|
83
|
+
Kobako::Codec::HandleWalk.deep_restore(value, @handles)
|
|
136
84
|
end
|
|
137
85
|
end
|
|
138
86
|
end
|
data/lib/kobako/transport.rb
CHANGED
|
@@ -9,20 +9,8 @@ require_relative "transport/reflection"
|
|
|
9
9
|
require_relative "transport/dispatcher"
|
|
10
10
|
|
|
11
11
|
module Kobako
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
# +Dispatcher+ that answers a routed Call, the +Yielder+ that re-enters
|
|
16
|
-
# the guest for a block, the +Reflection+ floor a dispatch must clear, the
|
|
17
|
-
# +Exposure+ each reference authorizes a call against, and +Error+ for a
|
|
18
|
-
# wire violation the host detects. Each invocation's
|
|
19
|
-
# +Context+ composes them into the dispatch +Proc+ it passes +Runtime+ for
|
|
20
|
-
# that run.
|
|
21
|
-
#
|
|
22
|
-
# "RPC" was deliberately not chosen — it implies a cross-process boundary that
|
|
23
|
-
# kobako does not have, since host and guest share one OS thread and
|
|
24
|
-
# one wasm linear memory. See
|
|
25
|
-
# {SPEC.md Refinement → Internal Concepts}[link:../../SPEC.md].
|
|
26
|
-
module Transport
|
|
12
|
+
# The host side of the guest↔host exchange. Only Transport::Error is
|
|
13
|
+
# public; the rest serves one invocation's dispatch.
|
|
14
|
+
module Transport # :nodoc:
|
|
27
15
|
end
|
|
28
16
|
end
|
data/lib/kobako/unresolved.rb
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Kobako
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# is refused as an unresolved target and surfaces as +Kobako::ServiceError+
|
|
9
|
-
# when the guest leaves it unrescued — the same capability-failure channel
|
|
10
|
-
# as an idiom with no backend bound.
|
|
11
|
-
#
|
|
12
|
-
# A single shared value; only its identity distinguishes it, so the dispatch
|
|
13
|
-
# layer recognises it with +equal?+. A Host App may name it at a +bind+ site
|
|
14
|
-
# to declare a fillable explicitly.
|
|
4
|
+
# Stands for the object of a fillable Service, one declared with
|
|
5
|
+
# Sandbox#bind and no object. Context#bind supplies the object for an
|
|
6
|
+
# invocation; a call to one left unfilled fails as a ServiceError. Passing
|
|
7
|
+
# it to Sandbox#bind declares a fillable explicitly.
|
|
15
8
|
module Unresolved
|
|
16
9
|
end
|
|
17
10
|
end
|
data/lib/kobako/usage.rb
CHANGED
|
@@ -12,14 +12,10 @@ module Kobako
|
|
|
12
12
|
# cap, even when the cap was hit.
|
|
13
13
|
#
|
|
14
14
|
# Filled on every outcome, traps included, so a Host App that rescues a
|
|
15
|
-
# trap
|
|
15
|
+
# trap reads from the error's +execution+ how much of the budget the
|
|
16
16
|
# invocation used.
|
|
17
|
-
#
|
|
18
|
-
# Built on the +class X < Data.define(...)+ subclass form (the
|
|
19
|
-
# Steep-friendly shape — see +.rubocop.yml+ for the rationale).
|
|
20
17
|
class Usage < Data.define(:wall_time, :memory_peak)
|
|
21
|
-
#
|
|
22
|
-
# runs, so an Execution's +#usage+ is never +nil+.
|
|
18
|
+
# The usage of a run that has not started: no time, no memory.
|
|
23
19
|
EMPTY = new(wall_time: 0.0, memory_peak: 0)
|
|
24
20
|
end
|
|
25
21
|
end
|
data/lib/kobako/version.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Kobako
|
|
|
5
5
|
|
|
6
6
|
def install: (untyped extension, snippets: Kobako::Catalog::Snippets, services: Kobako::Catalog::Services) -> self
|
|
7
7
|
|
|
8
|
-
def
|
|
8
|
+
def assert_dependencies!: () -> self
|
|
9
9
|
|
|
10
10
|
def resolve: () -> Hash[String, untyped]
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ module Kobako
|
|
|
17
17
|
|
|
18
18
|
def validate!: (untyped extension) -> void
|
|
19
19
|
|
|
20
|
-
def
|
|
20
|
+
def unmet_dependency: () -> [untyped, untyped]?
|
|
21
21
|
|
|
22
22
|
def symbolize: (untyped name) -> untyped
|
|
23
23
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Catalog
|
|
3
|
+
class Flags
|
|
4
|
+
type tuple = [String, String, bool]
|
|
5
|
+
|
|
6
|
+
def initialize: () -> void
|
|
7
|
+
|
|
8
|
+
def entries: () -> Array[tuple]
|
|
9
|
+
|
|
10
|
+
def register: (Symbol | String name, String value, advisory: bool) -> nil
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def utf8!: (String text, String what) -> String
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Catalog
|
|
3
3
|
class Services
|
|
4
|
-
NAME_PATTERN: Regexp
|
|
5
|
-
|
|
6
4
|
def initialize: () -> void
|
|
7
5
|
|
|
8
6
|
def bind: (Symbol | String path, untyped object) -> self
|
|
@@ -13,10 +11,6 @@ module Kobako
|
|
|
13
11
|
|
|
14
12
|
def paths: () -> Array[String]
|
|
15
13
|
|
|
16
|
-
def seal!: () -> self
|
|
17
|
-
|
|
18
|
-
def sealed?: () -> bool
|
|
19
|
-
|
|
20
14
|
private
|
|
21
15
|
|
|
22
16
|
def validate_path!: (Symbol | String path) -> String
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Catalog
|
|
3
3
|
class Snippets
|
|
4
|
-
NAME_PATTERN: Regexp
|
|
5
|
-
|
|
6
4
|
type entry = Kobako::Snippet::Source | Kobako::Snippet::Binary
|
|
7
5
|
|
|
8
6
|
type tuple = [Symbol, String?, String]
|
|
9
7
|
|
|
10
8
|
def initialize: () -> void
|
|
11
9
|
|
|
12
|
-
def register: (?code: String?, ?name: (Symbol | String)?, ?binary: String?) ->
|
|
10
|
+
def register: (?code: String?, ?name: (Symbol | String)?, ?binary: String?) -> nil
|
|
13
11
|
|
|
14
12
|
def entries: () -> Array[tuple]
|
|
15
13
|
|
|
14
|
+
def compile: () { (Array[tuple] entries) -> Array[String]? } -> nil
|
|
15
|
+
|
|
16
16
|
private
|
|
17
17
|
|
|
18
|
-
def register_source!: (String? code, (Symbol | String)? name) ->
|
|
18
|
+
def register_source!: (String? code, (Symbol | String)? name) -> nil
|
|
19
19
|
|
|
20
20
|
def ensure_source_args!: (String? code, (Symbol | String)? name) -> [String, Symbol | String]
|
|
21
21
|
|
|
@@ -5,21 +5,23 @@ module Kobako
|
|
|
5
5
|
EXT_HANDLE: Integer
|
|
6
6
|
UNREPRESENTABLE_GUARD_ID: Integer
|
|
7
7
|
|
|
8
|
-
def self
|
|
8
|
+
def self.build_factory: () -> MessagePack::Factory
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
private
|
|
11
11
|
|
|
12
|
-
def self
|
|
12
|
+
def self.pack_symbol: (Symbol symbol) -> String
|
|
13
13
|
|
|
14
|
-
def self
|
|
14
|
+
def self.unpack_symbol: (String payload) -> Symbol
|
|
15
15
|
|
|
16
|
-
def self
|
|
16
|
+
def self.pack_handle: (Kobako::Handle handle) -> String
|
|
17
17
|
|
|
18
|
-
def self
|
|
18
|
+
def self.unpack_handle: (String payload, State state) -> Kobako::Handle
|
|
19
19
|
|
|
20
|
-
def self
|
|
20
|
+
def self.register_symbol: (MessagePack::Factory factory) -> void
|
|
21
21
|
|
|
22
|
-
def self
|
|
22
|
+
def self.register_handle: (MessagePack::Factory factory) -> void
|
|
23
|
+
|
|
24
|
+
def self.register_unrepresentable: (MessagePack::Factory factory) -> void
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
FACTORY: MessagePack::Factory
|
|
@@ -3,19 +3,21 @@ module Kobako
|
|
|
3
3
|
module HandleWalk
|
|
4
4
|
MSGPACK_INT_RANGE: Range[Integer]
|
|
5
5
|
|
|
6
|
-
def self
|
|
6
|
+
def self.representable?: (untyped value, ?Integer depth) -> bool
|
|
7
7
|
|
|
8
|
-
def self
|
|
8
|
+
def self.deep_wrap: (untyped value, Kobako::Codec::_HandleTable handles, ?Integer depth) -> untyped
|
|
9
9
|
|
|
10
|
-
def self
|
|
10
|
+
def self.deep_restore: (untyped value, Kobako::Codec::_HandleTable handles) -> untyped
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
private
|
|
13
13
|
|
|
14
|
-
def self
|
|
14
|
+
def self.guard_nesting!: (Integer depth) -> void
|
|
15
15
|
|
|
16
|
-
def self
|
|
16
|
+
def self.deep_wrap_hash: (Hash[untyped, untyped] hash, Kobako::Codec::_HandleTable handles, Integer depth) -> Hash[untyped, untyped]
|
|
17
17
|
|
|
18
|
-
def self
|
|
18
|
+
def self.primitive_type?: (untyped value) -> bool
|
|
19
|
+
|
|
20
|
+
def self.container_representable?: (untyped value, Integer depth) -> bool
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
end
|
data/sig/kobako/codec/utils.rbs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Codec
|
|
3
3
|
module Utils
|
|
4
|
-
def self
|
|
4
|
+
def self.assert_utf8!: (String string, String label) -> void
|
|
5
5
|
|
|
6
|
-
def self
|
|
6
|
+
def self.with_boundary: [T] () { () -> T } -> T
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
end
|
data/sig/kobako/codec.rbs
CHANGED
|
@@ -17,8 +17,8 @@ module Kobako
|
|
|
17
17
|
# The Handle allocator/resolver a wire walk works against: alloc
|
|
18
18
|
# registers a non-wire-representable object and returns its Handle,
|
|
19
19
|
# fetch resolves a wire Handle id back to the live object. The
|
|
20
|
-
#
|
|
21
|
-
# modelled structurally so the Codec and Transport tiers need no
|
|
20
|
+
# Kobako::Catalog::Handles each invocation mints is the production
|
|
21
|
+
# conformer; modelled structurally so the Codec and Transport tiers need no
|
|
22
22
|
# upward dependency on Catalog.
|
|
23
23
|
interface _HandleTable
|
|
24
24
|
def alloc: (untyped object) -> Kobako::Handle
|
data/sig/kobako/context.rbs
CHANGED
|
@@ -4,6 +4,7 @@ module Kobako
|
|
|
4
4
|
runtime: Kobako::Runtime,
|
|
5
5
|
services: Kobako::Catalog::Services,
|
|
6
6
|
snippets: Kobako::Catalog::Snippets,
|
|
7
|
+
flags: Kobako::Catalog::Flags,
|
|
7
8
|
extensions: Kobako::Catalog::Extensions
|
|
8
9
|
) -> void
|
|
9
10
|
|
|
@@ -23,9 +24,7 @@ module Kobako
|
|
|
23
24
|
|
|
24
25
|
def populate_observability!: (Kobako::Runtime::Snapshot snapshot) -> void
|
|
25
26
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
def trap_error_for: (Kobako::Runtime::Snapshot snapshot, Symbol verb) -> Kobako::TrapError
|
|
27
|
+
def with_verb: (Kobako::TrapError err, Symbol verb) -> Kobako::TrapError
|
|
29
28
|
|
|
30
29
|
def build_execution: (untyped value, failed: bool) -> Kobako::Execution
|
|
31
30
|
|
data/sig/kobako/errors.rbs
CHANGED
|
@@ -60,12 +60,18 @@ module Kobako
|
|
|
60
60
|
class YieldValueError < Error
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
class UnsupportedError < Error
|
|
64
|
+
end
|
|
65
|
+
|
|
63
66
|
class HandleExhaustedError < SandboxError
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
class BytecodeError < SandboxError
|
|
67
70
|
end
|
|
68
71
|
|
|
72
|
+
class UnsupportedFlagError < SandboxError
|
|
73
|
+
end
|
|
74
|
+
|
|
69
75
|
class UndefinedEntrypointError < SandboxError
|
|
70
76
|
attr_reader name: Symbol?
|
|
71
77
|
attr_reader available: Array[Symbol]
|
data/sig/kobako/outcome.rbs
CHANGED
|
@@ -6,18 +6,16 @@ module Kobako
|
|
|
6
6
|
|
|
7
7
|
type panic_fields = [String, String, String, Array[String], Array[String]]
|
|
8
8
|
|
|
9
|
-
def self
|
|
9
|
+
def self.reify: (String payload, panic_fields? panic, ?entrypoint: Symbol?) -> Kobako::Codec::wire_value
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
# `self?` method private, so the declarations stay visible to the checker.
|
|
13
|
-
def self?.panic_error: (panic_fields panic, Symbol? entrypoint) -> (SandboxError | ServiceError)
|
|
11
|
+
private
|
|
14
12
|
|
|
15
|
-
def self
|
|
13
|
+
def self.panic_error: (panic_fields panic, Symbol? entrypoint) -> (SandboxError | ServiceError)
|
|
16
14
|
|
|
17
|
-
def self
|
|
15
|
+
def self.error_class: (String origin, String klass) -> (singleton(SandboxError) | singleton(ServiceError))
|
|
18
16
|
|
|
19
|
-
def self
|
|
17
|
+
def self.decode_value: (String payload) -> Kobako::Codec::wire_value
|
|
20
18
|
|
|
21
|
-
def self
|
|
19
|
+
def self.wire_error: (String message, ?diagnostic: String?) -> Transport::Error
|
|
22
20
|
end
|
|
23
21
|
end
|