wasmtime 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +941 -627
  3. data/Cargo.toml +2 -14
  4. data/LICENSE +23 -21
  5. data/README.md +47 -118
  6. data/ext/Cargo.toml +17 -0
  7. data/ext/extconf.rb +6 -0
  8. data/ext/src/helpers/mod.rs +3 -0
  9. data/ext/src/helpers/wrapped_struct.rs +84 -0
  10. data/ext/src/lib.rs +9 -0
  11. data/ext/src/ruby_api/config.rs +68 -0
  12. data/ext/src/ruby_api/convert.rs +92 -0
  13. data/ext/src/ruby_api/engine.rs +66 -0
  14. data/ext/src/ruby_api/errors.rs +56 -0
  15. data/ext/src/ruby_api/externals.rs +113 -0
  16. data/ext/src/ruby_api/func.rs +388 -0
  17. data/ext/src/ruby_api/func_type.rs +139 -0
  18. data/ext/src/ruby_api/instance.rs +174 -0
  19. data/ext/src/ruby_api/linker.rs +296 -0
  20. data/ext/src/ruby_api/macros.rs +12 -0
  21. data/ext/src/ruby_api/memory.rs +142 -0
  22. data/ext/src/ruby_api/memory_type.rs +56 -0
  23. data/ext/src/ruby_api/mod.rs +48 -0
  24. data/ext/src/ruby_api/module.rs +107 -0
  25. data/ext/src/ruby_api/params.rs +42 -0
  26. data/ext/src/ruby_api/static_id.rs +57 -0
  27. data/ext/src/ruby_api/store.rs +182 -0
  28. data/ext/src/ruby_api/trap.rs +135 -0
  29. data/lib/wasmtime/version.rb +1 -1
  30. data/lib/wasmtime.rb +29 -4
  31. metadata +54 -30
  32. data/.cargo/config +0 -4
  33. data/CHANGELOG.md +0 -27
  34. data/ext/wasmtime/Makefile +0 -5
  35. data/ext/wasmtime/Rakefile +0 -3
  36. data/ext/wasmtime/extconf.rb +0 -5
  37. data/lib/tasks/compile.rake +0 -27
  38. data/lib/wasmtime/refinements.rb +0 -20
  39. data/lib/wasmtime/require.rb +0 -72
  40. data/src/export.rs +0 -19
  41. data/src/func.rs +0 -175
  42. data/src/instance.rs +0 -93
  43. data/src/lib.rs +0 -22
  44. data/src/memory.rs +0 -48
  45. data/src/ruby_type.rs +0 -32
  46. data/src/vm.rs +0 -6
