kobako 0.2.1 → 0.4.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1 -1
  3. data/README.md +205 -59
  4. data/data/kobako.wasm +0 -0
  5. data/ext/kobako/Cargo.toml +2 -2
  6. data/ext/kobako/src/wasm/cache.rs +15 -7
  7. data/ext/kobako/src/wasm/dispatch.rs +88 -36
  8. data/ext/kobako/src/wasm/host_state.rs +298 -55
  9. data/ext/kobako/src/wasm/instance.rs +477 -160
  10. data/ext/kobako/src/wasm.rs +20 -5
  11. data/lib/kobako/capture.rb +12 -10
  12. data/lib/kobako/codec/decoder.rb +3 -4
  13. data/lib/kobako/codec/encoder.rb +1 -1
  14. data/lib/kobako/codec/error.rb +3 -2
  15. data/lib/kobako/codec/factory.rb +24 -17
  16. data/lib/kobako/codec/utils.rb +105 -12
  17. data/lib/kobako/codec.rb +2 -1
  18. data/lib/kobako/errors.rb +22 -10
  19. data/lib/kobako/handle.rb +62 -0
  20. data/lib/kobako/handle_table.rb +119 -0
  21. data/lib/kobako/invocation.rb +143 -0
  22. data/lib/kobako/outcome/panic.rb +2 -2
  23. data/lib/kobako/outcome.rb +61 -24
  24. data/lib/kobako/rpc/dispatcher.rb +30 -28
  25. data/lib/kobako/rpc/envelope.rb +10 -10
  26. data/lib/kobako/rpc/fault.rb +4 -3
  27. data/lib/kobako/rpc/namespace.rb +3 -3
  28. data/lib/kobako/rpc/server.rb +23 -33
  29. data/lib/kobako/rpc/wire_error.rb +23 -0
  30. data/lib/kobako/sandbox.rb +211 -136
  31. data/lib/kobako/sandbox_options.rb +73 -0
  32. data/lib/kobako/snippet/binary.rb +30 -0
  33. data/lib/kobako/snippet/source.rb +28 -0
  34. data/lib/kobako/snippet/table.rb +174 -0
  35. data/lib/kobako/snippet.rb +20 -0
  36. data/lib/kobako/usage.rb +41 -0
  37. data/lib/kobako/version.rb +1 -1
  38. data/lib/kobako.rb +1 -0
  39. data/sig/kobako/codec/factory.rbs +1 -1
  40. data/sig/kobako/codec/utils.rbs +10 -0
  41. data/sig/kobako/errors.rbs +3 -0
  42. data/sig/kobako/handle.rbs +19 -0
  43. data/sig/kobako/handle_table.rbs +23 -0
  44. data/sig/kobako/invocation.rbs +25 -0
  45. data/sig/kobako/outcome.rbs +1 -1
  46. data/sig/kobako/rpc/dispatcher.rbs +7 -7
  47. data/sig/kobako/rpc/envelope.rbs +3 -3
  48. data/sig/kobako/rpc/server.rbs +1 -7
  49. data/sig/kobako/rpc/wire_error.rbs +6 -0
  50. data/sig/kobako/sandbox.rbs +22 -17
  51. data/sig/kobako/sandbox_options.rbs +32 -0
  52. data/sig/kobako/snippet/binary.rbs +12 -0
  53. data/sig/kobako/snippet/source.rbs +13 -0
  54. data/sig/kobako/snippet/table.rbs +36 -0
  55. data/sig/kobako/snippet.rbs +4 -0
  56. data/sig/kobako/usage.rbs +11 -0
  57. data/sig/kobako/wasm.rbs +5 -1
  58. metadata +21 -5
  59. data/lib/kobako/rpc/handle.rb +0 -38
  60. data/lib/kobako/rpc/handle_table.rb +0 -107
  61. data/sig/kobako/rpc/handle.rbs +0 -19
  62. data/sig/kobako/rpc/handle_table.rbs +0 -25
