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.
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
+ }