wasmtime 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 278e090fef9ae4f35850cc892273ddbe94b2b838b0fc619ca835a17505129957
4
- data.tar.gz: fbafd3a60ace1ec5f4806ac94d86e73264feb16e5b4f781c09ad9927c070758e
3
+ metadata.gz: 51b9d23eb473612cd8d79f307021bdcf6ccbce2c1e522996af1bf3c1ebb85c1a
4
+ data.tar.gz: cde5dc2a81f5cc73a4e8abd70268d1e9322bad3093cf7ce8f1d3d13fa44aafda
5
5
  SHA512:
6
- metadata.gz: '016450946bf0d7ee92ffbc44bdc1be90a83602a14a209e3c24e7cc438883845b0b19aa173288169beb5248a080205c8b1d9abe46b373868b72e5caed3e5831bb'
7
- data.tar.gz: 8dda113d2501e84a1222dd5ccbc1683cc84490d30628f98f489c681db4e2712d0aa24d65261ae0f223377602d74293472e56166d6aae55d9253bebc78ce1d17d
6
+ metadata.gz: e5a78a30dd600e7c9618c2c0612b5d657d3002e027e826375522455762756b56f4606b433b94070a0227ceb2319321752744d6c86ce613bda672bc3e067c5423
7
+ data.tar.gz: 301fbc2e124b4653b957cee6e260408a5cefed5743da6bc7327f7a7d153f29f2ba63ddf331cb93da0fbb16f593cdd7f4b555dfae6b242e7c97bc2067b50ffa88
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2020-05-19
11
+
12
+ - Exported functions now live on `Wasmtime::Instance#exports` instead of `#funcs`.
13
+ - Exports hash is now keyed by strings instead of symbols.
14
+ - Added support for `Wasmtime::Memory` exports with `#data_size`, `#size` and `#grow` methods.
15
+
10
16
  ## [0.1.0] - 2020-05-07
11
17
 
12
18
  ### Added
@@ -16,5 +22,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
22
  - Support for 32 and 64-bit integers and floats in arguments and as return values.
17
23
  - Require patch for defining a Ruby module with functions for each export.
18
24
 
19
- [unreleased]: https://github.com/dtcristo/wasmtime-ruby/compare/v0.1.0...HEAD
25
+ [unreleased]: https://github.com/dtcristo/wasmtime-ruby/compare/v0.2.0...HEAD
26
+ [0.2.0]: https://github.com/dtcristo/wasmtime-ruby/releases/tag/v0.2.0
20
27
  [0.1.0]: https://github.com/dtcristo/wasmtime-ruby/releases/tag/v0.1.0
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <h1>wasmtime-ruby</h1>
3
3
  <p>
4
4
  <strong>
5
- <a href="https://github.com/bytecodealliance/wasmtime">Wasmtime</a> WebAssembly runtime in Ruby
5
+ Ruby bindings for <a href="https://github.com/bytecodealliance/wasmtime">Wasmtime</a>, a WebAssembly runtime
6
6
  </strong>
7
7
  </p>
8
8
  <p>
@@ -17,13 +17,10 @@
17
17
 
18
18
  ## Introduction
19
19
 
