kobako 0.26.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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +1 -1
  3. data/CHANGELOG.md +103 -0
  4. data/Cargo.lock +117 -140
  5. data/README.md +156 -118
  6. data/ROADMAP.md +23 -22
  7. data/SECURITY.md +1 -1
  8. data/crates/kobako-runtime/CHANGELOG.md +38 -0
  9. data/crates/kobako-runtime/Cargo.toml +2 -2
  10. data/crates/kobako-runtime/README.md +10 -12
  11. data/crates/kobako-runtime/src/error.rs +8 -9
  12. data/crates/kobako-runtime/src/lib.rs +1 -1
  13. data/crates/kobako-runtime/src/profile.rs +1 -1
  14. data/crates/kobako-runtime/src/runtime.rs +31 -17
  15. data/crates/kobako-runtime/src/snapshot.rs +13 -10
  16. data/crates/kobako-runtime/src/yielder.rs +9 -6
  17. data/crates/kobako-transport/CHANGELOG.md +35 -0
  18. data/crates/kobako-transport/Cargo.toml +1 -1
  19. data/crates/kobako-transport/README.md +43 -27
  20. data/crates/kobako-transport/src/abi.rs +11 -14
  21. data/crates/kobako-transport/src/envelope/bytes.rs +18 -6
  22. data/crates/kobako-transport/src/envelope/compile_reply.rs +139 -0
  23. data/crates/kobako-transport/src/envelope/outcome.rs +17 -16
  24. data/crates/kobako-transport/src/envelope/preamble.rs +513 -0
  25. data/crates/kobako-transport/src/envelope/reply.rs +77 -53
  26. data/crates/kobako-transport/src/envelope/request.rs +295 -0
  27. data/crates/kobako-transport/src/envelope/run.rs +1 -2
  28. data/crates/kobako-transport/src/envelope/tag.rs +49 -0
  29. data/crates/kobako-transport/src/envelope/unsupported.rs +105 -0
  30. data/crates/kobako-transport/src/envelope.rs +19 -12
  31. data/crates/kobako-transport/src/lib.rs +0 -2
  32. data/crates/kobako-wasmtime/CHANGELOG.md +51 -0
  33. data/crates/kobako-wasmtime/Cargo.toml +7 -5
  34. data/crates/kobako-wasmtime/README.md +8 -10
  35. data/crates/kobako-wasmtime/src/abi.rs +5 -8
  36. data/crates/kobako-wasmtime/src/ambient.rs +2 -2
  37. data/crates/kobako-wasmtime/src/cache.rs +25 -59
  38. data/crates/kobako-wasmtime/src/capture.rs +4 -11
  39. data/crates/kobako-wasmtime/src/config.rs +11 -14
  40. data/crates/kobako-wasmtime/src/dispatch.rs +70 -80
  41. data/crates/kobako-wasmtime/src/driver.rs +133 -86
  42. data/crates/kobako-wasmtime/src/exports.rs +88 -34
  43. data/crates/kobako-wasmtime/src/guest_mem.rs +145 -138
  44. data/crates/kobako-wasmtime/src/instance_pre.rs +11 -22
  45. data/crates/kobako-wasmtime/src/invocation.rs +55 -372
  46. data/crates/kobako-wasmtime/src/io.rs +286 -0
  47. data/crates/kobako-wasmtime/src/lib.rs +3 -24
  48. data/crates/kobako-wasmtime/src/limiter.rs +253 -0
  49. data/crates/kobako-wasmtime/src/trap.rs +32 -45
  50. data/crates/kobako-wasmtime/tests/preamble_flags.rs +69 -0
  51. data/crates/kobako-wasmtime/tests/snippet_compile.rs +94 -0
  52. data/crates/kobako-wasmtime/tests/support/mod.rs +34 -0
  53. data/crates/kobako-wasmtime/tests/unsupported_call.rs +50 -0
  54. data/data/kobako.wasm +0 -0
  55. data/ext/kobako/Cargo.toml +2 -2
  56. data/ext/kobako/src/runtime/bridge.rs +38 -47
  57. data/ext/kobako/src/runtime/errors.rs +26 -32
  58. data/ext/kobako/src/runtime/gvl.rs +4 -12
  59. data/ext/kobako/src/runtime.rs +169 -212
  60. data/lib/kobako/capture.rb +1 -4
  61. data/lib/kobako/catalog/extensions.rb +21 -59
  62. data/lib/kobako/catalog/flags.rb +41 -0
  63. data/lib/kobako/catalog/handles.rb +7 -54
  64. data/lib/kobako/catalog/services.rb +7 -61
  65. data/lib/kobako/catalog/snippets.rb +42 -66
  66. data/lib/kobako/catalog.rb +2 -10
  67. data/lib/kobako/codec/decoder.rb +9 -28
  68. data/lib/kobako/codec/encoder.rb +3 -22
  69. data/lib/kobako/codec/error.rb +6 -27
  70. data/lib/kobako/codec/ext_types.rb +72 -94
  71. data/lib/kobako/codec/handle_walk.rb +65 -130
  72. data/lib/kobako/codec/nesting.rb +3 -8
  73. data/lib/kobako/codec/state.rb +4 -10
  74. data/lib/kobako/codec/utils.rb +6 -34
  75. data/lib/kobako/codec.rb +3 -22
  76. data/lib/kobako/constant_name.rb +8 -0
  77. data/lib/kobako/context.rb +51 -112
  78. data/lib/kobako/errors.rb +51 -127
  79. data/lib/kobako/execution.rb +16 -21
  80. data/lib/kobako/extension.rb +23 -40
  81. data/lib/kobako/handle.rb +7 -12
  82. data/lib/kobako/outcome.rb +51 -80
  83. data/lib/kobako/payload/arguments.rb +1 -16
  84. data/lib/kobako/payload.rb +4 -12
  85. data/lib/kobako/pool.rb +23 -53
  86. data/lib/kobako/runtime.rb +7 -21
  87. data/lib/kobako/sandbox.rb +96 -133
  88. data/lib/kobako/sandbox_options.rb +38 -84
  89. data/lib/kobako/snippet/binary.rb +1 -16
  90. data/lib/kobako/snippet/source.rb +1 -16
  91. data/lib/kobako/snippet.rb +1 -9
  92. data/lib/kobako/transport/call.rb +1 -14
  93. data/lib/kobako/transport/dispatcher.rb +112 -195
  94. data/lib/kobako/transport/error.rb +6 -20
  95. data/lib/kobako/transport/exposure.rb +5 -10
  96. data/lib/kobako/transport/reflection.rb +39 -50
  97. data/lib/kobako/transport/run.rb +17 -71
  98. data/lib/kobako/transport/yielder.rb +21 -73
  99. data/lib/kobako/transport.rb +3 -15
  100. data/lib/kobako/unresolved.rb +4 -11
  101. data/lib/kobako/usage.rb +2 -6
  102. data/lib/kobako/version.rb +1 -1
  103. data/sig/kobako/catalog/extensions.rbs +2 -2
  104. data/sig/kobako/catalog/flags.rbs +17 -0
  105. data/sig/kobako/catalog/services.rbs +0 -6
  106. data/sig/kobako/catalog/snippets.rbs +4 -4
  107. data/sig/kobako/codec/ext_types.rbs +10 -8
  108. data/sig/kobako/codec/handle_walk.rbs +9 -7
  109. data/sig/kobako/codec/utils.rbs +2 -2
  110. data/sig/kobako/codec.rbs +2 -2
  111. data/sig/kobako/constant_name.rbs +3 -0
  112. data/sig/kobako/context.rbs +2 -3
  113. data/sig/kobako/errors.rbs +6 -0
  114. data/sig/kobako/outcome.rbs +6 -8
  115. data/sig/kobako/runtime.rbs +12 -8
  116. data/sig/kobako/sandbox.rbs +4 -0
  117. data/sig/kobako/sandbox_options.rbs +2 -6
  118. data/sig/kobako/transport/dispatcher.rbs +14 -18
  119. data/sig/kobako/transport/reflection.rbs +5 -3
  120. data/sig/kobako/transport/run.rbs +1 -3
  121. data/sig/kobako/transport/yielder.rbs +3 -3
  122. data/sig/kobako/transport.rbs +7 -6
  123. metadata +16 -4
  124. data/crates/kobako-transport/src/envelope/invocation_frames.rs +0 -241
  125. data/crates/kobako-wasmtime/src/frames.rs +0 -273
  126. data/rust-toolchain.toml +0 -11
