kobako 0.12.1 → 0.13.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 +22 -0
- data/Cargo.lock +138 -136
- data/Cargo.toml +6 -2
- data/README.md +3 -1
- data/crates/kobako-runtime/CHANGELOG.md +16 -0
- data/crates/kobako-runtime/Cargo.toml +23 -0
- data/crates/kobako-runtime/README.md +34 -0
- data/crates/kobako-runtime/src/dispatch.rs +22 -0
- data/crates/kobako-runtime/src/error.rs +64 -0
- data/crates/kobako-runtime/src/lib.rs +18 -0
- data/crates/kobako-runtime/src/profile.rs +35 -0
- data/crates/kobako-runtime/src/runtime.rs +57 -0
- data/crates/kobako-runtime/src/snapshot.rs +46 -0
- data/crates/kobako-runtime/src/yielder.rs +22 -0
- data/crates/kobako-wasmtime/CHANGELOG.md +16 -0
- data/crates/kobako-wasmtime/Cargo.toml +62 -0
- data/crates/kobako-wasmtime/README.md +32 -0
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/ambient.rs +8 -5
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/cache.rs +30 -41
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/capture.rs +2 -2
- data/crates/kobako-wasmtime/src/config.rs +33 -0
- data/crates/kobako-wasmtime/src/dispatch.rs +110 -0
- data/crates/kobako-wasmtime/src/driver.rs +297 -0
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/exports.rs +5 -6
- data/crates/kobako-wasmtime/src/frames.rs +276 -0
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/guest_mem.rs +38 -15
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/instance_pre.rs +13 -21
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/invocation.rs +54 -49
- data/crates/kobako-wasmtime/src/lib.rs +47 -0
- data/{ext/kobako/src/runtime → crates/kobako-wasmtime/src}/trap.rs +29 -35
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +9 -32
- data/ext/kobako/src/lib.rs +0 -2
- data/ext/kobako/src/runtime/bridge.rs +150 -0
- data/ext/kobako/src/runtime/errors.rs +45 -13
- data/ext/kobako/src/runtime.rs +246 -420
- data/lib/kobako/catalog/handles.rb +3 -3
- data/lib/kobako/catalog/namespaces.rb +4 -0
- data/lib/kobako/catalog/snippets.rb +4 -0
- data/lib/kobako/codec/encoder.rb +5 -1
- data/lib/kobako/codec/factory.rb +41 -13
- data/lib/kobako/codec/handle_walk.rb +4 -0
- data/lib/kobako/codec.rb +1 -1
- data/lib/kobako/errors.rb +18 -16
- data/lib/kobako/sandbox.rb +71 -39
- data/lib/kobako/sandbox_options.rb +71 -13
- data/lib/kobako/transport/dispatcher.rb +2 -2
- data/lib/kobako/transport/response.rb +14 -14
- data/lib/kobako/transport/run.rb +2 -6
- data/lib/kobako/transport/yield.rb +1 -1
- data/lib/kobako/transport/yielder.rb +2 -2
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +0 -1
- data/release-please-config.json +78 -3
- data/sig/kobako/codec/factory.rbs +3 -0
- data/sig/kobako/errors.rbs +7 -14
- data/sig/kobako/runtime.rbs +16 -6
- data/sig/kobako/sandbox.rbs +11 -7
- data/sig/kobako/sandbox_options.rbs +15 -4
- data/sig/kobako/transport/dispatcher.rbs +1 -1
- data/sig/kobako/transport/run.rbs +2 -2
- data/sig/kobako/transport/yielder.rbs +2 -2
- data/sig/kobako/transport.rbs +8 -0
- metadata +28 -15
- data/ext/kobako/src/runtime/config.rs +0 -25
- data/ext/kobako/src/runtime/dispatch.rs +0 -211
- data/ext/kobako/src/runtime/frames.rs +0 -188
- data/ext/kobako/src/snapshot.rs +0 -110
- data/lib/kobako/snapshot.rb +0 -38
- data/sig/kobako/snapshot.rbs +0 -15
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
//! Per-invocation byte-shuttle between Ruby and guest linear memory: it
|
|
2
|
-
//! resolves the required `memory` / ABI-export handles, writes the `#run`
|
|
3
|
-
//! envelope into a freshly allocated guest buffer, builds the stdin frame
|
|
4
|
-
//! stream plus stdout / stderr capture pipes for the WASI context, and
|
|
5
|
-
//! reads the OUTCOME_BUFFER back out. The ext owns no wire codec — these
|
|
6
|
-
//! helpers move raw bytes; Ruby decodes them.
|
|
7
|
-
|
|
8
|
-
use magnus::{Error as MagnusError, RString, Ruby};
|
|
9
|
-
use wasmtime::{AsContextMut, Memory, Store as WtStore, TypedFunc};
|
|
10
|
-
use wasmtime_wasi::p2::pipe::{MemoryInputPipe, MemoryOutputPipe};
|
|
11
|
-
use wasmtime_wasi::WasiCtxBuilder;
|
|
12
|
-
|
|
13
|
-
use super::config::Config;
|
|
14
|
-
use super::exports::Exports;
|
|
15
|
-
use super::invocation::Invocation;
|
|
16
|
-
use super::rstring_to_vec;
|
|
17
|
-
use super::{ambient, capture, errors, guest_mem};
|
|
18
|
-
|
|
19
|
-
/// Return the resolved `memory` export handle, or raise
|
|
20
|
-
/// `Kobako::TrapError` when the loaded module exports no linear
|
|
21
|
-
/// memory — the "not a Kobako-shaped runtime" failure mode
|
|
22
|
-
/// (`SANDBOX_RUNTIME_NOT_KOBAKO`).
|
|
23
|
-
fn require_memory(ruby: &Ruby, exports: &Exports) -> Result<Memory, MagnusError> {
|
|
24
|
-
exports
|
|
25
|
-
.memory
|
|
26
|
-
.ok_or_else(|| errors::trap_err(ruby, SANDBOX_RUNTIME_NOT_KOBAKO))
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/// Allocate a `len`-byte buffer in guest linear memory via
|
|
30
|
-
/// `__kobako_alloc`, copy `envelope` into it, and return `(ptr, len)`
|
|
31
|
-
/// as `i32` values matching the `__kobako_run(env_ptr, env_len)` ABI.
|
|
32
|
-
/// Raises `Kobako::TrapError` when the allocation hook is missing or
|
|
33
|
-
/// itself traps, and `Kobako::SandboxError` when the hook runs but
|
|
34
|
-
/// cannot reserve the buffer (`__kobako_alloc` returns 0) — an
|
|
35
|
-
/// intact runtime, not an engine fault.
|
|
36
|
-
pub(crate) fn write_envelope(
|
|
37
|
-
ruby: &Ruby,
|
|
38
|
-
store: &mut WtStore<Invocation>,
|
|
39
|
-
exports: &Exports,
|
|
40
|
-
envelope: RString,
|
|
41
|
-
) -> Result<(i32, i32), MagnusError> {
|
|
42
|
-
let bytes = rstring_to_vec(envelope);
|
|
43
|
-
let len_i32 =
|
|
44
|
-
guest_mem::checked_payload_len(bytes.len()).map_err(|msg| errors::trap_err(ruby, msg))?;
|
|
45
|
-
|
|
46
|
-
let alloc = require_export(ruby, exports.alloc.as_ref())?;
|
|
47
|
-
let memory = require_memory(ruby, exports)?;
|
|
48
|
-
|
|
49
|
-
let ptr = alloc
|
|
50
|
-
.call(store.as_context_mut(), bytes.len() as u32)
|
|
51
|
-
.map_err(|e| errors::trap_err(ruby, format!("failed to allocate input buffer: {}", e)))?;
|
|
52
|
-
if ptr == 0 {
|
|
53
|
-
return Err(errors::sandbox_err(
|
|
54
|
-
ruby,
|
|
55
|
-
"could not allocate input buffer (out of memory)",
|
|
56
|
-
));
|
|
57
|
-
}
|
|
58
|
-
let data = memory.data_mut(store.as_context_mut());
|
|
59
|
-
let range = guest_mem::guest_buffer_range(ptr as usize, bytes.len(), data.len())
|
|
60
|
-
.map_err(|msg| errors::trap_err(ruby, msg))?;
|
|
61
|
-
data[range].copy_from_slice(&bytes);
|
|
62
|
-
|
|
63
|
-
Ok((ptr as i32, len_i32))
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/// Build the per-invocation WASI context with stdin carrying every frame
|
|
67
|
-
/// in `frames` (each prefixed by its 4-byte big-endian u32 length —
|
|
68
|
-
/// docs/wire-codec.md § Invocation channels) plus fresh stdout / stderr
|
|
69
|
-
/// pipes, and install it on the invocation's Store. `#eval` passes three
|
|
70
|
-
/// frames (preamble, source, snippets), `#run` passes two (preamble,
|
|
71
|
-
/// snippets — the invocation envelope arrives via linear memory
|
|
72
|
-
/// instead). Each output pipe is sized at `cap + 1` so
|
|
73
|
-
/// `capture::clip_capture` can distinguish "wrote exactly cap bytes"
|
|
74
|
-
/// from "exceeded cap"; uncapped channels fall back to `usize::MAX` and
|
|
75
|
-
/// rely on `memory_limit` for the real ceiling.
|
|
76
|
-
/// Raises `Kobako::TrapError` when any frame exceeds the 16 MiB cap that
|
|
77
|
-
/// keeps its `u32` length prefix from wrapping.
|
|
78
|
-
pub(crate) fn install_wasi_frames(
|
|
79
|
-
store: &mut WtStore<Invocation>,
|
|
80
|
-
config: &Config,
|
|
81
|
-
frames: &[Vec<u8>],
|
|
82
|
-
) -> Result<(), MagnusError> {
|
|
83
|
-
let ruby = Ruby::get().expect("Ruby thread");
|
|
84
|
-
// Every frame carries the same 16 MiB cap as the `#run` envelope
|
|
85
|
-
// (`write_envelope`): the length prefix is a `u32`, so a frame past
|
|
86
|
-
// the cap would silently wrap and corrupt the stdin frame stream.
|
|
87
|
-
for frame in frames {
|
|
88
|
-
guest_mem::checked_payload_len(frame.len()).map_err(|msg| errors::trap_err(&ruby, msg))?;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
let total: usize = frames.iter().map(|f| 4 + f.len()).sum();
|
|
92
|
-
let mut stdin_content: Vec<u8> = Vec::with_capacity(total);
|
|
93
|
-
for frame in frames {
|
|
94
|
-
stdin_content.extend_from_slice(&(frame.len() as u32).to_be_bytes());
|
|
95
|
-
stdin_content.extend_from_slice(frame);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
let stdin_pipe = MemoryInputPipe::new(stdin_content);
|
|
99
|
-
let stdout_pipe = MemoryOutputPipe::new(capture::pipe_capacity(config.stdout_limit_bytes));
|
|
100
|
-
let stderr_pipe = MemoryOutputPipe::new(capture::pipe_capacity(config.stderr_limit_bytes));
|
|
101
|
-
|
|
102
|
-
let mut builder = WasiCtxBuilder::new();
|
|
103
|
-
builder.stdin(stdin_pipe);
|
|
104
|
-
builder.stdout(stdout_pipe.clone());
|
|
105
|
-
builder.stderr(stderr_pipe.clone());
|
|
106
|
-
// Deny the preview1 ambient-authority imports the guest never legitimately
|
|
107
|
-
// reaches but the WASI layer would otherwise grant (see `ambient`).
|
|
108
|
-
builder.wall_clock(ambient::FrozenWallClock);
|
|
109
|
-
builder.monotonic_clock(ambient::FrozenMonotonicClock);
|
|
110
|
-
builder.secure_random(ambient::deterministic_rng());
|
|
111
|
-
let wasi = builder.build_p1();
|
|
112
|
-
|
|
113
|
-
store
|
|
114
|
-
.data_mut()
|
|
115
|
-
.install_wasi(wasi, stdout_pipe, stderr_pipe);
|
|
116
|
-
Ok(())
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/// Invoke `__kobako_take_outcome`, decode the packed `(ptr<<32)|len`
|
|
120
|
-
/// u64, and copy the OUTCOME_BUFFER slice out of guest memory. Raises
|
|
121
|
-
/// `Kobako::TrapError` when the export is missing, `len` exceeds the
|
|
122
|
-
/// 16 MiB single-dispatch cap, the `ptr`/`len` arithmetic overflows,
|
|
123
|
-
/// the slice falls outside live memory, or the `memory` export itself
|
|
124
|
-
/// is absent.
|
|
125
|
-
pub(crate) fn fetch_outcome_bytes(
|
|
126
|
-
ruby: &Ruby,
|
|
127
|
-
store: &mut WtStore<Invocation>,
|
|
128
|
-
exports: &Exports,
|
|
129
|
-
) -> Result<Vec<u8>, MagnusError> {
|
|
130
|
-
let take = require_export(ruby, exports.take_outcome.as_ref())?;
|
|
131
|
-
let mem = require_memory(ruby, exports)?;
|
|
132
|
-
|
|
133
|
-
let packed = take
|
|
134
|
-
.call(store.as_context_mut(), ())
|
|
135
|
-
.map_err(|e| errors::trap_err(ruby, format!("failed to read the Sandbox result: {}", e)))?;
|
|
136
|
-
let (ptr, len) = guest_mem::unpack_outcome_packed(packed);
|
|
137
|
-
if len > guest_mem::MAX_DISPATCH_PAYLOAD {
|
|
138
|
-
return Err(errors::trap_err(
|
|
139
|
-
ruby,
|
|
140
|
-
"result payload exceeds the 16 MiB limit",
|
|
141
|
-
));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
let data = mem.data(store.as_context_mut());
|
|
145
|
-
let range = guest_mem::guest_buffer_range(ptr, len, data.len()).map_err(|msg| {
|
|
146
|
-
errors::trap_err(
|
|
147
|
-
ruby,
|
|
148
|
-
format!("the Sandbox result is out of bounds: {}", msg),
|
|
149
|
-
)
|
|
150
|
-
})?;
|
|
151
|
-
Ok(data[range].to_vec())
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/// User-facing message for the "Sandbox runtime is missing one of the
|
|
155
|
-
/// internal Kobako hooks" failure mode. Phrased in caller vocabulary —
|
|
156
|
-
/// the underlying ABI symbol names (`__kobako_alloc`, `__kobako_eval`,
|
|
157
|
-
/// `__kobako_take_outcome`) are not actionable to callers, and the
|
|
158
|
-
/// gem itself raises this error so a self-reference like "matches the
|
|
159
|
-
/// kobako gem version" reads as third-person. The actionable
|
|
160
|
-
/// diagnosis is "your data/kobako.wasm is out of sync; rebuild it".
|
|
161
|
-
const SANDBOX_RUNTIME_MISSING_HOOKS: &str = "Sandbox runtime is missing required hooks; \
|
|
162
|
-
rebuild data/kobako.wasm against the installed version";
|
|
163
|
-
|
|
164
|
-
/// User-facing message for the "the loaded Wasm module is not a
|
|
165
|
-
/// Kobako-shaped runtime at all" failure mode (no linear memory
|
|
166
|
-
/// export). Same phrasing philosophy as
|
|
167
|
-
/// `SANDBOX_RUNTIME_MISSING_HOOKS`.
|
|
168
|
-
const SANDBOX_RUNTIME_NOT_KOBAKO: &str =
|
|
169
|
-
"the loaded Wasm module is not a Kobako-compatible runtime";
|
|
170
|
-
|
|
171
|
-
/// Return the resolved `TypedFunc` for an ABI export, or raise
|
|
172
|
-
/// `Kobako::TrapError` when the option is `None`. Both run-path
|
|
173
|
-
/// methods (`#eval`, `#run`) plus the `build_snapshot` readout that
|
|
174
|
-
/// drains `OUTCOME_BUFFER` share the same "missing export → Ruby
|
|
175
|
-
/// error" boilerplate; this helper collapses those sites onto one
|
|
176
|
-
/// safe entry. The user-facing message is intentionally export-
|
|
177
|
-
/// agnostic (see `SANDBOX_RUNTIME_MISSING_HOOKS`) — the ABI symbol
|
|
178
|
-
/// name is not actionable to callers, so it is not threaded in.
|
|
179
|
-
pub(crate) fn require_export<'a, Params, Results>(
|
|
180
|
-
ruby: &Ruby,
|
|
181
|
-
export: Option<&'a TypedFunc<Params, Results>>,
|
|
182
|
-
) -> Result<&'a TypedFunc<Params, Results>, MagnusError>
|
|
183
|
-
where
|
|
184
|
-
Params: wasmtime::WasmParams,
|
|
185
|
-
Results: wasmtime::WasmResults,
|
|
186
|
-
{
|
|
187
|
-
export.ok_or_else(|| errors::trap_err(ruby, SANDBOX_RUNTIME_MISSING_HOOKS))
|
|
188
|
-
}
|
data/ext/kobako/src/snapshot.rs
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
//! `Kobako::Snapshot` — per-invocation observable bundle.
|
|
2
|
-
//!
|
|
3
|
-
//! Every successful `Kobako::Runtime#eval` / `#run` returns one of these.
|
|
4
|
-
//! It carries every observable the host needs to surface after a guest
|
|
5
|
-
//! invocation: the OUTCOME_BUFFER bytes (`return_bytes`), the captured
|
|
6
|
-
//! stdout / stderr byte slices with their truncation flags, and
|
|
7
|
-
//! the wall-clock + memory-peak figures from `Kobako::Usage`.
|
|
8
|
-
//!
|
|
9
|
-
//! Ruby callers see the seven raw readers registered below; the helper
|
|
10
|
-
//! methods that pack them into `Kobako::Capture` / `Kobako::Usage`
|
|
11
|
-
//! (`Kobako::Snapshot#stdout` / `#stderr` / `#usage`) live in
|
|
12
|
-
//! `lib/kobako/snapshot.rb`. The split keeps the ext side a pure value
|
|
13
|
-
//! carrier and lets Ruby own the convenience surface.
|
|
14
|
-
|
|
15
|
-
use std::cell::Cell;
|
|
16
|
-
use std::time::Duration;
|
|
17
|
-
|
|
18
|
-
use magnus::{method, prelude::*, Error as MagnusError, RModule, RString, Ruby};
|
|
19
|
-
|
|
20
|
-
/// Per-invocation snapshot value. Magnus wraps it so a single ext call
|
|
21
|
-
/// from `Runtime::eval` / `Runtime::run` returns the whole bundle —
|
|
22
|
-
/// the Sandbox layer can decompose it without round-tripping into ext
|
|
23
|
-
/// again. All fields are private; the seven public methods registered
|
|
24
|
-
/// in `init` read them out one by one. The wall-clock duration is
|
|
25
|
-
/// held as a `Cell<Duration>` only because magnus' `#[magnus::wrap]`
|
|
26
|
-
/// macro requires interior mutability — every field is set once at
|
|
27
|
-
/// construction time and never mutated again.
|
|
28
|
-
#[magnus::wrap(class = "Kobako::Snapshot", free_immediately, size)]
|
|
29
|
-
pub(crate) struct Snapshot {
|
|
30
|
-
return_bytes: Vec<u8>,
|
|
31
|
-
stdout_bytes: Vec<u8>,
|
|
32
|
-
stdout_truncated: bool,
|
|
33
|
-
stderr_bytes: Vec<u8>,
|
|
34
|
-
stderr_truncated: bool,
|
|
35
|
-
wall_time: Cell<Duration>,
|
|
36
|
-
memory_peak: usize,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
impl Snapshot {
|
|
40
|
-
/// Construct a fresh Snapshot from the per-invocation data the
|
|
41
|
-
/// Runtime has just collected. Called from
|
|
42
|
-
/// `crate::runtime::Runtime::build_snapshot` once the
|
|
43
|
-
/// guest export has returned, the OUTCOME_BUFFER has been drained,
|
|
44
|
-
/// and the capture pipes have been clipped to their caps.
|
|
45
|
-
pub(crate) fn new(
|
|
46
|
-
return_bytes: Vec<u8>,
|
|
47
|
-
stdout_bytes: Vec<u8>,
|
|
48
|
-
stdout_truncated: bool,
|
|
49
|
-
stderr_bytes: Vec<u8>,
|
|
50
|
-
stderr_truncated: bool,
|
|
51
|
-
wall_time: Duration,
|
|
52
|
-
memory_peak: usize,
|
|
53
|
-
) -> Self {
|
|
54
|
-
Self {
|
|
55
|
-
return_bytes,
|
|
56
|
-
stdout_bytes,
|
|
57
|
-
stdout_truncated,
|
|
58
|
-
stderr_bytes,
|
|
59
|
-
stderr_truncated,
|
|
60
|
-
wall_time: Cell::new(wall_time),
|
|
61
|
-
memory_peak,
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
fn return_bytes(&self) -> RString {
|
|
66
|
-
let ruby = Ruby::get().expect("Ruby thread");
|
|
67
|
-
ruby.str_from_slice(&self.return_bytes)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
fn stdout_bytes(&self) -> RString {
|
|
71
|
-
let ruby = Ruby::get().expect("Ruby thread");
|
|
72
|
-
ruby.str_from_slice(&self.stdout_bytes)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
fn stdout_truncated(&self) -> bool {
|
|
76
|
-
self.stdout_truncated
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
fn stderr_bytes(&self) -> RString {
|
|
80
|
-
let ruby = Ruby::get().expect("Ruby thread");
|
|
81
|
-
ruby.str_from_slice(&self.stderr_bytes)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
fn stderr_truncated(&self) -> bool {
|
|
85
|
-
self.stderr_truncated
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
fn wall_time(&self) -> f64 {
|
|
89
|
-
self.wall_time.get().as_secs_f64()
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
fn memory_peak(&self) -> usize {
|
|
93
|
-
self.memory_peak
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/// Register `Kobako::Snapshot` plus its seven raw readers under the
|
|
98
|
-
/// `Kobako` module. Called from `crate::init` after `Kobako::Runtime`
|
|
99
|
-
/// is registered so the magnus wrap macro can resolve the class name.
|
|
100
|
-
pub(crate) fn init(ruby: &Ruby, kobako: RModule) -> Result<(), MagnusError> {
|
|
101
|
-
let snapshot = kobako.define_class("Snapshot", ruby.class_object())?;
|
|
102
|
-
snapshot.define_method("return_bytes", method!(Snapshot::return_bytes, 0))?;
|
|
103
|
-
snapshot.define_method("stdout_bytes", method!(Snapshot::stdout_bytes, 0))?;
|
|
104
|
-
snapshot.define_method("stdout_truncated", method!(Snapshot::stdout_truncated, 0))?;
|
|
105
|
-
snapshot.define_method("stderr_bytes", method!(Snapshot::stderr_bytes, 0))?;
|
|
106
|
-
snapshot.define_method("stderr_truncated", method!(Snapshot::stderr_truncated, 0))?;
|
|
107
|
-
snapshot.define_method("wall_time", method!(Snapshot::wall_time, 0))?;
|
|
108
|
-
snapshot.define_method("memory_peak", method!(Snapshot::memory_peak, 0))?;
|
|
109
|
-
Ok(())
|
|
110
|
-
}
|
data/lib/kobako/snapshot.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "capture"
|
|
4
|
-
require_relative "usage"
|
|
5
|
-
|
|
6
|
-
module Kobako
|
|
7
|
-
# Kobako::Snapshot — per-invocation observable bundle returned from
|
|
8
|
-
# +Kobako::Runtime#eval+ and +#run+.
|
|
9
|
-
#
|
|
10
|
-
# The magnus class (see ext/kobako/src/snapshot.rs) carries seven raw
|
|
11
|
-
# readers: +return_bytes+, +stdout_bytes+, +stdout_truncated+,
|
|
12
|
-
# +stderr_bytes+, +stderr_truncated+, +wall_time+, +memory_peak+. This
|
|
13
|
-
# file reopens the class to add the Ruby-side helpers that pack those
|
|
14
|
-
# raw fields into the user-facing value objects +Kobako::Capture+ and
|
|
15
|
-
# +Kobako::Usage+ — the same shape +Kobako::Sandbox+ exposes to the
|
|
16
|
-
# Host App.
|
|
17
|
-
class Snapshot
|
|
18
|
-
# Wrap the stdout capture pair (+stdout_bytes+, +stdout_truncated+)
|
|
19
|
-
# as a +Kobako::Capture+ value object. The byte content never carries
|
|
20
|
-
# a truncation sentinel; +#truncated?+ is the only way to observe
|
|
21
|
-
# that the cap was hit.
|
|
22
|
-
def stdout
|
|
23
|
-
Capture.new(bytes: stdout_bytes, truncated: stdout_truncated)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Wrap the stderr capture pair as a +Kobako::Capture+ value object.
|
|
27
|
-
# Mirror of +#stdout+.
|
|
28
|
-
def stderr
|
|
29
|
-
Capture.new(bytes: stderr_bytes, truncated: stderr_truncated)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Wrap the per-last-invocation usage pair (+wall_time+,
|
|
33
|
-
# +memory_peak+) as a +Kobako::Usage+ value object.
|
|
34
|
-
def usage
|
|
35
|
-
Usage.new(wall_time: wall_time, memory_peak: memory_peak)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
data/sig/kobako/snapshot.rbs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
module Kobako
|
|
2
|
-
class Snapshot
|
|
3
|
-
def return_bytes: () -> String
|
|
4
|
-
def stdout_bytes: () -> String
|
|
5
|
-
def stdout_truncated: () -> bool
|
|
6
|
-
def stderr_bytes: () -> String
|
|
7
|
-
def stderr_truncated: () -> bool
|
|
8
|
-
def wall_time: () -> Float
|
|
9
|
-
def memory_peak: () -> Integer
|
|
10
|
-
|
|
11
|
-
def stdout: () -> Kobako::Capture
|
|
12
|
-
def stderr: () -> Kobako::Capture
|
|
13
|
-
def usage: () -> Kobako::Usage
|
|
14
|
-
end
|
|
15
|
-
end
|