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