@@ -15,20 +15,28 @@ module Kobako
15
15
  def eval: (
16
16
  Kobako::Transport::dispatch_proc dispatch,
17
17
  Array[String] paths,
18
- String source,
19
- Array[Kobako::Catalog::Snippets::tuple] snippets
18
+ Array[Kobako::Catalog::Snippets::tuple] snippets,
19
+ Array[Kobako::Catalog::Flags::tuple] flags,
20
+ String source
20
21
  ) -> Kobako::Runtime::Snapshot
21
22
 
22
23
  def run: (
23
24
  Kobako::Transport::dispatch_proc dispatch,
24
25
  Array[String] paths,
25
26
  Array[Kobako::Catalog::Snippets::tuple] snippets,
27
+ Array[Kobako::Catalog::Flags::tuple] flags,
26
28
  String entrypoint,
27
29
  String payload
28
30
  ) -> Kobako::Runtime::Snapshot
29
31
 
30
32
  def profile: () -> Symbol
31
33
 
34
+ def compile: (
35
+ Array[String] paths,
36
+ Array[Kobako::Catalog::Snippets::tuple] snippets,
37
+ Array[Kobako::Catalog::Flags::tuple] flags
38
+ ) -> Array[String]?
39
+
32
40
  # Frame-scoped guest re-entry handle the ext hands the dispatch Proc as