20
- This gem allows you to use the [Wasmtime](https://wasmtime.dev/) WebAssembly
21
- runtime from within your Ruby project.
22
-
23
- Why would you want that? [WebAssembly](https://webassembly.org/) (or WASM) is a
24
- technology that allows you to write programs that run at near-native speeds in a
25
- safe sandboxed environment. Wasmtime is a runtime for WASM programs. This gem
26
- embedds Wasmtime in a native extension so you can now run WASM from Ruby.
20
+ This project provides Ruby bindings for [Wasmtime](https://github.com/bytecodealliance/wasmtime),
21
+ a [WebAssembly](https://webassembly.org/) runtime. This allows you to execute
22
+ WASM modules from within Ruby executing at near-native speeds in a safe
23
+ sandboxed environment.
27
24
 
28
25
  This is pretty experimental and not production ready right now. There are quite
29
26
  a few things that aren't built yet, see [TODO](#todo) section below.
@@ -42,7 +39,7 @@ Install the `wasmtime` gem. Pre-compiled binaries are available for
42
39
  gem install wasmtime
43
40
  ```
44
41
 
45
- WASM has two formats `*.wasm` (binary) and `*.wat` (human-readable text). Both
42
+ WASM has two formats `.wasm` (binary) and `.wat` (human-readable text). Both
46
43
  formats are supported. With the following `fibonacci.wat` file in your current
47
44
  directory.
48
45
 
@@ -65,7 +62,7 @@ directory.
65
62
  ```
66
63
 
67
64
  In a ruby file, `require 'wasmtime/require'` to activate the Wasmtime require
68
- patch, allowing you to require any `*.wasm` or `*.wat` module as if it were a
65
+ patch, allowing you to require any `.wasm` or `.wat` module as if it were a
69
66
  Ruby file. Doing so will internally create a `Wasmtime::Instance` and define a
70
67
  Ruby module with functions for each export.
71
68
 
@@ -86,7 +83,7 @@ use this approach too.
86
83
  require 'wasmtime'
87
84
 
88
85
  instance = Wasmtime::Instance.new('fibonacci.wat')
89
- puts instance.funcs[:fib].call(11) #=> 89
86
+ puts instance.exports['fib'].call(11) #=> 89
90
87
  ```
91
88
 
92
89
  ## Benchmarks
@@ -60,8 +60,11 @@ module Wasmtime
60
60
  end
61
61
  mod = Object.const_set(module_name.camelize, Module.new)
62
62
  instance = Wasmtime::Instance.new(absolute_path)
63
- instance.funcs.each do |name, func|
64
- mod.define_singleton_method(name) { |*args| func.call(*args) }
63
+ instance.exports.each do |name, export|
64
+ case export
65
+ when Wasmtime::Func
66
+ mod.define_singleton_method(name) { |*args| export.call(*args) }
67
+ end
65
68
  end
66
69
  $LOADED_FEATURES << absolute_path
67
70
  true
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wasmtime
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -0,0 +1,19 @@
1
+ use rutie::{AnyObject, Object};
2
+ use wasmtime as w;
3
+
4
+ use crate::func::{Func, RubyFunc};
5
+ use crate::memory::RubyMemory;
6
+
7
+ pub enum Export {
8
+ Func(Func),
9
+ Memory(w::Memory),
10
+ }
11
+
12
+ impl From<Export> for AnyObject {
13
+ fn from(export: Export) -> Self {
14
+ match export {
15
+ Export::Func(func) => RubyFunc::from(func).value().into(),
16
+ Export::Memory(memory) => RubyMemory::from(memory).value().into(),
17
+ }
18
+ }
19
+ }
@@ -8,7 +8,8 @@ use rutie::{
8
8
  use std::mem;
9
9
  use wasmtime as w;
10
10
 
11
- use crate::vm::*;
11
+ use crate::ruby_type::RubyType;
12
+ use crate::vm::raise;
12
13
 
13
14
  pub struct Func {
14
15
  func: w::Func,
@@ -23,58 +24,24 @@ impl Func {
23
24
  self.func.call(args).expect("failed to call func").to_vec()
24
25
  }
25
26
 
26
- pub fn into_ruby(self) -> RubyFunc {
27
- Module::from_existing("Wasmtime")
28
- .get_nested_class("Func")
29
- .wrap_data(self, &*FUNC_WRAPPER)
30
- }
31
-
32
27
  fn parse_param_types(&self) -> Vec<RubyType> {
33
28
  self.func
34
29
  .ty()
35
30
  .params()
36
31
  .iter()
37
- .map(|val_type| val_type_to_ruby_type(val_type))
32
+ .map(|val_type| val_type.into())
38
33
  .collect()
39
34
  }
40
35
 
41
36
  fn parse_result_type(&self) -> RubyType {
42
37
  match self.func.ty().results().len() {
43
38
  0 => RubyType::NilClass,
44
- 1 => val_type_to_ruby_type(self.func.ty().results().first().unwrap()),
39
+ 1 => self.func.ty().results().first().unwrap().into(),
45
40
  _ => raise("StandardError", "multiple return values are not supported"),
46
41
  }
47
42
  }
48
43
  }
49
44
 
50
- fn val_type_to_ruby_type(val_type: &w::ValType) -> RubyType {
51
- match val_type {
52
- w::ValType::I32 => RubyType::Integer32,
53
- w::ValType::I64 => RubyType::Integer64,
54
- w::ValType::F32 => RubyType::Float32,
55
- w::ValType::F64 => RubyType::Float64,
56
- _ => RubyType::Unsupported,
57
- }
58
- }
59
-
60
- #[derive(Debug, Copy, Clone)]
61
- enum RubyType {
62
- Integer32,
63
- Integer64,
64
- Float32,
65
- Float64,
66
- // String,
67
- // Boolean,
68
- NilClass,
69
- Unsupported,
70
- }
71
-
72
- impl Into<AnyObject> for RubyType {
73
- fn into(self) -> AnyObject {
74
- RString::new_utf8(&format!("{:?}", self)).into()
75
- }
76
- }
77
-
78
45
  fn translate_incoming(args: Array, param_types: &[RubyType]) -> Vec<w::Val> {
79
46
  if args.length() != param_types.len() {
80
47
  raise(
@@ -141,6 +108,14 @@ fn translate_outgoing(native_results: Vec<w::Val>) -> AnyObject {
141
108
  wrappable_struct!(Func, FuncWrapper, FUNC_WRAPPER);
142
109
  class!(RubyFunc);
143
110
 
111
+ impl From<Func> for RubyFunc {
112
+ fn from(func: Func) -> Self {
113
+ Module::from_existing("Wasmtime")
114
+ .get_nested_class("Func")
115
+ .wrap_data(func, &*FUNC_WRAPPER)
116
+ }
117
+ }
118
+
144
119
  #[rustfmt::skip]
145
120
  methods!(
146
121
  RubyFunc,
@@ -1,11 +1,11 @@
1
1
  use lazy_static::lazy_static;
2
- use rutie::{class, methods, wrappable_struct, Hash, Module, Object, RString, Symbol};
2
+ use rutie::{class, methods, wrappable_struct, AnyObject, Hash, Module, Object, RString};
3
3
  use std::collections::HashMap;
4
4
  use std::fs;
5
5
  use wasmtime as w;
6
6
 
7
+ use crate::export::Export;
7
8
  use crate::func::Func;
8
- use crate::memory::Memory;
9
9
 
10
10
  pub struct Instance {
11
11
  instance: w::Instance,
@@ -27,58 +27,57 @@ impl Instance {
27
27
  Instance { instance }
28
28
  }
29
29
 
30
- fn exports(&self) -> (HashMap<String, Func>, HashMap<String, Memory>) {
31
- let mut funcs = HashMap::new();
32
- let mut memories = HashMap::new();
30
+ fn exports(&self) -> HashMap<String, Export> {
31
+ let mut exports = HashMap::new();
33
32
 
34
33
  for export in self.instance.exports() {
35
34
  match export.ty() {
36
35
  w::ExternType::Func(_) => {
37
36
  let name = export.name().to_string();
38
- let func = Func::new(export.into_func().expect("failed to create func"));
39
- funcs.insert(name, func);
37
+ let func = Func::new(export.into_func().unwrap());
38
+ exports.insert(name, Export::Func(func));
40
39
  }
41
40
  w::ExternType::Memory(_) => {
42
- let memory = Memory::new();
43
- memories.insert(export.name().to_string(), memory);
41
+ let name = export.name().to_string();
42
+ let memory = export.into_memory().unwrap();
43
+ exports.insert(name, Export::Memory(memory));
44
44
  }
45
45
  _ => {}
46
46
  }
47
47
  }
48
48
 
49
- (funcs, memories)
49
+ exports
50
50
  }
51
+ }
51
52
 
52
- pub fn funcs(&self) -> HashMap<String, Func> {
53
- let (functions, _) = self.exports();
54
- functions
55
- }
53
+ wrappable_struct!(Instance, InstanceWrapper, INSTANCE_WRAPPER);
54
+ class!(RubyInstance);
56
55
 
57
- pub fn into_ruby(self) -> RubyInstance {
56
+ impl From<Instance> for RubyInstance {
57
+ fn from(instance: Instance) -> Self {
58
58
  Module::from_existing("Wasmtime")
59
59
  .get_nested_class("Instance")
60
- .wrap_data(self, &*INSTANCE_WRAPPER)
60
+ .wrap_data(instance, &*INSTANCE_WRAPPER)
61
61
  }
62
62
  }
63
63
 
64
- wrappable_struct!(Instance, InstanceWrapper, INSTANCE_WRAPPER);
65
- class!(RubyInstance);
66
-
67
64
  #[rustfmt::skip]
68
65
  methods!(
69
66
  RubyInstance,
70
67
  itself,
71
68
 
72
69
  fn ruby_instance_new(path: RString) -> RubyInstance {
73
- Instance::new(path.expect("failed read path").to_string()).into_ruby()
70
+ Instance::new(path.expect("failed read path").to_string()).into()
74
71
  }
75
72
 
76
- fn ruby_instance_funcs() -> Hash {
77
- let mut funcs = Hash::new();
78
- for (export_name, func) in itself.get_data(&*INSTANCE_WRAPPER).funcs().into_iter() {
79
- funcs.store(Symbol::new(&export_name), func.into_ruby());
73
+ fn ruby_instance_exports() -> Hash {
74
+ let mut exports = Hash::new();
75
+
76
+ for (export_name, export) in itself.get_data(&*INSTANCE_WRAPPER).exports().into_iter() {
77
+ exports.store::<RString, AnyObject>(RString::new_utf8(&export_name), export.into());
80
78
  }
81
- funcs
79
+
80
+ exports
82
81
  }
83
82
  );
84
83
 
@@ -88,7 +87,7 @@ pub fn ruby_init() {
88
87
  .define_nested_class("Instance", None)
89
88
  .define(|class| {
90
89
  class.def_self("new", ruby_instance_new);
91
- class.def("funcs", ruby_instance_funcs);
90
+ class.def("exports", ruby_instance_exports);
92
91
  });
93
92
  });
94
93
  }
data/src/lib.rs CHANGED
@@ -1,6 +1,8 @@
1
+ mod export;
1
2
  mod func;
2
3
  mod instance;
3
4
  mod memory;
5
+ mod ruby_type;
4
6
  mod vm;
5
7
 
6
8
  #[allow(non_snake_case)]
@@ -16,4 +18,5 @@ pub extern "C" fn Init_native() {
16
18
 
17
19
  instance::ruby_init();
18
20
  func::ruby_init();
21
+ memory::ruby_init();
19
22
  }
@@ -1,7 +1,48 @@
1
- pub struct Memory {}
1
+ use lazy_static::lazy_static;
2
+ use rutie::{class, methods, wrappable_struct, AnyObject, Integer, Module, NilClass, Object};
3
+ use wasmtime as w;
2
4
 
3
- impl Memory {
4
- pub fn new() -> Self {
5
- Memory {}
5
+ wrappable_struct!(w::Memory, MemoryWrapper, MEMORY_WRAPPER);
6
+ class!(RubyMemory);
7
+
8
+ impl From<w::Memory> for RubyMemory {
9
+ fn from(memory: w::Memory) -> Self {
10
+ Module::from_existing("Wasmtime")
11
+ .get_nested_class("Memory")
12
+ .wrap_data(memory, &*MEMORY_WRAPPER)
13
+ }
14
+ }
15
+
16
+ #[rustfmt::skip]
17
+ methods!(
18
+ RubyMemory,
19
+ itself,
20
+
21
+ fn ruby_instance_data_size() -> Integer {
22
+ Integer::from(itself.get_data(&*MEMORY_WRAPPER).data_size() as u32)
6
23
  }
24
+
25
+ fn ruby_instance_size() -> Integer {
26
+ Integer::from(itself.get_data(&*MEMORY_WRAPPER).size())
27
+ }
28
+
29
+ fn ruby_instance_grow(delta: Integer) -> AnyObject {
30
+ let memory = itself.get_data(&*MEMORY_WRAPPER);
31
+ let delta = delta.unwrap().to_i32();
32
+ if delta < 0 { return NilClass::new().into() }
33
+ match memory.grow(delta as u32) {
34
+ Ok(original) => Integer::from(original).into(),
35
+ Err(_) => NilClass::new().into()
36
+ }
37
+ }
38
+ );
39
+
40
+ pub fn ruby_init() {
41
+ Module::from_existing("Wasmtime").define(|module| {
42
+ module.define_nested_class("Memory", None).define(|class| {
43
+ class.def("data_size", ruby_instance_data_size);
44
+ class.def("size", ruby_instance_size);
45
+ class.def("grow", ruby_instance_grow);
46
+ });
47
+ });
7
48
  }
@@ -0,0 +1,32 @@
1
+ use rutie::{AnyObject, RString};
2
+ use wasmtime as w;
3
+
4
+ #[derive(Debug, Copy, Clone)]
5
+ pub enum RubyType {
6
+ Integer32,
7
+ Integer64,
8
+ Float32,
9
+ Float64,
10
+ // String,
11
+ // Boolean,
12
+ NilClass,
13
+ Unsupported,
14
+ }
15
+
16
+ impl From<RubyType> for AnyObject {
17
+ fn from(ruby_type: RubyType) -> AnyObject {
18
+ RString::new_utf8(&format!("{:?}", ruby_type)).into()
19
+ }
20
+ }
21
+
22
+ impl From<&w::ValType> for RubyType {
23
+ fn from(val_type: &w::ValType) -> Self {
24
+ match val_type {
25
+ w::ValType::I32 => RubyType::Integer32,
26
+ w::ValType::I64 => RubyType::Integer64,
27
+ w::ValType::F32 => RubyType::Float32,
28
+ w::ValType::F64 => RubyType::Float64,
29
+ _ => RubyType::Unsupported,
30
+ }
31
+ }
32
+ }
metadata CHANGED
@@ -1,17 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wasmtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cristofaro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-07 00:00:00.000000000 Z
11
+ date: 2020-05-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: This gem allows you to use the Wasmtime WebAssembly runtime from within
14
- your Ruby project.
13
+ description:
15
14
  email:
16
15
  - david@dtcristo.com
17
16
  executables: []
@@ -33,10 +32,12 @@ files:
33
32
  - lib/wasmtime/refinements.rb
34
33
  - lib/wasmtime/require.rb
35
34
  - lib/wasmtime/version.rb
35
+ - src/export.rs
36
36
  - src/func.rs
37
37
  - src/instance.rs
38
38
  - src/lib.rs
39
39
  - src/memory.rs
40
+ - src/ruby_type.rs
40
41
  - src/vm.rs
41
42
  homepage: https://github.com/dtcristo/wasmtime-ruby
42
43
  licenses:
@@ -62,5 +63,5 @@ requirements: []
62
63
  rubygems_version: 3.1.2
63
64
  signing_key:
64
65
  specification_version: 4
65
- summary: Wasmtime WebAssembly runtime
66
+ summary: Ruby bindings for Wasmtime, a WebAssembly runtime
66
67
  test_files: []