@@ -0,0 +1,66 @@
1
+ use super::{config::Config, root};
2
+ use crate::error;
3
+ use magnus::{function, method, scan_args, Error, Module, Object, RString, Value};
4
+ use wasmtime::Engine as EngineImpl;
5
+
6
+ /// @yard
7
+ /// Represents a Wasmtime execution engine.
8
+ /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Engine.html Wasmtime's Rust doc
9
+ #[derive(Clone)]
10
+ #[magnus::wrap(class = "Wasmtime::Engine")]
11
+ pub struct Engine {
12
+ inner: EngineImpl,
13
+ }
14
+
15
+ impl Engine {
16
+ /// @yard
17
+ /// @def new(config)
18
+ /// @param config [Configuration]
19
+ pub fn new(args: &[Value]) -> Result<Self, Error> {
20
+ let args = scan_args::scan_args::<(), (Option<Value>,), (), (), (), ()>(args)?;
21
+ let (config,) = args.optional;
22
+ let config = config.and_then(|v| if v.is_nil() { None } else { Some(v) });
23
+ let inner = match config {
24
+ Some(config) => EngineImpl::new(&config.try_convert::<&Config>()?.get())
25
+ .map_err(|e| error!("{}", e))?,
26
+ None => EngineImpl::default(),
27
+ };
28
+
29
+ Ok(Self { inner })
30
+ }
31
+
32
+ pub fn get(&self) -> &EngineImpl {
33
+ &self.inner
34
+ }
35
+
36
+ pub fn is_equal(&self, other: &Engine) -> bool {
37
+ EngineImpl::same(self.get(), other.get())
38
+ }
39
+
40
+ /// @yard
41
+ /// AoT compile a WebAssembly text or WebAssembly binary module for later use.
42
+ ///
43
+ /// The compiled module can be instantiated using {Module.deserialize}.
44
+ ///
45
+ /// @def precompile_module(wat_or_wasm)
46
+ /// @param wat_or_wasm [String] The String of WAT or Wasm.
47
+ /// @return [String] Binary String of the compiled module.
48
+ /// @see Module.deserialize
49
+ pub fn precompile_module(&self, wat_or_wasm: RString) -> Result<RString, Error> {
50
+ self.inner
51
+ .precompile_module(unsafe { wat_or_wasm.as_slice() })
52
+ .map(|bytes| RString::from_slice(&bytes))
53
+ .map_err(|e| error!("{}", e.to_string()))
54
+ }
55
+ }
56
+
57
+ pub fn init() -> Result<(), Error> {
58
+ let class = root().define_class("Engine", Default::default())?;
59
+
60
+ class.define_singleton_method("new", function!(Engine::new, -1))?;
61
+
62
+ class.define_method("==", method!(Engine::is_equal, 1))?;
63
+ class.define_method("precompile_module", method!(Engine::precompile_module, 1))?;
64
+
65
+ Ok(())
66
+ }
@@ -0,0 +1,56 @@
1
+ use crate::ruby_api::root;
2
+ use magnus::rb_sys::FromRawValue;
3
+ use magnus::{exception::standard_error, memoize, ExceptionClass, Module};
4
+ use magnus::{Error, Value};
5
+
6
+ /// Base error class for all Wasmtime errors.
7
+ pub fn base_error() -> ExceptionClass {
8
+ *memoize!(ExceptionClass: root().define_error("Error", standard_error()).unwrap())
9
+ }
10
+
11
+ /// Ruby's `NotImplementedError` class.
12
+ pub fn not_implemented_error() -> ExceptionClass {
13
+ *memoize!(ExceptionClass: {
14
+ Value::from_raw(rb_sys::rb_eNotImpError).try_convert().unwrap()
15
+ })
16
+ }
17
+
18
+ /// The `Wasmtime::ConversionError` class.
19
+ pub fn conversion_error() -> ExceptionClass {
20
+ *memoize!(ExceptionClass: root().define_error("ConversionError", base_error()).unwrap())
21
+ }
22
+
23
+ #[macro_export]
24
+ macro_rules! err {
25
+ ($($arg:expr),*) => {
26
+ Result::Err($crate::error!($($arg),*))
27
+ };
28
+ }
29
+
30
+ #[macro_export]
31
+ macro_rules! error {
32
+ ($($arg:expr),*) => {
33
+ Error::new($crate::ruby_api::errors::base_error(), format!($($arg),*))
34
+ };
35
+ }
36
+
37
+ #[macro_export]
38
+ macro_rules! not_implemented {
39
+ ($($arg:expr),*) => {
40
+ Err(Error::new($crate::ruby_api::errors::not_implemented_error(), format!($($arg),*)))
41
+ };
42
+ }
43
+
44
+ #[macro_export]
45
+ macro_rules! conversion_err {
46
+ ($($arg:expr),*) => {
47
+ Err(Error::new($crate::ruby_api::errors::conversion_error(), format!("cannot convert {} to {}", $($arg),*)))
48
+ };
49
+ }
50
+
51
+ pub fn init() -> Result<(), Error> {
52
+ let _ = base_error();
53
+ let _ = conversion_error();
54
+
55
+ Ok(())
56
+ }
@@ -0,0 +1,113 @@
1
+ use super::{
2
+ convert::WrapWasmtimeType, func::Func, memory::Memory, root, store::StoreContextValue,
3
+ };
4
+ use crate::{conversion_err, helpers::WrappedStruct, not_implemented};
5
+ use magnus::{
6
+ memoize, method, r_typed_data::DataTypeBuilder, rb_sys::AsRawValue, DataTypeFunctions, Error,
7
+ Module, RClass, TypedData, Value,
8
+ };
9
+
10
+ /// @yard
11
+ /// @rename Wasmtime::Extern
12
+ /// An external item to a WebAssembly module, or a list of what can possibly be exported from a Wasm module.
13
+ /// @see https://docs.rs/wasmtime/latest/wasmtime/enum.Extern.html Wasmtime's Rust doc
14
+ pub enum Extern<'a> {
15
+ Func(WrappedStruct<Func<'a>>),
16
+ Memory(WrappedStruct<Memory<'a>>),
17
+ }
18
+
19
+ unsafe impl TypedData for Extern<'_> {
20
+ fn class() -> magnus::RClass {
21
+ *memoize!(RClass: root().define_class("Extern", Default::default()).unwrap())
22
+ }
23
+
24
+ fn data_type() -> &'static magnus::DataType {
25
+ memoize!(magnus::DataType: {
26
+ let mut builder = DataTypeBuilder::<Extern<'_>>::new("Wasmtime::Extern");
27
+ builder.size();
28
+ builder.mark();
29
+ builder.free_immediately();
30
+ builder.build()
31
+ })
32
+ }
33
+ }
34
+
35
+ impl DataTypeFunctions for Extern<'_> {
36
+ fn mark(&self) {
37
+ match self {
38
+ Extern::Func(f) => f.mark(),
39
+ Extern::Memory(m) => m.mark(),
40
+ }
41
+ }
42
+ }
43
+ unsafe impl Send for Extern<'_> {}
44
+
45
+ impl Extern<'_> {
46
+ /// @yard
47
+ /// Returns the exported function or raises a `{ConversionError}` when the export is not a
48
+ /// function.
49
+ /// @return [Func] The exported function.
50
+ pub fn to_func(rb_self: WrappedStruct<Self>) -> Result<Value, Error> {
51
+ match rb_self.get()? {
52
+ Extern::Func(f) => Ok(f.to_value()),
53
+ _ => conversion_err!(Self::inner_class(rb_self)?, Func::class()),
54
+ }
55
+ }
56
+
57
+ /// @yard
58
+ /// Returns the exported memory or raises a `{ConversionError}` when the export is not a
59
+ /// memory.
60
+ /// @return [Memory] The exported memory.
61
+ pub fn to_memory(rb_self: WrappedStruct<Self>) -> Result<Value, Error> {
62
+ match rb_self.get()? {
63
+ Extern::Memory(f) => Ok(f.to_value()),
64
+ _ => conversion_err!(Self::inner_class(rb_self)?, Memory::class()),
65
+ }
66
+ }
67
+
68
+ pub fn inspect(rb_self: WrappedStruct<Self>) -> Result<String, Error> {
69
+ let rs_self = rb_self.get()?;
70
+
71
+ let inner_string: String = match rs_self {
72
+ Extern::Func(f) => f.inspect(),
73
+ Extern::Memory(m) => m.inspect(),
74
+ };
75
+
76
+ Ok(format!(
77
+ "#<Wasmtime::Extern:0x{:016x} @value={}>",
78
+ rb_self.to_value().as_raw(),
79
+ inner_string
80
+ ))
81
+ }
82
+
83
+ fn inner_class(rb_self: WrappedStruct<Self>) -> Result<RClass, Error> {
84
+ match rb_self.get()? {
85
+ Extern::Func(f) => Ok(f.to_value().class()),
86
+ Extern::Memory(m) => Ok(m.to_value().class()),
87
+ }
88
+ }
89
+ }
90
+
91
+ impl<'a> WrapWasmtimeType<'a, Extern<'a>> for wasmtime::Extern {
92
+ fn wrap_wasmtime_type(&self, store: StoreContextValue<'a>) -> Result<Extern<'a>, Error> {
93
+ match self {
94
+ wasmtime::Extern::Func(func) => Ok(Extern::Func(Func::from_inner(store, *func).into())),
95
+ wasmtime::Extern::Memory(mem) => {
96
+ Ok(Extern::Memory(Memory::from_inner(store, *mem).into()))
97
+ }
98
+ wasmtime::Extern::Global(_) => not_implemented!("global not yet supported"),
99
+ wasmtime::Extern::Table(_) => not_implemented!("table not yet supported"),
100
+ wasmtime::Extern::SharedMemory(_) => not_implemented!("shared memory not supported"),
101
+ }
102
+ }
103
+ }
104
+
105
+ pub fn init() -> Result<(), Error> {
106
+ let class = root().define_class("Extern", Default::default())?;
107
+
108
+ class.define_method("to_func", method!(Extern::to_func, 0))?;
109
+ class.define_method("to_memory", method!(Extern::to_memory, 0))?;
110
+ class.define_method("inspect", method!(Extern::inspect, 0))?;
111
+
112
+ Ok(())
113
+ }
@@ -0,0 +1,388 @@
1
+ use super::{
2
+ convert::{ToRubyValue, ToWasmVal, WrapWasmtimeType},
3
+ externals::Extern,
4
+ func_type::FuncType,
5
+ params::Params,
6
+ root,
7
+ store::{Store, StoreContextValue, StoreData},
8
+ };
9
+ use crate::{error, helpers::WrappedStruct};
10
+ use magnus::{
11
+ block::Proc, function, memoize, method, r_typed_data::DataTypeBuilder, scan_args::scan_args,
12
+ value::BoxValue, DataTypeFunctions, Error, Exception, Module as _, Object, RArray, RClass,
13
+ RString, TryConvert, TypedData, Value, QNIL,
14
+ };
15
+ use std::cell::UnsafeCell;
16
+ use wasmtime::{
17
+ AsContext, AsContextMut, Caller as CallerImpl, Func as FuncImpl, StoreContext, StoreContextMut,
18
+ Val,
19
+ };
20
+
21
+ /// @yard
22
+ /// @rename Wasmtime::Func
23
+ /// Represents a WebAssembly Function
24
+ /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Func.html Wasmtime's Rust doc
25
+ #[derive(Debug)]
26
+ pub struct Func<'a> {
27
+ store: StoreContextValue<'a>,
28
+ inner: FuncImpl,
29
+ }
30
+
31
+ unsafe impl<'a> TypedData for Func<'a> {
32
+ fn class() -> magnus::RClass {
33
+ *memoize!(RClass: root().define_class("Func", Default::default()).unwrap())
34
+ }
35
+
36
+ fn data_type() -> &'static magnus::DataType {
37
+ memoize!(magnus::DataType: {
38
+ let mut builder = DataTypeBuilder::<Func<'_>>::new("Wasmtime::Func");
39
+ builder.size();
40
+ builder.mark();
41
+ builder.free_immediately();
42
+ builder.build()
43
+ })
44
+ }
45
+ }
46
+
47
+ impl DataTypeFunctions for Func<'_> {
48
+ fn mark(&self) {
49
+ self.store.mark()
50
+ }
51
+ }
52
+
53
+ // Wraps a Proc to satisfy wasmtime::Func's Send+Sync requirements. This is safe
54
+ // to do as long as (1) we hold the GVL when whe execute the proc and (2) we do
55
+ // not have multiple threads running at once (e.g. with Wasm thread proposal).
56
+ #[repr(transparent)]
57
+ struct ShareableProc(Proc);
58
+ unsafe impl Send for ShareableProc {}
59
+ unsafe impl Sync for ShareableProc {}
60
+
61
+ unsafe impl Send for Func<'_> {}
62
+
63
+ impl<'a> Func<'a> {
64
+ /// @yard
65
+ /// @def new(store, type, callable, &block)
66
+ /// @param store [Store]
67
+ /// @param type [FuncType]
68
+ /// @param block [Block] The funcs's implementation
69
+ ///
70
+ /// @yield [caller, *args] The function's body
71
+ /// @yieldparam caller [Caller] Caller which can be used to interact with the {Store}.
72
+ /// @yieldparam *args [Object] Splat of Ruby objects matching the {FuncType}’s params arity.
73
+ /// @yieldreturn [nil, Object, Array<Object>] The return type depends on {FuncType}’s results arity:
74
+ /// * 0 => +nil+
75
+ /// * 1 => +Object+
76
+ /// * > 1 => +Array<Object>+
77
+ ///
78
+ /// @return [Func]
79
+ ///
80
+ /// @example Function that increments an i32:
81
+ /// store = Wasmtime::Store.new(Wasmtime::Engine.new)
82
+ /// type = FuncType.new([:i32], [:i32])
83
+ /// Wasmtime::Func.new(store, type) do |_caller, arg1|
84
+ /// arg1.succ
85
+ /// end
86
+ pub fn new(args: &[Value]) -> Result<Self, Error> {
87
+ let args = scan_args::<(Value, &FuncType), (), (), (), (), Proc>(args)?;
88
+ let (s, functype) = args.required;
89
+ let callable = args.block;
90
+
91
+ let wrapped_store: WrappedStruct<Store> = s.try_convert()?;
92
+ let store = wrapped_store.get()?;
93
+
94
+ store.retain(callable.into());
95
+ let context = store.context_mut();
96
+ let ty = functype.get();
97
+
98
+ let inner = wasmtime::Func::new(context, ty.clone(), make_func_closure(ty, callable));
99
+
100
+ Ok(Self {
101
+ store: wrapped_store.into(),
102
+ inner,
103
+ })
104
+ }
105
+
106
+ pub fn from_inner(store: StoreContextValue<'a>, inner: FuncImpl) -> Self {
107
+ Self { store, inner }
108
+ }
109
+
110
+ pub fn get(&self) -> FuncImpl {
111
+ // Makes a copy (wasmtime::Func implements Copy)
112
+ self.inner
113
+ }
114
+
115
+ /// @yard
116
+ /// Calls a Wasm function.
117
+ ///
118
+ /// @def call(*args)
119
+ /// @param args [Object]
120
+ /// The arguments to send to the Wasm function. Raises if the arguments do
121
+ /// not conform to the Wasm function's parameters.
122
+ ///
123
+ /// @return [nil, Object, Array<Object>] The return type depends on {FuncType}’s results arity:
124
+ /// * 0 => +nil+
125
+ /// * 1 => +Object+
126
+ /// * > 1 => +Array<Object>+
127
+ pub fn call(&self, args: &[Value]) -> Result<Value, Error> {
128
+ Self::invoke(&self.store, &self.inner, args).map_err(|e| e.into())
129
+ }
130
+
131
+ pub fn inner(&self) -> &FuncImpl {
132
+ &self.inner
133
+ }
134
+
135
+ pub fn invoke(
136
+ store: &StoreContextValue,
137
+ func: &wasmtime::Func,
138
+ args: &[Value],
139
+ ) -> Result<Value, InvokeError> {
140
+ let func_ty = func.ty(store.context_mut()?);
141
+ let param_types = func_ty.params().collect::<Vec<_>>();
142
+ let params = Params::new(args, param_types)?.to_vec()?;
143
+ let mut results = vec![Val::null(); func_ty.results().len()];
144
+
145
+ func.call(store.context_mut()?, &params, &mut results)
146
+ .map_err(|e| store.handle_wasm_error(e))?;
147
+
148
+ match results.as_slice() {
149
+ [] => Ok(QNIL.into()),
150
+ [result] => result.to_ruby_value(store).map_err(|e| e.into()),
151
+ _ => {
152
+ let array = RArray::with_capacity(results.len());
153
+ for result in results {
154
+ array.push(result.to_ruby_value(store)?)?;
155
+ }
156
+ Ok(array.into())
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ impl From<&Func<'_>> for wasmtime::Extern {
163
+ fn from(func: &Func) -> Self {
164
+ Self::Func(func.get())
165
+ }
166
+ }
167
+
168
+ pub fn make_func_closure(
169
+ ty: &wasmtime::FuncType,
170
+ callable: Proc,
171
+ ) -> impl Fn(CallerImpl<'_, StoreData>, &[Val], &mut [Val]) -> anyhow::Result<()> + Send + Sync + 'static
172
+ {
173
+ let ty = ty.to_owned();
174
+ let callable = ShareableProc(callable);
175
+
176
+ move |caller_impl: CallerImpl<'_, StoreData>, params: &[Val], results: &mut [Val]| {
177
+ let wrapped_caller: WrappedStruct<Caller> = Caller::new(caller_impl).into();
178
+ let caller = wrapped_caller.get().unwrap();
179
+ let store_context = StoreContextValue::from(wrapped_caller);
180
+
181
+ let rparams = RArray::with_capacity(params.len() + 1);
182
+ rparams.push(Value::from(wrapped_caller)).unwrap();
183
+
184
+ for (i, param) in params.iter().enumerate() {
185
+ let rparam = param
186
+ .to_ruby_value(&store_context)
187
+ .map_err(|e| anyhow::anyhow!(format!("invalid argument at index {}: {}", i, e)))?;
188
+ rparams.push(rparam).unwrap();
189
+ }
190
+
191
+ let callable = callable.0;
192
+
193
+ let result = callable
194
+ .call(unsafe { rparams.as_slice() })
195
+ .map_err(|e| {
196
+ if let Error::Exception(exception) = e {
197
+ caller.hold_exception(exception);
198
+ }
199
+ e
200
+ })
201
+ .and_then(|proc_result| {
202
+ match results.len() {
203
+ 0 => Ok(()), // Ignore return value
204
+ n => {
205
+ // For len=1, accept both `val` and `[val]`
206
+ let proc_result = RArray::try_convert(proc_result)?;
207
+ if proc_result.len() != n {
208
+ return Result::Err(error!(
209
+ "wrong number of results (given {}, expected {})",
210
+ proc_result.len(),
211
+ n
212
+ ));
213
+ }
214
+ for ((rb_val, wasm_val), ty) in unsafe { proc_result.as_slice() }
215
+ .iter()
216
+ .zip(results.iter_mut())
217
+ .zip(ty.results())
218
+ {
219
+ *wasm_val = rb_val.to_wasm_val(&ty)?;
220
+ }
221
+ Ok(())
222
+ }
223
+ }
224
+ })
225
+ .map_err(|e| {
226
+ anyhow::anyhow!(format!(
227
+ "Error when calling Func {}\n Error: {}",
228
+ callable.inspect(),
229
+ e
230
+ ))
231
+ });
232
+
233
+ // Drop the wasmtime::Caller so it does not outlive the Func call, if e.g. the user
234
+ // assigned the Ruby Wasmtime::Caller instance to a global.
235
+ caller.expire();
236
+
237
+ result
238
+ }
239
+ }
240
+
241
+ pub enum InvokeError {
242
+ BoxedException(BoxValue<Exception>),
243
+ Error(Error),
244
+ }
245
+
246
+ impl From<InvokeError> for magnus::Error {
247
+ fn from(e: InvokeError) -> Self {
248
+ match e {
249
+ InvokeError::Error(e) => e,
250
+ InvokeError::BoxedException(e) => Error::from(e.to_owned()),
251
+ }
252
+ }
253
+ }
254
+
255
+ impl From<magnus::Error> for InvokeError {
256
+ fn from(e: magnus::Error) -> Self {
257
+ InvokeError::Error(e)
258
+ }
259
+ }
260
+
261
+ impl From<BoxValue<Exception>> for InvokeError {
262
+ fn from(e: BoxValue<Exception>) -> Self {
263
+ InvokeError::BoxedException(e)
264
+ }
265
+ }
266
+
267
+ /// A handle to a [`wasmtime::Caller`] that's only valid during a Func execution.
268
+ /// [`UnsafeCell`] wraps the wasmtime::Caller because the Value's lifetime can't
269
+ /// be tied to the Caller: the Value is handed back to Ruby and we can't control
270
+ /// whether the user keeps a handle to it or not.
271
+ #[derive(Debug)]
272
+ pub struct CallerHandle<'a> {
273
+ caller: UnsafeCell<Option<CallerImpl<'a, StoreData>>>,
274
+ }
275
+
276
+ impl<'a> CallerHandle<'a> {
277
+ pub fn new(caller: CallerImpl<'a, StoreData>) -> Self {
278
+ Self {
279
+ caller: UnsafeCell::new(Some(caller)),
280
+ }
281
+ }
282
+
283
+ pub fn get_mut(&self) -> Result<&mut CallerImpl<'a, StoreData>, Error> {
284
+ unsafe { &mut *self.caller.get() }
285
+ .as_mut()
286
+ .ok_or_else(|| error!("Caller outlived its Func execution"))
287
+ }
288
+
289
+ pub fn get(&self) -> Result<&CallerImpl<'a, StoreData>, Error> {
290
+ unsafe { (*self.caller.get()).as_ref() }
291
+ .ok_or_else(|| error!("Caller outlived its Func execution"))
292
+ }
293
+
294
+ pub fn expire(&self) {
295
+ unsafe { *self.caller.get() = None }
296
+ }
297
+ }
298
+
299
+ /// @yard
300
+ /// @rename Wasmtime::Caller
301
+ /// Represents the Caller's context within a Func execution. An instance of
302
+ /// Caller is sent as the first parameter to Func's implementation (the
303
+ /// block argument in {Func.new}).
304
+ /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Caller.html Wasmtime's Rust doc
305
+ #[derive(Debug)]
306
+ pub struct Caller<'a> {
307
+ handle: CallerHandle<'a>,
308
+ }
309
+
310
+ impl<'a> Caller<'a> {
311
+ pub fn new(caller: CallerImpl<'a, StoreData>) -> Self {
312
+ Self {
313
+ handle: CallerHandle::new(caller),
314
+ }
315
+ }
316
+
317
+ /// @yard
318
+ /// Returns the store's data. Akin to {Store#data}.
319
+ /// @return [Object] The store's data (the object passed to {Store.new}).
320
+ pub fn store_data(&self) -> Result<Value, Error> {
321
+ self.context().map(|ctx| ctx.data().user_data())
322
+ }
323
+
324
+ /// @yard
325
+ /// @def export(name)
326
+ /// @see Instance#export
327
+ pub fn export(
328
+ rb_self: WrappedStruct<Caller<'a>>,
329
+ name: RString,
330
+ ) -> Result<Option<Extern<'a>>, Error> {
331
+ let caller = rb_self.try_convert::<&Self>()?;
332
+ let inner = caller.handle.get_mut()?;
333
+
334
+ if let Some(export) = inner.get_export(unsafe { name.as_str() }?) {
335
+ export.wrap_wasmtime_type(rb_self.into()).map(Some)
336
+ } else {
337
+ Ok(None)
338
+ }
339
+ }
340
+
341
+ pub fn context(&self) -> Result<StoreContext<StoreData>, Error> {
342
+ self.handle.get().map(|c| c.as_context())
343
+ }
344
+
345
+ pub fn context_mut(&self) -> Result<StoreContextMut<StoreData>, Error> {
346
+ self.handle.get_mut().map(|c| c.as_context_mut())
347
+ }
348
+
349
+ pub fn expire(&self) {
350
+ self.handle.expire();
351
+ }
352
+
353
+ fn hold_exception(&self, exception: Exception) {
354
+ self.context_mut()
355
+ .unwrap()
356
+ .data_mut()
357
+ .exception()
358
+ .hold(exception);
359
+ }
360
+ }
361
+
362
+ unsafe impl<'a> TypedData for Caller<'a> {
363
+ fn class() -> magnus::RClass {
364
+ *memoize!(RClass: root().define_class("Caller", Default::default()).unwrap())
365
+ }
366
+
367
+ fn data_type() -> &'static magnus::DataType {
368
+ memoize!(magnus::DataType: {
369
+ let mut builder = DataTypeBuilder::<Caller<'_>>::new("Wasmtime::Caller");
370
+ builder.free_immediately();
371
+ builder.build()
372
+ })
373
+ }
374
+ }
375
+ impl DataTypeFunctions for Caller<'_> {}
376
+ unsafe impl Send for Caller<'_> {}
377
+
378
+ pub fn init() -> Result<(), Error> {
379
+ let func = root().define_class("Func", Default::default())?;
380
+ func.define_singleton_method("new", function!(Func::new, -1))?;
381
+ func.define_method("call", method!(Func::call, -1))?;
382
+
383
+ let caller = root().define_class("Caller", Default::default())?;
384
+ caller.define_method("store_data", method!(Caller::store_data, 0))?;
385
+ caller.define_method("export", method!(Caller::export, 1))?;
386
+
387
+ Ok(())
388
+ }