33
41
  # its last argument — the production conformer of
34
42
  # +Kobako::Transport::_GuestYielder+, answering the Yield Reply already
@@ -39,13 +47,9 @@ module Kobako
39
47
 
40
48
  # One invocation's result — the whole Snapshot the driver produced.
41
49
  class Snapshot
42
- def outcome: () -> [Symbol, String, Kobako::Outcome::panic_fields?]
43
-
44
- def trapped?: () -> bool
45
-
46
- def trap_kind: () -> Symbol?
50
+ def outcome: () -> [String, Kobako::Outcome::panic_fields?]
47
51
 
48
- def trap_message: () -> String?
52
+ def trap_error: () -> Kobako::TrapError?
49
53
 
50
54
  def wall_time: () -> Float
51
55
 
@@ -27,6 +27,8 @@ module Kobako
27
27
  def preload: (code: String, name: Symbol | String) -> Kobako::Sandbox
28
28
  | (binary: String) -> Kobako::Sandbox
29
29
 
30
+ def flag: (Symbol | String name, ?String value, ?advisory: bool) -> Kobako::Sandbox
31
+
30
32
  def run: (Symbol | String target, *untyped args, **untyped kwargs) ?{ (Kobako::Context) -> void } -> Kobako::Execution
31
33
 
32
34
  def eval: (String code) ?{ (Kobako::Context) -> void } -> Kobako::Execution
@@ -37,6 +39,8 @@ module Kobako
37
39
 
38
40
  def new_invocation: () -> Kobako::Context
39
41
 
42
+ def refuse_once_invoked!: (String verb) -> void
43
+
40
44
  def begin_invocation!: () -> void
41
45
  end
42
46
  end
@@ -39,12 +39,8 @@ module Kobako
39
39
 
40
40
  def normalize_timeout: ((Float | Integer)? timeout) -> Float?
41
41
 
42
- def normalize_memory_limit: (Integer? memory_limit) -> Integer?
42
+ def normalize_byte_limit: (Integer? limit, String name) -> Integer?
43
43
 
44
- def normalize_output_limit: (Integer? limit, String name) -> Integer?
45
-
46
- def normalize_profile: (untyped profile) -> Symbol
47
-
48
- def normalize_gvl: (untyped gvl) -> Symbol
44
+ def normalize_choice: (untyped value, Array[Symbol] choices, String name) -> Symbol
49
45
  end
50
46
  end
@@ -11,37 +11,33 @@ module Kobako
11
11
 
12
12
  OWN_FAULTS: Hash[singleton(StandardError), String]
13
13
 
14
+ def self.dispatch: (Kobako::Transport::Call call, Kobako::Transport::_ServiceResolver resolver, Kobako::Transport::_HandleTable handles, Kobako::Transport::_GuestYielder guest_yielder) -> [bool, String, String?]
14
15
 
16
+ private
15
17
 