@@ -0,0 +1,32 @@
1
+ module Kobako
2
+ class SandboxOptions < Data
3
+ DEFAULT_TIMEOUT_SECONDS: Float
4
+ DEFAULT_MEMORY_LIMIT: Integer
5
+ DEFAULT_OUTPUT_LIMIT: Integer
6
+
7
+ attr_reader timeout: Float?
8
+ attr_reader memory_limit: Integer?
9
+ attr_reader stdout_limit: Integer
10
+ attr_reader stderr_limit: Integer
11
+
12
+ def self.new: (
13
+ ?timeout: (Float | Integer)?,
14
+ ?memory_limit: Integer?,
15
+ ?stdout_limit: Integer?,
16
+ ?stderr_limit: Integer?
17
+ ) -> SandboxOptions
18
+
19
+ def initialize: (
20
+ ?timeout: (Float | Integer)?,
21
+ ?memory_limit: Integer?,
22
+ ?stdout_limit: Integer?,
23
+ ?stderr_limit: Integer?
24
+ ) -> void
25
+
26
+ private
27
+
28
+ def normalize_timeout: ((Float | Integer)? timeout) -> Float?
29
+
30
+ def normalize_memory_limit: (Integer? memory_limit) -> Integer?
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ module Kobako
2
+ module Snippet
3
+ class Binary < Data
4
+ KIND: String
5
+
6
+ attr_reader body: String
7
+
8
+ def self.new: (body: String) -> Binary
9
+ | (String body) -> Binary
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Kobako
2
+ module Snippet
3
+ class Source < Data
4
+ KIND: String
5
+
6
+ attr_reader name: Symbol
7
+ attr_reader body: String
8
+
9
+ def self.new: (name: Symbol, body: String) -> Source
10
+ | (Symbol name, String body) -> Source
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ module Kobako
2
+ module Snippet
3
+ class Table
4
+ NAME_PATTERN: Regexp
5
+
6
+ type entry = Kobako::Snippet::Source | Kobako::Snippet::Binary
7
+
8
+ def initialize: () -> void
9
+
10
+ def register: (?code: String?, ?name: (Symbol | String)?, ?binary: String?) -> (Symbol | nil)
11
+
12
+ def encode: () -> String
13
+
14
+ def each: () { (entry) -> void } -> Array[entry]
15
+ | () -> Enumerator[entry, Array[entry]]
16
+
17
+ def names: () -> Array[Symbol]
18
+
19
+ def size: () -> Integer
20
+
21
+ def empty?: () -> bool
22
+
23
+ private
24
+
25
+ def register_source!: (String? code, (Symbol | String)? name) -> Symbol
26
+
27
+ def ensure_source_args!: (String? code, (Symbol | String)? name) -> [String, Symbol | String]
28
+
29
+ def register_binary!: (String bytes) -> nil
30
+
31
+ def entry_payload: (entry) -> Hash[String, untyped]
32
+
33
+ def normalize_name: (Symbol | String name) -> Symbol
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module Kobako
2
+ module Snippet
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ module Kobako
2
+ class Usage < Data
3
+ EMPTY: Usage
4
+
5
+ attr_reader wall_time: Float
6
+ attr_reader memory_peak: Integer
7
+
8
+ def self.new: (wall_time: Float, memory_peak: Integer) -> Usage
9
+ | (Float wall_time, Integer memory_peak) -> Usage
10
+ end
11
+ end
data/sig/kobako/wasm.rbs CHANGED
@@ -25,13 +25,17 @@ module Kobako
25
25
 
26
26
  def server=: (Kobako::RPC::Server server) -> void
27
27
 
28
- def run: (String preamble, String source) -> void
28
+ def eval: (String preamble, String source, String snippets) -> void
29
+
30
+ def run: (String preamble, String snippets, String envelope) -> void
29
31
 
30
32
  def stdout: () -> [String, bool]
31
33
 
32
34
  def stderr: () -> [String, bool]
33
35
 
34
36
  def outcome!: () -> String
37
+
38
+ def usage: () -> [Float, Integer]
35
39
  end
36
40
  end
37
41
  end
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.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aotokitsuruya
@@ -69,17 +69,25 @@ files:
69
69
  - lib/kobako/codec/factory.rb
70
70
  - lib/kobako/codec/utils.rb
71
71
  - lib/kobako/errors.rb
72
+ - lib/kobako/handle.rb
73
+ - lib/kobako/handle_table.rb
74
+ - lib/kobako/invocation.rb
72
75
  - lib/kobako/outcome.rb
73
76
  - lib/kobako/outcome/panic.rb
74
77
  - lib/kobako/rpc.rb
75
78
  - lib/kobako/rpc/dispatcher.rb
76
79
  - lib/kobako/rpc/envelope.rb
77
80
  - lib/kobako/rpc/fault.rb
78
- - lib/kobako/rpc/handle.rb
79
- - lib/kobako/rpc/handle_table.rb
80
81
  - lib/kobako/rpc/namespace.rb
81
82
  - lib/kobako/rpc/server.rb
83
+ - lib/kobako/rpc/wire_error.rb
82
84
  - lib/kobako/sandbox.rb
85
+ - lib/kobako/sandbox_options.rb
86
+ - lib/kobako/snippet.rb
87
+ - lib/kobako/snippet/binary.rb
88
+ - lib/kobako/snippet/source.rb
89
+ - lib/kobako/snippet/table.rb
90
+ - lib/kobako/usage.rb
83
91
  - lib/kobako/version.rb
