wasmtime 0.2.0 → 0.3.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/Cargo.lock +941 -627
- data/Cargo.toml +2 -14
- data/LICENSE +23 -21
- data/README.md +47 -118
- data/ext/Cargo.toml +17 -0
- data/ext/extconf.rb +6 -0
- data/ext/src/helpers/mod.rs +3 -0
- data/ext/src/helpers/wrapped_struct.rs +84 -0
- data/ext/src/lib.rs +9 -0
- data/ext/src/ruby_api/config.rs +68 -0
- data/ext/src/ruby_api/convert.rs +92 -0
- data/ext/src/ruby_api/engine.rs +66 -0
- data/ext/src/ruby_api/errors.rs +56 -0
- data/ext/src/ruby_api/externals.rs +113 -0
- data/ext/src/ruby_api/func.rs +388 -0
- data/ext/src/ruby_api/func_type.rs +139 -0
- data/ext/src/ruby_api/instance.rs +174 -0
- data/ext/src/ruby_api/linker.rs +296 -0
- data/ext/src/ruby_api/macros.rs +12 -0
- data/ext/src/ruby_api/memory.rs +142 -0
- data/ext/src/ruby_api/memory_type.rs +56 -0
- data/ext/src/ruby_api/mod.rs +48 -0
- data/ext/src/ruby_api/module.rs +107 -0
- data/ext/src/ruby_api/params.rs +42 -0
- data/ext/src/ruby_api/static_id.rs +57 -0
- data/ext/src/ruby_api/store.rs +182 -0
- data/ext/src/ruby_api/trap.rs +135 -0
- data/lib/wasmtime/version.rb +1 -1
- data/lib/wasmtime.rb +29 -4
- metadata +54 -30
- data/.cargo/config +0 -4
- data/CHANGELOG.md +0 -27
- data/ext/wasmtime/Makefile +0 -5
- data/ext/wasmtime/Rakefile +0 -3
- data/ext/wasmtime/extconf.rb +0 -5
- data/lib/tasks/compile.rake +0 -27
- data/lib/wasmtime/refinements.rb +0 -20
- data/lib/wasmtime/require.rb +0 -72
- data/src/export.rs +0 -19
- data/src/func.rs +0 -175
- data/src/instance.rs +0 -93
- data/src/lib.rs +0 -22
- data/src/memory.rs +0 -48
- data/src/ruby_type.rs +0 -32
- data/src/vm.rs +0 -6
@@ -0,0 +1,142 @@
|
|
1
|
+
use super::{
|
2
|
+
memory_type::MemoryType,
|
3
|
+
root,
|
4
|
+
store::{Store, StoreContextValue},
|
5
|
+
};
|
6
|
+
use crate::{error, helpers::WrappedStruct};
|
7
|
+
use magnus::{
|
8
|
+
function, memoize, method, r_string::RString, r_typed_data::DataTypeBuilder, DataTypeFunctions,
|
9
|
+
Error, Module as _, Object, RClass, TypedData,
|
10
|
+
};
|
11
|
+
use wasmtime::{Extern, Memory as MemoryImpl};
|
12
|
+
|
13
|
+
/// @yard
|
14
|
+
/// @rename Wasmtime::Memory
|
15
|
+
/// Represents a WebAssembly memory.
|
16
|
+
/// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Memory.html Wasmtime's Rust doc
|
17
|
+
#[derive(Debug)]
|
18
|
+
pub struct Memory<'a> {
|
19
|
+
store: StoreContextValue<'a>,
|
20
|
+
inner: MemoryImpl,
|
21
|
+
}
|
22
|
+
|
23
|
+
unsafe impl TypedData for Memory<'_> {
|
24
|
+
fn class() -> magnus::RClass {
|
25
|
+
*memoize!(RClass: root().define_class("Memory", Default::default()).unwrap())
|
26
|
+
}
|
27
|
+
|
28
|
+
fn data_type() -> &'static magnus::DataType {
|
29
|
+
memoize!(magnus::DataType: {
|
30
|
+
let mut builder = DataTypeBuilder::<Memory<'_>>::new("Wasmtime::Memory");
|
31
|
+
builder.free_immediately();
|
32
|
+
builder.build()
|
33
|
+
})
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
impl DataTypeFunctions for Memory<'_> {
|
38
|
+
fn mark(&self) {
|
39
|
+
self.store.mark()
|
40
|
+
}
|
41
|
+
}
|
42
|
+
unsafe impl Send for Memory<'_> {}
|
43
|
+
|
44
|
+
impl<'a> Memory<'a> {
|
45
|
+
/// @yard
|
46
|
+
/// @def new(store, memtype)
|
47
|
+
/// @param store [Store]
|
48
|
+
/// @param memtype [MemoryType]
|
49
|
+
pub fn new(s: WrappedStruct<Store>, memtype: &MemoryType) -> Result<Self, Error> {
|
50
|
+
let store = s.get()?;
|
51
|
+
|
52
|
+
let inner = MemoryImpl::new(store.context_mut(), memtype.get().clone())
|
53
|
+
.map_err(|e| error!("{}", e))?;
|
54
|
+
|
55
|
+
Ok(Self {
|
56
|
+
store: s.into(),
|
57
|
+
inner,
|
58
|
+
})
|
59
|
+
}
|
60
|
+
|
61
|
+
pub fn from_inner(store: StoreContextValue<'a>, inner: MemoryImpl) -> Self {
|
62
|
+
Self { store, inner }
|
63
|
+
}
|
64
|
+
|
65
|
+
/// @yard
|
66
|
+
/// Read +size+ bytes starting at +offset+.
|
67
|
+
///
|
68
|
+
/// @def read(offset, size)
|
69
|
+
/// @param offset [Integer]
|
70
|
+
/// @param size [Integer]
|
71
|
+
/// @return [String] Binary string of the memory.
|
72
|
+
pub fn read(&self, offset: usize, size: usize) -> Result<RString, Error> {
|
73
|
+
self.inner
|
74
|
+
.data(self.store.context()?)
|
75
|
+
.get(offset..)
|
76
|
+
.and_then(|s| s.get(..size))
|
77
|
+
.map(RString::from_slice)
|
78
|
+
.ok_or_else(|| error!("out of bounds memory access"))
|
79
|
+
}
|
80
|
+
|
81
|
+
/// @yard
|
82
|
+
/// Write +value+ starting at +offset+.
|
83
|
+
///
|
84
|
+
/// @def write(offset, value)
|
85
|
+
/// @param offset [Integer]
|
86
|
+
/// @param value [String]
|
87
|
+
/// @return [void]
|
88
|
+
pub fn write(&self, offset: usize, value: RString) -> Result<(), Error> {
|
89
|
+
let slice = unsafe { value.as_slice() };
|
90
|
+
|
91
|
+
self.inner
|
92
|
+
.write(self.store.context_mut()?, offset, slice)
|
93
|
+
.map_err(|e| error!("{}", e))
|
94
|
+
}
|
95
|
+
|
96
|
+
/// @yard
|
97
|
+
/// Grows a memory by +delta+ pages.
|
98
|
+
/// Raises if the memory grows beyond its limit.
|
99
|
+
///
|
100
|
+
/// @def grow(delta)
|
101
|
+
/// @param delta [Integer] The number of pages to grow by.
|
102
|
+
/// @return [Integer] The number of pages the memory had before being resized.
|
103
|
+
pub fn grow(&self, delta: u64) -> Result<u64, Error> {
|
104
|
+
self.inner
|
105
|
+
.grow(self.store.context_mut()?, delta)
|
106
|
+
.map_err(|e| error!("{}", e))
|
107
|
+
}
|
108
|
+
|
109
|
+
/// @yard
|
110
|
+
/// @return [Integer] The number of pages of the memory.
|
111
|
+
pub fn size(&self) -> Result<u64, Error> {
|
112
|
+
Ok(self.inner.size(self.store.context()?))
|
113
|
+
}
|
114
|
+
|
115
|
+
/// @yard
|
116
|
+
/// @return [MemoryType]
|
117
|
+
pub fn ty(&self) -> Result<MemoryType, Error> {
|
118
|
+
Ok(self.inner.ty(self.store.context()?).into())
|
119
|
+
}
|
120
|
+
|
121
|
+
pub fn get(&self) -> MemoryImpl {
|
122
|
+
self.inner
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
impl From<&Memory<'_>> for Extern {
|
127
|
+
fn from(memory: &Memory) -> Self {
|
128
|
+
Self::Memory(memory.get())
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
pub fn init() -> Result<(), Error> {
|
133
|
+
let class = root().define_class("Memory", Default::default())?;
|
134
|
+
class.define_singleton_method("new", function!(Memory::new, 2))?;
|
135
|
+
class.define_method("read", method!(Memory::read, 2))?;
|
136
|
+
class.define_method("write", method!(Memory::write, 2))?;
|
137
|
+
class.define_method("grow", method!(Memory::grow, 1))?;
|
138
|
+
class.define_method("size", method!(Memory::size, 0))?;
|
139
|
+
class.define_method("ty", method!(Memory::ty, 0))?;
|
140
|
+
|
141
|
+
Ok(())
|
142
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
use super::root;
|
2
|
+
use magnus::{function, method, scan_args, Error, Module as _, Object, Value};
|
3
|
+
use wasmtime::MemoryType as MemoryTypeImpl;
|
4
|
+
|
5
|
+
/// @yard
|
6
|
+
/// @see https://docs.rs/wasmtime/latest/wasmtime/struct.MemoryType.html Wasmtime's Rust doc
|
7
|
+
#[derive(Clone, Debug)]
|
8
|
+
#[magnus::wrap(class = "Wasmtime::MemoryType")]
|
9
|
+
pub struct MemoryType {
|
10
|
+
inner: MemoryTypeImpl,
|
11
|
+
}
|
12
|
+
|
13
|
+
impl MemoryType {
|
14
|
+
/// @yard
|
15
|
+
/// @def new(min, max = nil)
|
16
|
+
/// @param min [Integer] The minimum memory pages.
|
17
|
+
/// @param max [Integer, nil] The maximum memory pages.
|
18
|
+
pub fn new(args: &[Value]) -> Result<Self, Error> {
|
19
|
+
let args = scan_args::scan_args::<(u32,), (Option<u32>,), (), (), (), ()>(args)?;
|
20
|
+
let (min,) = args.required;
|
21
|
+
let (max,) = args.optional;
|
22
|
+
let inner = MemoryTypeImpl::new(min, max);
|
23
|
+
Ok(Self { inner })
|
24
|
+
}
|
25
|
+
|
26
|
+
pub fn get(&self) -> &MemoryTypeImpl {
|
27
|
+
&self.inner
|
28
|
+
}
|
29
|
+
|
30
|
+
/// @yard
|
31
|
+
/// @return [Integer] The minimum memory pages.
|
32
|
+
pub fn minimum(&self) -> u64 {
|
33
|
+
self.inner.minimum()
|
34
|
+
}
|
35
|
+
|
36
|
+
/// @yard
|
37
|
+
/// @return [Integer, nil] The maximum memory pages.
|
38
|
+
pub fn maximum(&self) -> Option<u64> {
|
39
|
+
self.inner.maximum()
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
pub fn init() -> Result<(), Error> {
|
44
|
+
let class = root().define_class("MemoryType", Default::default())?;
|
45
|
+
|
46
|
+
class.define_singleton_method("new", function!(MemoryType::new, -1))?;
|
47
|
+
class.define_method("minimum", method!(MemoryType::minimum, 0))?;
|
48
|
+
class.define_method("maximum", method!(MemoryType::maximum, 0))?;
|
49
|
+
Ok(())
|
50
|
+
}
|
51
|
+
|
52
|
+
impl From<MemoryTypeImpl> for MemoryType {
|
53
|
+
fn from(inner: MemoryTypeImpl) -> Self {
|
54
|
+
Self { inner }
|
55
|
+
}
|
56
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#![allow(rustdoc::broken_intra_doc_links)]
|
2
|
+
#![allow(rustdoc::invalid_html_tags)]
|
3
|
+
#![allow(rustdoc::bare_urls)]
|
4
|
+
#![allow(rustdoc::invalid_rust_codeblocks)]
|
5
|
+
use magnus::{define_module, memoize, Error, RModule};
|
6
|
+
|
7
|
+
mod config;
|
8
|
+
mod convert;
|
9
|
+
mod engine;
|
10
|
+
mod errors;
|
11
|
+
mod externals;
|
12
|
+
mod func;
|
13
|
+
mod func_type;
|
14
|
+
mod instance;
|
15
|
+
mod linker;
|
16
|
+
mod macros;
|
17
|
+
mod memory;
|
18
|
+
mod memory_type;
|
19
|
+
mod module;
|
20
|
+
mod params;
|
21
|
+
mod static_id;
|
22
|
+
mod store;
|
23
|
+
mod trap;
|
24
|
+
|
25
|
+
/// The "Wasmtime" Ruby module.
|
26
|
+
pub fn root() -> RModule {
|
27
|
+
*memoize!(RModule: define_module("Wasmtime").unwrap())
|
28
|
+
}
|
29
|
+
|
30
|
+
pub fn init() -> Result<(), Error> {
|
31
|
+
let _ = root();
|
32
|
+
|
33
|
+
errors::init()?;
|
34
|
+
trap::init()?;
|
35
|
+
config::init()?;
|
36
|
+
engine::init()?;
|
37
|
+
module::init()?;
|
38
|
+
store::init()?;
|
39
|
+
instance::init()?;
|
40
|
+
func::init()?;
|
41
|
+
func_type::init()?;
|
42
|
+
memory_type::init()?;
|
43
|
+
memory::init()?;
|
44
|
+
linker::init()?;
|
45
|
+
externals::init()?;
|
46
|
+
|
47
|
+
Ok(())
|
48
|
+
}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
use super::{engine::Engine, root};
|
2
|
+
use crate::error;
|
3
|
+
use magnus::{function, method, Error, Module as _, Object, RString};
|
4
|
+
use wasmtime::Module as ModuleImpl;
|
5
|
+
|
6
|
+
/// @yard
|
7
|
+
/// Represents a WebAssembly module.
|
8
|
+
/// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Module.html Wasmtime's Rust doc
|
9
|
+
#[derive(Clone)]
|
10
|
+
#[magnus::wrap(class = "Wasmtime::Module", size, free_immediatly)]
|
11
|
+
pub struct Module {
|
12
|
+
inner: ModuleImpl,
|
13
|
+
}
|
14
|
+
|
15
|
+
impl Module {
|
16
|
+
/// @yard
|
17
|
+
/// @def new(engine, wat_or_wasm)
|
18
|
+
/// @param engine [Wasmtime::Engine]
|
19
|
+
/// @param wat_or_wasm [String] The String of WAT or Wasm.
|
20
|
+
/// @return [Wasmtime::Module]
|
21
|
+
pub fn new(engine: &Engine, wat_or_wasm: RString) -> Result<Self, Error> {
|
22
|
+
let eng = engine.get();
|
23
|
+
// SAFETY: this string is immediately copied and never moved off the stack
|
24
|
+
let module = ModuleImpl::new(eng, unsafe { wat_or_wasm.as_slice() })
|
25
|
+
.map_err(|e| error!("Could not build module from file: {:?}", e.to_string()))?;
|
26
|
+
|
27
|
+
Ok(Self { inner: module })
|
28
|
+
}
|
29
|
+
|
30
|
+
/// @yard
|
31
|
+
/// @def from_file(engine, path)
|
32
|
+
/// @param engine [Wasmtime::Engine]
|
33
|
+
/// @param path [String]
|
34
|
+
/// @return [Wasmtime::Module]
|
35
|
+
pub fn from_file(engine: &Engine, path: RString) -> Result<Self, Error> {
|
36
|
+
let eng = engine.get();
|
37
|
+
// SAFETY: this string is immediately copied and never moved off the stack
|
38
|
+
let module = ModuleImpl::from_file(eng, unsafe { path.as_str()? })
|
39
|
+
.map_err(|e| error!("Could not build module: {:?}", e.to_string()))?;
|
40
|
+
|
41
|
+
Ok(Self { inner: module })
|
42
|
+
}
|
43
|
+
|
44
|
+
/// @yard
|
45
|
+
/// Instantiates a serialized module coming from either {#serialize} or {Wasmtime::Engine#precompile_module}.
|
46
|
+
///
|
47
|
+
/// The engine serializing and the engine deserializing must:
|
48
|
+
/// * have the same configuration
|
49
|
+
/// * be of the same gem version
|
50
|
+
///
|
51
|
+
/// @def deserialize(engine, compiled)
|
52
|
+
/// @param engine [Wasmtime::Engine]
|
53
|
+
/// @param compiled [String] String obtained with either {Wasmtime::Engine#precompile_module} or {#serialize}.
|
54
|
+
/// @return [Wasmtime::Module]
|
55
|
+
pub fn deserialize(engine: &Engine, compiled: RString) -> Result<Self, Error> {
|
56
|
+
// SAFETY: this string is immediately copied and never moved off the stack
|
57
|
+
unsafe { ModuleImpl::deserialize(engine.get(), compiled.as_slice()) }
|
58
|
+
.map(|module| Self { inner: module })
|
59
|
+
.map_err(|e| error!("Could not deserialize module: {:?}", e.to_string()))
|
60
|
+
}
|
61
|
+
|
62
|
+
/// @yard
|
63
|
+
/// Instantiates a serialized module from a file.
|
64
|
+
///
|
65
|
+
/// @def deserialize_file(engine, path)
|
66
|
+
/// @param engine [Wasmtime::Engine]
|
67
|
+
/// @param path [String]
|
68
|
+
/// @return [Wasmtime::Module]
|
69
|
+
/// @see .deserialize
|
70
|
+
pub fn deserialize_file(engine: &Engine, path: RString) -> Result<Self, Error> {
|
71
|
+
unsafe { ModuleImpl::deserialize_file(engine.get(), path.as_str()?) }
|
72
|
+
.map(|module| Self { inner: module })
|
73
|
+
.map_err(|e| {
|
74
|
+
error!(
|
75
|
+
"Could not deserialize module from file: {:?}",
|
76
|
+
e.to_string()
|
77
|
+
)
|
78
|
+
})
|
79
|
+
}
|
80
|
+
|
81
|
+
/// @yard
|
82
|
+
/// Serialize the module.
|
83
|
+
/// @return [String]
|
84
|
+
/// @see .deserialize
|
85
|
+
pub fn serialize(&self) -> Result<RString, Error> {
|
86
|
+
self.get()
|
87
|
+
.serialize()
|
88
|
+
.map(|bytes| RString::from_slice(&bytes))
|
89
|
+
.map_err(|e| error!("{:?}", e))
|
90
|
+
}
|
91
|
+
|
92
|
+
pub fn get(&self) -> &ModuleImpl {
|
93
|
+
&self.inner
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
pub fn init() -> Result<(), Error> {
|
98
|
+
let class = root().define_class("Module", Default::default())?;
|
99
|
+
|
100
|
+
class.define_singleton_method("new", function!(Module::new, 2))?;
|
101
|
+
class.define_singleton_method("from_file", function!(Module::from_file, 2))?;
|
102
|
+
class.define_singleton_method("deserialize", function!(Module::deserialize, 2))?;
|
103
|
+
class.define_singleton_method("deserialize_file", function!(Module::deserialize_file, 2))?;
|
104
|
+
class.define_method("serialize", method!(Module::serialize, 0))?;
|
105
|
+
|
106
|
+
Ok(())
|
107
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
use super::convert::ToWasmVal;
|
2
|
+
use crate::err;
|
3
|
+
use magnus::{Error, Value};
|
4
|
+
use wasmtime::ValType;
|
5
|
+
|
6
|
+
#[derive(Debug)]
|
7
|
+
pub struct ParamTuple<'a>(ValType, &'a Value);
|
8
|
+
|
9
|
+
impl<'a> ParamTuple<'a> {
|
10
|
+
pub fn new(ty: ValType, val: &'a Value) -> Self {
|
11
|
+
Self(ty, val)
|
12
|
+
}
|
13
|
+
|
14
|
+
fn to_wasmtime_val(&self) -> Result<wasmtime::Val, Error> {
|
15
|
+
self.1.to_wasm_val(&self.0)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
pub struct Params<'a>(Vec<ValType>, &'a [Value]);
|
20
|
+
|
21
|
+
impl<'a> Params<'a> {
|
22
|
+
pub fn new(params_slice: &'a [Value], param_types: Vec<ValType>) -> Result<Self, Error> {
|
23
|
+
if param_types.len() != params_slice.len() {
|
24
|
+
return err!(
|
25
|
+
"/wrong number of arguments (given {}, expected {})",
|
26
|
+
params_slice.len(),
|
27
|
+
param_types.len()
|
28
|
+
);
|
29
|
+
}
|
30
|
+
Ok(Self(param_types, params_slice))
|
31
|
+
}
|
32
|
+
|
33
|
+
pub fn to_vec(&self) -> Result<Vec<wasmtime::Val>, Error> {
|
34
|
+
let mut vals = Vec::with_capacity(self.0.len());
|
35
|
+
let mut values_iter = self.1.iter();
|
36
|
+
for param in &self.0 {
|
37
|
+
let tuple = ParamTuple::new(param.clone(), values_iter.next().unwrap());
|
38
|
+
vals.push(tuple.to_wasmtime_val()?);
|
39
|
+
}
|
40
|
+
Ok(vals)
|
41
|
+
}
|
42
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
use magnus::rb_sys::{AsRawId, FromRawId};
|
2
|
+
use magnus::{value::Id, Symbol};
|
3
|
+
use std::convert::TryInto;
|
4
|
+
use std::num::NonZeroUsize;
|
5
|
+
|
6
|
+
/// A static `Id` that can be used to refer to a Ruby ID.
|
7
|
+
///
|
8
|
+
/// Use `define_rb_intern!` to define it so that it will be cached in a global variable.
|
9
|
+
///
|
10
|
+
/// Magnus' `Id` can't be used for this purpose since it is not `Sync`, so cannot
|
11
|
+
/// be used as a global variable with `lazy_static` in `define_rb_intern!`.
|
12
|
+
/// See [this commit on the Magnus repo][commit].
|
13
|
+
///
|
14
|
+
/// [commit]: https://github.com/matsadler/magnus/commit/1a1c1ee874e15b0b222f7aae68bb9b5360072e57
|
15
|
+
///
|
16
|
+
/// ```rust
|
17
|
+
/// # use magnus::{embed, Module, RClass, RString};
|
18
|
+
/// # use liquid_wasm::ruby_api::StaticId;
|
19
|
+
/// # use liquid_wasm::define_rb_intern;
|
20
|
+
/// # let _cleanup = unsafe { embed::init() };
|
21
|
+
/// define_rb_intern!(
|
22
|
+
/// NAME => "name",
|
23
|
+
/// );
|
24
|
+
///
|
25
|
+
/// let string_class = magnus::class::object().const_get::<_, RClass>("String").unwrap();
|
26
|
+
/// let result: RString = string_class.funcall(*NAME, ()).unwrap();
|
27
|
+
///
|
28
|
+
/// assert_eq!(result.to_string().unwrap(), "String");
|
29
|
+
/// ```
|
30
|
+
#[derive(Clone, Copy)]
|
31
|
+
#[repr(transparent)]
|
32
|
+
pub struct StaticId(NonZeroUsize);
|
33
|
+
|
34
|
+
impl StaticId {
|
35
|
+
// Use `define_rb_intern!` instead, which uses this function.
|
36
|
+
pub fn intern_str(id: &'static str) -> Self {
|
37
|
+
let id: Id = magnus::StaticSymbol::new(id).into();
|
38
|
+
|
39
|
+
// SAFETY: Ruby will never return a `0` ID.
|
40
|
+
StaticId(unsafe { NonZeroUsize::new_unchecked(id.as_raw() as _) })
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
impl From<StaticId> for Id {
|
45
|
+
fn from(static_id: StaticId) -> Self {
|
46
|
+
// SAFEFY: This is safe because we know that the `Id` is something
|
47
|
+
// returned from ruby.
|
48
|
+
unsafe { Id::from_raw(static_id.0.get().try_into().expect("ID to be a usize")) }
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
impl From<StaticId> for Symbol {
|
53
|
+
fn from(static_id: StaticId) -> Self {
|
54
|
+
let id: Id = static_id.into();
|
55
|
+
id.into()
|
56
|
+
}
|
57
|
+
}
|
@@ -0,0 +1,182 @@
|
|
1
|
+
use super::{engine::Engine, func::Caller, root, trap::Trap};
|
2
|
+
use crate::{error, helpers::WrappedStruct};
|
3
|
+
use magnus::{
|
4
|
+
exception::Exception, function, method, scan_args, value::BoxValue, DataTypeFunctions, Error,
|
5
|
+
Module, Object, TypedData, Value, QNIL,
|
6
|
+
};
|
7
|
+
use std::cell::{RefCell, UnsafeCell};
|
8
|
+
use std::convert::TryFrom;
|
9
|
+
use wasmtime::{AsContext, AsContextMut, Store as StoreImpl, StoreContext, StoreContextMut};
|
10
|
+
|
11
|
+
#[derive(Debug)]
|
12
|
+
pub struct StoreData {
|
13
|
+
user_data: Value,
|
14
|
+
host_exception: HostException,
|
15
|
+
}
|
16
|
+
|
17
|
+
type BoxedException = BoxValue<Exception>;
|
18
|
+
#[derive(Debug, Default)]
|
19
|
+
pub struct HostException(Option<BoxedException>);
|
20
|
+
impl HostException {
|
21
|
+
pub fn take(&mut self) -> Option<Exception> {
|
22
|
+
std::mem::take(&mut self.0).map(|e| e.to_owned())
|
23
|
+
}
|
24
|
+
|
25
|
+
pub fn hold(&mut self, e: Exception) {
|
26
|
+
self.0 = Some(BoxValue::new(e));
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
impl StoreData {
|
31
|
+
pub fn exception(&mut self) -> &mut HostException {
|
32
|
+
&mut self.host_exception
|
33
|
+
}
|
34
|
+
|
35
|
+
pub fn take_last_error(&mut self) -> Option<Error> {
|
36
|
+
self.host_exception.take().map(Error::from)
|
37
|
+
}
|
38
|
+
|
39
|
+
pub fn user_data(&self) -> Value {
|
40
|
+
self.user_data
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
/// @yard
|
45
|
+
/// Represents a WebAssebmly store.
|
46
|
+
/// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html Wasmtime's Rust doc
|
47
|
+
#[derive(Debug, TypedData)]
|
48
|
+
#[magnus(class = "Wasmtime::Store", size, mark, free_immediatly)]
|
49
|
+
pub struct Store {
|
50
|
+
inner: UnsafeCell<StoreImpl<StoreData>>,
|
51
|
+
refs: RefCell<Vec<Value>>,
|
52
|
+
}
|
53
|
+
|
54
|
+
impl DataTypeFunctions for Store {
|
55
|
+
fn mark(&self) {
|
56
|
+
self.refs.borrow().iter().for_each(magnus::gc::mark);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
unsafe impl Send for Store {}
|
61
|
+
unsafe impl Send for StoreData {}
|
62
|
+
|
63
|
+
impl Store {
|
64
|
+
/// @yard
|
65
|
+
///
|
66
|
+
/// @def new(engine, data = nil)
|
67
|
+
/// @param engine [Wasmtime::Engine]
|
68
|
+
/// The engine for this store.
|
69
|
+
/// @param data [Object]
|
70
|
+
/// The data attached to the store. Can be retrieved through {Wasmtime::Store#data} and {Wasmtime::Caller#data}.
|
71
|
+
/// @return [Wasmtime::Store]
|
72
|
+
///
|
73
|
+
/// @example
|
74
|
+
/// store = Wasmtime::Store.new(Wasmtime::Engine.new)
|
75
|
+
///
|
76
|
+
/// @example
|
77
|
+
/// store = Wasmtime::Store.new(Wasmtime::Engine.new, {})
|
78
|
+
pub fn new(args: &[Value]) -> Result<Self, Error> {
|
79
|
+
let args = scan_args::scan_args::<(&Engine,), (Option<Value>,), (), (), (), ()>(args)?;
|
80
|
+
let (engine,) = args.required;
|
81
|
+
let (user_data,) = args.optional;
|
82
|
+
let user_data = user_data.unwrap_or_else(|| QNIL.into());
|
83
|
+
|
84
|
+
let eng = engine.get();
|
85
|
+
let store_data = StoreData {
|
86
|
+
user_data,
|
87
|
+
host_exception: HostException::default(),
|
88
|
+
};
|
89
|
+
let store = Self {
|
90
|
+
inner: UnsafeCell::new(StoreImpl::new(eng, store_data)),
|
91
|
+
refs: Default::default(),
|
92
|
+
};
|
93
|
+
|
94
|
+
store.retain(user_data);
|
95
|
+
|
96
|
+
Ok(store)
|
97
|
+
}
|
98
|
+
|
99
|
+
/// @yard
|
100
|
+
/// @return [Object] The passed in value in {.new}
|
101
|
+
pub fn data(&self) -> Value {
|
102
|
+
self.context().data().user_data()
|
103
|
+
}
|
104
|
+
|
105
|
+
pub fn context(&self) -> StoreContext<StoreData> {
|
106
|
+
unsafe { (*self.inner.get()).as_context() }
|
107
|
+
}
|
108
|
+
|
109
|
+
pub fn context_mut(&self) -> StoreContextMut<StoreData> {
|
110
|
+
unsafe { (*self.inner.get()).as_context_mut() }
|
111
|
+
}
|
112
|
+
|
113
|
+
pub fn retain(&self, value: Value) {
|
114
|
+
self.refs.borrow_mut().push(value);
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
/// A wrapper around a Ruby Value that has a store context.
|
119
|
+
/// Used in places where both Store or Caller can be used.
|
120
|
+
#[derive(Debug, Clone, Copy)]
|
121
|
+
pub enum StoreContextValue<'a> {
|
122
|
+
Store(WrappedStruct<Store>),
|
123
|
+
Caller(WrappedStruct<Caller<'a>>),
|
124
|
+
}
|
125
|
+
|
126
|
+
impl<'a> From<WrappedStruct<Store>> for StoreContextValue<'a> {
|
127
|
+
fn from(store: WrappedStruct<Store>) -> Self {
|
128
|
+
StoreContextValue::Store(store)
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
impl<'a> From<WrappedStruct<Caller<'a>>> for StoreContextValue<'a> {
|
133
|
+
fn from(caller: WrappedStruct<Caller<'a>>) -> Self {
|
134
|
+
StoreContextValue::Caller(caller)
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
impl<'a> StoreContextValue<'a> {
|
139
|
+
pub fn mark(&self) {
|
140
|
+
match self {
|
141
|
+
Self::Store(store) => store.mark(),
|
142
|
+
Self::Caller(_) => {
|
143
|
+
// The Caller is on the stack while it's "live". Right before the end of a host call,
|
144
|
+
// we remove the Caller form the Ruby object, thus there is no need to mark.
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
pub fn context(&self) -> Result<StoreContext<StoreData>, Error> {
|
150
|
+
match self {
|
151
|
+
Self::Store(store) => Ok(store.get()?.context()),
|
152
|
+
Self::Caller(caller) => caller.get()?.context(),
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
pub fn context_mut(&self) -> Result<StoreContextMut<StoreData>, Error> {
|
157
|
+
match self {
|
158
|
+
Self::Store(store) => Ok(store.get()?.context_mut()),
|
159
|
+
Self::Caller(caller) => caller.get()?.context_mut(),
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
pub fn handle_wasm_error(&self, error: anyhow::Error) -> Error {
|
164
|
+
match self.context_mut() {
|
165
|
+
Ok(mut context) => context.data_mut().take_last_error().unwrap_or_else(|| {
|
166
|
+
Trap::try_from(error)
|
167
|
+
.map(|trap| trap.into())
|
168
|
+
.unwrap_or_else(|e| error!("{}", e))
|
169
|
+
}),
|
170
|
+
Err(e) => e,
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
pub fn init() -> Result<(), Error> {
|
176
|
+
let class = root().define_class("Store", Default::default())?;
|
177
|
+
|
178
|
+
class.define_singleton_method("new", function!(Store::new, -1))?;
|
179
|
+
class.define_method("data", method!(Store::data, 0))?;
|
180
|
+
|
181
|
+
Ok(())
|
182
|
+
}
|