18
+ def self.run: (Kobako::Transport::Call call, Kobako::Transport::_ServiceResolver resolver, Kobako::Transport::_HandleTable handles, Kobako::Transport::Yielder? yielder) -> untyped
16
19
 
17
- def self?.dispatch: (Kobako::Transport::Call call, Kobako::Transport::_ServiceRegistry resolver, Kobako::Transport::_HandleTable handler, Kobako::Transport::_GuestYielder yield_to_guest) -> [bool, String, String?]
20
+ def self.decode_arguments: (String payload) -> [Kobako::Payload::Arguments, bool]
18
21
 
19
- def self?.run: (Kobako::Transport::Call call, Kobako::Transport::_ServiceRegistry resolver, Kobako::Transport::_HandleTable handler, Kobako::Transport::Yielder? yielder) -> untyped
22
+ def self.resolve_call_args: (Kobako::Payload::Arguments arguments, Kobako::Codec::_HandleTable handles, bool carried_handle) -> [Array[untyped], Hash[Symbol, untyped]]
20
23
 
21
- def self?.resolve_call_args: (Kobako::Payload::Arguments arguments, Kobako::Codec::_HandleTable handler, bool carried_handle) -> [Array[untyped], Hash[Symbol, untyped]]
24
+ def self.caught_fault: (StandardError error, Kobako::Transport::Yielder? yielder) -> [String, String]
22
25
 
23
- def self?.decode_arguments: (String payload) -> [Kobako::Payload::Arguments, bool]
26
+ def self.invoke: (Kobako::Transport::Exposure exposure, String method, Array[untyped] args, Hash[Symbol, untyped] kwargs, Kobako::Transport::Yielder? yielder) -> untyped
24
27
 
25
- def self?.caught_fault: (StandardError error, Kobako::Transport::Yielder? yielder) -> [String, String]
28
+ def self.reject_unreachable!: (Kobako::Transport::Exposure exposure, Symbol name) -> void
26
29
 
27
- def self?.invoke: (Kobako::Transport::Exposure exposure, String method, Array[untyped] args, Hash[Symbol, untyped] kwargs, ?Kobako::Transport::Yielder? yielder) -> untyped
30
+ def self.resolve_arg: (untyped value, Kobako::Codec::_HandleTable handles) -> untyped
28
31
 
29
- def self?.reject_unreachable!: (Kobako::Transport::Exposure exposure, Symbol name) -> void
32
+ def self.resolve_target: (String | Integer target, Kobako::Transport::_ServiceResolver resolver, Kobako::Transport::_HandleTable handles) -> Kobako::Transport::Exposure
30
33
 
34
+ def self.resolve_path: (String path, Kobako::Transport::_ServiceResolver resolver) -> Kobako::Transport::Exposure
31
35
 
32
- def self?.resolve_arg: (untyped value, Kobako::Codec::_HandleTable handler) -> untyped
36
+ def self.resolve_handle: (Integer id, Kobako::Transport::_HandleTable handles) -> Kobako::Transport::Exposure
33
37
 
34
- def self?.resolve_target: (String | Integer target, Kobako::Transport::_ServiceRegistry resolver, Kobako::Transport::_HandleTable handler) -> Kobako::Transport::Exposure
38
+ def self.encode_ok: (untyped value, Kobako::Codec::_HandleTable handles) -> String
35
39
 
36
- def self?.resolve_path: (String path, Kobako::Transport::_ServiceRegistry resolver) -> Kobako::Transport::Exposure
37
-
38
- def self?.resolve_handle: (Integer id, Kobako::Transport::_HandleTable handler) -> Kobako::Transport::Exposure
39
-
40
- def self?.encode_ok: (untyped value, Kobako::Codec::_HandleTable handler) -> String
41
-
42
- def self?.wrap_as_handle: (untyped value, Kobako::Codec::_HandleTable handler) -> Kobako::Handle
43
-
44
- def self?.fault: (String type, String message) -> [String, String]
40
+ def self.fault: (String type, String message) -> [String, String]
45
41
  end
46
42
  end
47
43
  end
@@ -5,11 +5,13 @@ module Kobako
5
5
  GADGET_OWNERS: Array[Module]
6
6
  CALLABLE_ALLOW: Array[Symbol]
7
7
 