84
92
  - lib/kobako/wasm.rb
85
93
  - sig/kobako.rbs
@@ -90,17 +98,25 @@ files:
90
98
  - sig/kobako/codec/factory.rbs
91
99
  - sig/kobako/codec/utils.rbs
92
100
  - sig/kobako/errors.rbs
101
+ - sig/kobako/handle.rbs
102
+ - sig/kobako/handle_table.rbs
103
+ - sig/kobako/invocation.rbs
93
104
  - sig/kobako/outcome.rbs
94
105
  - sig/kobako/outcome/panic.rbs
95
106
  - sig/kobako/rpc.rbs
96
107
  - sig/kobako/rpc/dispatcher.rbs
97
108
  - sig/kobako/rpc/envelope.rbs
98
109
  - sig/kobako/rpc/fault.rbs
99
- - sig/kobako/rpc/handle.rbs
100
- - sig/kobako/rpc/handle_table.rbs
101
110
  - sig/kobako/rpc/namespace.rbs
102
111
  - sig/kobako/rpc/server.rbs
112
+ - sig/kobako/rpc/wire_error.rbs
103
113
  - sig/kobako/sandbox.rbs
114
+ - sig/kobako/sandbox_options.rbs
115
+ - sig/kobako/snippet.rbs
116
+ - sig/kobako/snippet/binary.rbs
117
+ - sig/kobako/snippet/source.rbs
118
+ - sig/kobako/snippet/table.rbs
119
+ - sig/kobako/usage.rbs
104
120
  - sig/kobako/wasm.rbs
105
121
  homepage: https://github.com/elct9620/kobako