8
- def self?.refusal: (Kobako::Transport::Exposure exposure, Symbol name) -> String?
8
+ def self.refusal: (Kobako::Transport::Exposure exposure, Symbol name) -> String?
9
9
 
10
- def self?.ambient_refusal: (untyped target, Symbol name) -> String?
10
+ private
11
11
 
12
- def self?.ambient_owner?: (Module owner, untyped target) -> bool
12
+ def self.ambient_refusal: (untyped target, Symbol name) -> String?
13
+
14
+ def self.ambient_owner?: (Module owner, untyped target) -> bool
13
15
  end
14
16
  end
15
17
  end
@@ -1,8 +1,6 @@
1
1
  module Kobako
2
2
  module Transport
3
3
  class Run < Data
4
- NAME_PATTERN: Regexp
5
-
6
4
  attr_reader entrypoint: Symbol
7
5
  attr_reader args: Array[Kobako::Codec::wire_value]
8
6
  attr_reader kwargs: Hash[Symbol, Kobako::Codec::wire_value]
@@ -11,7 +9,7 @@ module Kobako
11
9
 
12
10
  def initialize: (entrypoint: Symbol | String, ?args: Array[untyped], ?kwargs: Hash[untyped, untyped]) -> void
13
11
 
14
- def payload: (Kobako::Codec::_HandleTable handler) -> String
12
+ def payload: (Kobako::Codec::_HandleTable handles) -> String
15
13
 
16
14
  private
17
15
 
@@ -1,13 +1,13 @@
1
1
  module Kobako
2
2
  module Transport
3
3
  class Yielder
4
- @yield_to_guest: Kobako::Transport::_GuestYielder
4
+ @guest_yielder: Kobako::Transport::_GuestYielder
5
5
  @break_tag: Symbol
6
- @handler: Kobako::Codec::_HandleTable
6
+ @handles: Kobako::Codec::_HandleTable
7
7
  @active: bool
8
8
  @raised: Kobako::BlockError?
9
9
 
10
- def initialize: (Kobako::Transport::_GuestYielder yield_to_guest, Symbol break_tag, Kobako::Codec::_HandleTable handler) -> void
10
+ def initialize: (Kobako::Transport::_GuestYielder guest_yielder, Symbol break_tag, Kobako::Codec::_HandleTable handles) -> void
11
11
 
12
12
  def fault_text: (Exception error) -> String?
13
13
 
@@ -1,7 +1,8 @@
1
1
  module Kobako
2
2
  module Transport
3
3
  # The guest re-entry callable a dispatch hands to a Yielder: invoked
4
- # with the encoded yield args, it returns the encoded Yield Reply.
4
+ # with the encoded yield args, it returns the decoded Yield Reply as an
5
+ # +[arm, body, klass]+ triple.
5
6
  # The ext's Kobako::Runtime::GuestYielder is the production conformer;
6
7
  # modelled structurally so the Transport layer needs no upward
7
8
  # dependency on Runtime.
@@ -15,11 +16,11 @@ module Kobako
15
16
  # consumer (Runtime) cannot declare it differently.
16
17
  type dispatch_proc = ^(String | Integer, String, bool, String, _GuestYielder) -> [bool, String, String?]
17
18
 
18
- # The Service registry a dispatch resolves constant-path targets
19
- # against. The Sandbox's Kobako::Catalog::Services is the
20
- # production conformer; modelled structurally so the Transport
21
- # layer needs no upward dependency on Catalog.
22
- interface _ServiceRegistry
19
+ # What a dispatch resolves constant-path targets against. The
20
+ # invocation's Kobako::Context is the production conformer, so its
21
+ # overrides answer before the Sandbox's bindings; modelled structurally
22
+ # so the Transport layer needs no upward dependency on Orchestration.
23
+ interface _ServiceResolver
23
24
  def lookup: (String target) -> Exposure
24
25
  end
25
26
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kobako
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.0
4
+ version: 0.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aotokitsuruya
@@ -72,12 +72,16 @@ files:
72
72
  - crates/kobako-transport/src/envelope.rs
73
73
  - crates/kobako-transport/src/envelope/bytes.rs
74
74
  - crates/kobako-transport/src/envelope/call.rs
75
+ - crates/kobako-transport/src/envelope/compile_reply.rs
75
76
  - crates/kobako-transport/src/envelope/error_record.rs
76
77
  - crates/kobako-transport/src/envelope/fault.rs
77
- - crates/kobako-transport/src/envelope/invocation_frames.rs
78
78
  - crates/kobako-transport/src/envelope/outcome.rs
79
+ - crates/kobako-transport/src/envelope/preamble.rs
79
80
  - crates/kobako-transport/src/envelope/reply.rs
81
+ - crates/kobako-transport/src/envelope/request.rs
80
82
  - crates/kobako-transport/src/envelope/run.rs
83
+ - crates/kobako-transport/src/envelope/tag.rs
84
+ - crates/kobako-transport/src/envelope/unsupported.rs
81
85
  - crates/kobako-transport/src/lib.rs
82
86
  - crates/kobako-wasmtime/CHANGELOG.md
83
87
  - crates/kobako-wasmtime/Cargo.toml
@@ -90,12 +94,17 @@ files:
90
94
  - crates/kobako-wasmtime/src/dispatch.rs
91
95
  - crates/kobako-wasmtime/src/driver.rs
92
96
  - crates/kobako-wasmtime/src/exports.rs
93
- - crates/kobako-wasmtime/src/frames.rs
94
97
  - crates/kobako-wasmtime/src/guest_mem.rs
95
98
  - crates/kobako-wasmtime/src/instance_pre.rs
96
99
  - crates/kobako-wasmtime/src/invocation.rs
100
+ - crates/kobako-wasmtime/src/io.rs
97
101
  - crates/kobako-wasmtime/src/lib.rs
102
+ - crates/kobako-wasmtime/src/limiter.rs
98
103
  - crates/kobako-wasmtime/src/trap.rs
104
+ - crates/kobako-wasmtime/tests/preamble_flags.rs
105
+ - crates/kobako-wasmtime/tests/snippet_compile.rs
106
+ - crates/kobako-wasmtime/tests/support/mod.rs
107
+ - crates/kobako-wasmtime/tests/unsupported_call.rs
99
108
  - data/kobako.wasm
100
109
  - ext/kobako/Cargo.toml
101
110
  - ext/kobako/extconf.rb
@@ -108,6 +117,7 @@ files:
108
117
  - lib/kobako/capture.rb
109
118
  - lib/kobako/catalog.rb
110
119
  - lib/kobako/catalog/extensions.rb
120
+ - lib/kobako/catalog/flags.rb
111
121
  - lib/kobako/catalog/handles.rb
112
122
  - lib/kobako/catalog/services.rb
113
123
  - lib/kobako/catalog/snippets.rb
@@ -120,6 +130,7 @@ files:
120
130
  - lib/kobako/codec/nesting.rb
121
131
  - lib/kobako/codec/state.rb
122
132
  - lib/kobako/codec/utils.rb
133
+ - lib/kobako/constant_name.rb
123
134
  - lib/kobako/context.rb
124
135
  - lib/kobako/errors.rb
125
136
  - lib/kobako/execution.rb
@@ -147,11 +158,11 @@ files:
147
158
  - lib/kobako/usage.rb
148
159
  - lib/kobako/version.rb
149
160
  - release-please-config.json
150
- - rust-toolchain.toml
151
161
  - sig/kobako.rbs
152
162
  - sig/kobako/capture.rbs
153
163
  - sig/kobako/catalog.rbs
154
164
  - sig/kobako/catalog/extensions.rbs
165
+ - sig/kobako/catalog/flags.rbs
155
166
  - sig/kobako/catalog/handles.rbs
156
167
  - sig/kobako/catalog/services.rbs
157
168
  - sig/kobako/catalog/snippets.rbs
@@ -164,6 +175,7 @@ files:
164
175
  - sig/kobako/codec/nesting.rbs
165
176
  - sig/kobako/codec/state.rbs
166
177
  - sig/kobako/codec/utils.rbs
178
+ - sig/kobako/constant_name.rbs
167
179
  - sig/kobako/context.rbs
168
180
  - sig/kobako/errors.rbs
169
181
  - sig/kobako/execution.rbs