106
122
  licenses:
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kobako
4
- module RPC
5
- # Wire-level value object for an ext-0x01 Capability Handle.
6
- #
7
- # SPEC pins the binary layout to fixext 4 with a 4-byte big-endian u32
8
- # payload (Wire Codec → Ext Types → ext 0x01). ID 0 is reserved as the
9
- # invalid sentinel; the maximum valid ID is 0x7fff_ffff (2^31 - 1).
10
- #
11
- # This is intentionally a thin value object built on +Data.define+ so
12
- # equality, hash, and immutability are inherited. The runtime-facing
13
- # +Kobako::RPC::Handle+ class lives at a higher layer and may add behaviour
14
- # (HandleTable bookkeeping, reset semantics). The codec only needs to
15
- # carry the opaque integer ID across the wire.
16
- Handle = Data.define(:id) do
17
- # +MIN_ID+ / +MAX_ID+ live on the Handle class (defined below this
18
- # block), not in this block's binding — Data.define's block scope
19
- # resolves bare constants against the enclosing +Wire+ module, so
20
- # +MIN_ID+ would raise +NameError+. Use +self.class::CONST+ to
21
- # reach the constants attached to the Handle class itself. Do not
22
- # "simplify" this back to bare +MIN_ID+/+MAX_ID+.
23
- # steep:ignore:start
24
- def initialize(id:)
25
- min = self.class::MIN_ID
26
- max = self.class::MAX_ID
27
- raise ArgumentError, "Handle id must be Integer" unless id.is_a?(Integer)
28
- raise ArgumentError, "Handle id #{id} out of range [#{min}, #{max}]" unless id.between?(min, max)
29
-
30
- super
31
- end
32
- # steep:ignore:end
33
- end
34
-
35
- Handle::MIN_ID = 1
36
- Handle::MAX_ID = 0x7fff_ffff
37
- end
38
- end
@@ -1,107 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "handle"
4
-
5
- module Kobako
6
- module RPC
7
- # Host-side mapping from opaque integer Handle IDs to Ruby objects
8
- # (capability proxies). One table is owned per +Kobako::RPC::Server+
9
- # instance (and therefore per +Kobako::Sandbox+ instance). See
10
- # {SPEC.md B-15}[link:../../../SPEC.md].
11
- #
12
- # Lifecycle invariants ({SPEC.md}[link:../../../SPEC.md]):
13
- #
14
- # - {SPEC.md B-15}[link:../../../SPEC.md] — Handle IDs are allocated by
15
- # a monotonically increasing counter scoped to a single `#run`. The
16
- # first ID issued in a run is 1; ID 0 is reserved as the invalid
17
- # sentinel and is never returned by #alloc.
18
- #
19
- # - {SPEC.md B-19}[link:../../../SPEC.md] — When between `#run`
20
- # invocations (via `#reset!`), every Handle issued under the old state
21
- # becomes invalid.
22
- #
23
- # - {SPEC.md B-21}[link:../../../SPEC.md] — The cap is `0x7fff_ffff`
24
- # (2³¹ − 1). Allocation beyond the cap raises immediately — no silent
25
- # truncation, no wrap, no ID reuse.
26
- class HandleTable
27
- # Build a fresh, empty HandleTable. +next_id+ is an internal seam that
28
- # sets the starting value of the monotonic counter (defaults to 1 per
29
- # B-15); tests pass a value near +RPC::Handle::MAX_ID+ to exercise
30
- # the cap-exhaustion path without 2³¹ allocations.
31
- def initialize(next_id: 1)
32
- @entries = {} # : Hash[Integer, untyped]
33
- @next_id = next_id
34
- end
35
-
36
- # Bind +object+ in the table and return its newly-allocated Handle ID.
37
- # +object+ is any host-side Ruby object to bind. Returns a freshly-
38
- # allocated Handle ID in +[1, RPC::Handle::MAX_ID]+. Raises
39
- # +Kobako::HandleTableExhausted+ if the next ID would exceed the cap.
40
- # The cap is anchored on +RPC::Handle+ — the wire codec and the
41
- # allocator share the same invariant ({SPEC.md B-21}[link:../../../SPEC.md]).
42
- def alloc(object)
43
- id = @next_id
44
- cap = RPC::Handle::MAX_ID
45
- raise HandleTableExhausted, "HandleTable exhausted: id #{id} exceeds MAX_ID #{cap}" if id > cap
46
-
47
- @entries[id] = object
48
- @next_id = id + 1
49
- id
50
- end
51
-
52
- # Resolve a Handle ID to its bound object. +id+ is a Handle ID previously
53
- # returned by +#alloc+. Returns the bound object. Raises
54
- # +Kobako::HandleTableError+ if +id+ is not currently bound.
55
- def fetch(id)
56
- require_bound!(id)
57
- @entries[id]
58
- end
59
-
60
- # Remove and return the binding for +id+. +id+ is the Handle ID to
61
- # release. Returns the previously-bound object. Raises
62
- # +Kobako::HandleTableError+ if +id+ is not currently bound.
63
- def release(id)
64
- require_bound!(id)
65
- @entries.delete(id)
66
- end
67
-
68
- # Clear all entries AND reset the counter to 1. Called at the per-run
69
- # boundary — see {SPEC.md B-19}[link:../../../SPEC.md].
70
- # Returns +self+.
71
- def reset!
72
- @entries.clear
73
- @next_id = 1
74
- self
75
- end
76
-
77
- # Mark the entry at +id+ as disconnected (ABA protection). +id+ is the
78
- # Handle ID to poison; silently ignored if +id+ is not currently bound.
79
- # Returns +self+ for chainability, matching the convention of +#reset!+.
80
- def mark_disconnected(id)
81
- @entries[id] = :disconnected if @entries.key?(id)
82
- self
83
- end
84
-
85
- # Returns the number of currently-bound entries.
86
- def size
87
- @entries.size
88
- end
89
-
90
- # Returns +true+ when +id+ is currently bound, +false+ otherwise.
91
- def include?(id)
92
- @entries.key?(id)
93
- end
94
-
95
- private
96
-
97
- # Single source of truth for the "unknown Handle id" raise shared by
98
- # {#fetch} and {#release}. Returns +nil+ on success; raises
99
- # +Kobako::HandleTableError+ when +id+ is not currently bound.
100
- def require_bound!(id)
101
- return if @entries.key?(id)
102
-
103
- raise HandleTableError, "unknown Handle id: #{id.inspect}"
104
- end
105
- end
106
- end
107
- end
@@ -1,19 +0,0 @@
1
- module Kobako
2
- module RPC
3
- class Handle
4
- MIN_ID: Integer
5
- MAX_ID: Integer
6
-
7
- attr_reader id: Integer
8
-
9
- def initialize: (Integer id) -> void
10
- | (id: Integer) -> void
11
-
12
- def with: (?id: Integer) -> Handle
13
-
14
- def ==: (untyped other) -> bool
15
-
16
- def hash: () -> Integer
17
- end
18
- end
19
- end
@@ -1,25 +0,0 @@
1
- module Kobako
2
- module RPC
3
- class HandleTable
4
- def initialize: (?next_id: Integer) -> void
5
-
6
- def alloc: (untyped object) -> Integer
7
-
8
- def fetch: (Integer id) -> untyped
9
-
10
- def release: (Integer id) -> untyped
11
-
12
- def reset!: () -> self
13
-
14
- def mark_disconnected: (Integer id) -> self
15
-
16
- def size: () -> Integer
17
-
18
- def include?: (Integer id) -> bool
19
-
20
- private
21
-
22
- def require_bound!: (Integer id) -> void
23
- end
24
- end
25
- end