@@ -1,241 +0,0 @@
1
- //! The invocation frames — Frame 1's bound constant paths and Frame 3's
2
- //! preloaded snippets, the two both entry points read before running
3
- //! anything. The numbering skips Frame 2 because the `#eval` user source
4
- //! is raw UTF-8 with no envelope of its own.
5
- //!
6
- //! Both are mandatory-presence even when empty, so a reader never has to
7
- //! tell an absent frame from an empty one, and each frame's length reaches
8
- //! the guest from the channel's own prefix rather than from the envelope.
9
-
10
- use super::bytes::{Reader, Writer};
11
- use super::DecodeError;
12
-
13
- const SNIPPET_SOURCE: u8 = 0;
14
- const SNIPPET_BYTECODE: u8 = 1;
15
-
16
- /// Frame 1 — the bound constant paths the guest installs proxies from.
17
- /// Always present; an empty list means no Service is bound.
18
- #[derive(Debug, Clone, PartialEq, Eq, Default)]
19
- pub struct Bindings {
20
- pub paths: Vec<String>,
21
- }
22
-
23
- impl Bindings {
24
- pub fn decode(bytes: &[u8]) -> Result<Self, DecodeError> {
25
- let mut reader = Reader::new(bytes);
26
- let paths = reader.text_list()?;
27
- reader.finish()?;
28
- Ok(Bindings { paths })
29
- }
30
-
31
- pub fn encode(&self) -> Vec<u8> {
32
- let mut writer = Writer::new();
33
- writer.list(&self.paths);
34
- writer.into_bytes()
35
- }
36
- }
37
-
38
- /// One preloaded snippet. Source carries the filename the guest compiles
39
- /// under; bytecode does not, because its filename — when it has one — lives
40
- /// in the bytecode's own debug section.
41
- #[derive(Debug, Clone, PartialEq, Eq)]
42
- pub enum Snippet {
43
- Source { name: String, body: String },
44
- Bytecode { body: Vec<u8> },
45
- }
46
-
47
- /// Frame 3 — the preloaded snippets, in insertion order. Always present;
48
- /// a zero count means nothing was preloaded.
49
- #[derive(Debug, Clone, PartialEq, Eq, Default)]
50
- pub struct Snippets {
51
- pub entries: Vec<Snippet>,
52
- }
53
-
54
- impl Snippets {
55
- pub fn decode(bytes: &[u8]) -> Result<Self, DecodeError> {
56
- let mut reader = Reader::new(bytes);
57
- let count = reader.u32()? as usize;
58
- // Each entry costs at least a kind byte, so a count past the bytes
59
- // left cannot be satisfied; refusing it bounds the allocation.
60
- if count > reader.remaining().len() {
61
- return Err(DecodeError::new(
62
- "Frame 3 declares more entries than the frame holds",
63
- ));
64
- }
65
- let mut entries = Vec::with_capacity(count);
66
- for _ in 0..count {
67
- entries.push(match reader.u8()? {
68
- SNIPPET_SOURCE => Snippet::Source {
69
- name: reader.text()?.to_owned(),
70
- body: reader.text()?.to_owned(),
71
- },
72
- SNIPPET_BYTECODE => Snippet::Bytecode {
73
- body: reader.bytes()?.to_vec(),
74
- },
75
- _ => return Err(DecodeError::new("Frame 3 snippet kind must be 0 or 1")),
76
- });
77
- }
78
- reader.finish()?;
79
- Ok(Snippets { entries })
80
- }
81
-
82
- pub fn encode(&self) -> Vec<u8> {
83
- let mut writer = Writer::new();
84
- writer.u32(self.entries.len() as u32);
85
- for entry in &self.entries {
86
- match entry {
87
- Snippet::Source { name, body } => {
88
- writer
89
- .u8(SNIPPET_SOURCE)
90
- .bytes(name.as_bytes())
91
- .bytes(body.as_bytes());
92
- }
93
- Snippet::Bytecode { body } => {
94
- writer.u8(SNIPPET_BYTECODE).bytes(body);
95
- }
96
- }
97
- }
98
- writer.into_bytes()
99
- }
100
- }
101
-
102
- #[cfg(test)]
103
- mod tests {
104
- use super::*;
105
-
106
- // @behavior WE-050
107
- #[test]
108
- fn empty_bindings_round_trip() {
109
- let encoded = Bindings::default().encode();
110
- assert_eq!(
111
- Bindings::decode(&encoded),
112
- Ok(Bindings::default()),
113
- "a Sandbox with no bindings must send a present, empty Frame 1"
114
- );
115
- }
116
-
117
- // @behavior WE-051
118
- #[test]
119
- fn bindings_round_trip_every_path() {
120
- let bindings = Bindings {
121
- paths: vec!["MyService::KV".into(), "File".into()],
122
- };
123
- let encoded = bindings.encode();
124
- assert_eq!(
125
- Bindings::decode(&encoded),
126
- Ok(bindings),
127
- "Frame 1 must carry every bound path in order"
128
- );
129
- }
130
-
131
- // @behavior WE-052
132
- #[test]
133
- fn snippets_round_trip_both_kinds_in_order() {
134
- let snippets = Snippets {
135
- entries: vec![
136
- Snippet::Source {
137
- name: "Helper".into(),
138
- body: "def helper; end".into(),
139
- },
140
- Snippet::Bytecode {
141
- body: vec![0x52, 0x49, 0x54, 0x45],
142
- },
143
- ],
144
- };
145
- let encoded = snippets.encode();
146
- assert_eq!(
147
- Snippets::decode(&encoded),
148
- Ok(snippets),
149
- "Frame 3 must carry source and bytecode entries in insertion order"
150
- );
151
- }
152
-
153
- // @behavior WE-053
154
- #[test]
155
- fn an_empty_snippet_table_round_trips() {
156
- let encoded = Snippets::default().encode();
157
- assert_eq!(
158
- Snippets::decode(&encoded),
159
- Ok(Snippets::default()),
160
- "a Sandbox with no preloads must send a present, zero-count Frame 3"
161
- );
162
- }
163
-
164
- // @behavior WE-054
165
- #[test]
166
- fn golden_layout_pins_the_bindings_as_a_counted_list() {
167
- let bindings = Bindings {
168
- paths: vec!["A".into()],
169
- };
170
- assert_eq!(
171
- bindings.encode(),
172
- vec![
173
- 0, 0, 0, 1, // path count
174
- 0, 0, 0, 1, b'A',
175
- ],
176
- "Frame 1 must be a counted list of paths, so the count precedes the first entry"
177
- );
178
- }
179
-
180
- // @behavior WE-055
181
- #[test]
182
- fn golden_layout_pins_the_snippet_entry_shape() {
183
- let snippets = Snippets {
184
- entries: vec![
185
- Snippet::Source {
186
- name: "N".into(),
187
- body: "b".into(),
188
- },
189
- Snippet::Bytecode { body: vec![0x52] },
190
- ],
191
- };
192
- assert_eq!(
193
- snippets.encode(),
194
- vec![
195
- 0, 0, 0, 2, // entry count
196
- 0, // kind: source
197
- 0, 0, 0, 1, b'N', // name, source only
198
- 0, 0, 0, 1, b'b', // body
199
- 1, // kind: bytecode
200
- 0, 0, 0, 1, 0x52, // body, no name
201
- ],
202
- "a source entry must encode as kind byte 0 with a name and a bytecode entry as \
203
- kind byte 1 with none, so the two stay distinguishable by their tag alone"
204
- );
205
- }
206
-
207
- // @behavior WE-056
208
- #[test]
209
- fn an_unknown_snippet_kind_is_refused() {
210
- let bytes = {
211
- let mut w = Writer::new();
212
- w.u32(1).u8(9);
213
- w.into_bytes()
214
- };
215
- assert!(
216
- Snippets::decode(&bytes).is_err(),
217
- "a Frame 3 snippet kind that is neither source nor bytecode must be rejected"
218
- );
219
- }
220
-
221
- // @behavior WE-057
222
- #[test]
223
- fn a_snippet_count_the_frame_cannot_satisfy_is_refused() {
224
- let bytes = [0xff, 0xff, 0xff, 0xff];
225
- assert!(
226
- Snippets::decode(&bytes).is_err(),
227
- "a Frame 3 count larger than the frame must be rejected before any allocation"
228
- );
229
- }
230
-
231
- // @behavior WE-058
232
- #[test]
233
- fn trailing_bytes_after_a_frame_are_refused() {
234
- let mut encoded = Bindings::default().encode();
235
- encoded.push(0);
236
- assert!(
237
- Bindings::decode(&encoded).is_err(),
238
- "bytes past Frame 1's last field must fail loudly as a framing desync"
239
- );
240
- }
241
- }