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,135 @@
1
+ use std::convert::TryFrom;
2
+
3
+ use crate::helpers::WrappedStruct;
4
+ use crate::ruby_api::{errors::base_error, root};
5
+ use magnus::Error;
6
+ use magnus::{
7
+ memoize, method, rb_sys::AsRawValue, DataTypeFunctions, ExceptionClass, Module as _, Symbol,
8
+ TypedData, Value,
9
+ };
10
+
11
+ pub fn trap_error() -> ExceptionClass {
12
+ *memoize!(ExceptionClass: root().define_error("Trap", base_error()).unwrap())
13
+ }
14
+
15
+ macro_rules! trap_const {
16
+ ($trap:ident) => {
17
+ trap_error().const_get(stringify!($trap)).map(Some)
18
+ };
19
+ }
20
+
21
+ #[derive(TypedData, Debug)]
22
+ #[magnus(class = "Wasmtime::Trap", size, free_immediatly)]
23
+ /// @yard
24
+ pub struct Trap {
25
+ trap: wasmtime::Trap,
26
+ wasm_backtrace: Option<wasmtime::WasmBacktrace>,
27
+ }
28
+ impl DataTypeFunctions for Trap {}
29
+
30
+ impl Trap {
31
+ pub fn new(trap: wasmtime::Trap, wasm_backtrace: Option<wasmtime::WasmBacktrace>) -> Self {
32
+ Self {
33
+ trap,
34
+ wasm_backtrace,
35
+ }
36
+ }
37
+
38
+ /// @yard
39
+ /// Returns a textual description of the trap error, for example:
40
+ /// wasm trap: wasm `unreachable` instruction executed
41
+ /// @return [String]
42
+ pub fn message(&self) -> String {
43
+ self.trap.to_string()
44
+ }
45
+
46
+ /// @yard
47
+ /// Returns a textual representation of the Wasm backtrce, if it exists.
48
+ /// For example:
49
+ /// error while executing at wasm backtrace:
50
+ /// 0: 0x1a - <unknown>!<wasm function 0>
51
+ /// @return [String, nil]
52
+ pub fn wasm_backtrace_message(&self) -> Option<String> {
53
+ self.wasm_backtrace.as_ref().map(|bt| format!("{}", bt))
54
+ }
55
+
56
+ /// @yard
57
+ /// Returns the trap code as a Symbol, possibly nil if the trap did not
58
+ /// origin from Wasm code. All possible trap codes are defined as constants on {Trap}.
59
+ /// @return [Symbol, nil]
60
+ pub fn code(&self) -> Result<Option<Symbol>, Error> {
61
+ match self.trap {
62
+ wasmtime::Trap::HeapMisaligned => trap_const!(HEAP_MISALIGNED),
63
+ wasmtime::Trap::TableOutOfBounds => trap_const!(TABLE_OUT_OF_BOUNDS),
64
+ wasmtime::Trap::IndirectCallToNull => trap_const!(INDIRECT_CALL_TO_NULL),
65
+ wasmtime::Trap::BadSignature => trap_const!(BAD_SIGNATURE),
66
+ wasmtime::Trap::IntegerOverflow => trap_const!(INTEGER_OVERFLOW),
67
+ wasmtime::Trap::IntegerDivisionByZero => trap_const!(INTEGER_DIVISION_BY_ZERO),
68
+ wasmtime::Trap::BadConversionToInteger => trap_const!(BAD_CONVERSION_TO_INTEGER),
69
+ wasmtime::Trap::UnreachableCodeReached => trap_const!(UNREACHABLE_CODE_REACHED),
70
+ wasmtime::Trap::Interrupt => trap_const!(INTERRUPT),
71
+ wasmtime::Trap::AlwaysTrapAdapter => trap_const!(ALWAYS_TRAP_ADAPTER),
72
+ // When adding a trap code here, define a matching constant on Wasmtime::Trap (in Ruby)
73
+ _ => trap_const!(UNKNOWN),
74
+ }
75
+ }
76
+
77
+ // pub fn wasm_backtrace(&self) -> Option<RArray> {
78
+ // self.wasm_backtrace.as_ref().map(|backtrace| {
79
+ // let array = RArray::with_capacity(backtrace.frames().len());
80
+ // backtrace
81
+ // .frames()
82
+ // .iter()
83
+ // .for_each(|frame| array.push(frame.format()).unwrap());
84
+
85
+ // array
86
+ // })
87
+ // }
88
+
89
+ pub fn inspect(rb_self: WrappedStruct<Self>) -> Result<String, Error> {
90
+ let rs_self = rb_self.get()?;
91
+
92
+ Ok(format!(
93
+ "#<Wasmtime::Trap:0x{:016x} @trap_code={}>",
94
+ rb_self.to_value().as_raw(),
95
+ Value::from(rs_self.code()?).inspect()
96
+ ))
97
+ }
98
+ }
99
+
100
+ impl From<Trap> for Error {
101
+ fn from(trap: Trap) -> Self {
102
+ magnus::Value::from(trap)
103
+ .try_convert::<magnus::Exception>()
104
+ .unwrap() // Can't fail: Wasmtime::Trap is an Exception
105
+ .into()
106
+ }
107
+ }
108
+
109
+ impl TryFrom<anyhow::Error> for Trap {
110
+ type Error = anyhow::Error;
111
+
112
+ fn try_from(value: anyhow::Error) -> Result<Self, Self::Error> {
113
+ match value.downcast_ref::<wasmtime::Trap>() {
114
+ Some(trap) => {
115
+ let trap = trap.to_owned();
116
+ let bt = value.downcast::<wasmtime::WasmBacktrace>();
117
+ Ok(Trap::new(trap, bt.map(Some).unwrap_or(None)))
118
+ }
119
+ None => Err(value),
120
+ }
121
+ }
122
+ }
123
+
124
+ pub fn init() -> Result<(), Error> {
125
+ let class = trap_error();
126
+ class.define_method("message", method!(Trap::message, 0))?;
127
+ class.define_method(
128
+ "wasm_backtrace_message",
129
+ method!(Trap::wasm_backtrace_message, 0),
130
+ )?;
131
+ class.define_method("code", method!(Trap::code, 0))?;
132
+ class.define_method("inspect", method!(Trap::inspect, 0))?;
133
+ class.define_alias("to_s", "message")?;
134
+ Ok(())
135
+ }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wasmtime
4
- VERSION = '0.2.0'
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/wasmtime.rb CHANGED
@@ -1,7 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Wasmtime; end
3
+ require_relative "wasmtime/version"
4
4
 
5
- require 'wasmtime/version'
6
- require 'wasmtime/refinements'
7
- require 'wasmtime/native'
5
+ # Tries to require the extension for the given Ruby version first
6
+ begin
7
+ RUBY_VERSION =~ /(\d+\.\d+)/
8
+ require "wasmtime/#{Regexp.last_match(1)}/ext"
9
+ rescue LoadError
10
+ require "wasmtime/ext"
11
+ end
12
+
13
+ module Wasmtime
14
+ class Error < StandardError; end
15
+
16
+ class ConversionError < Error; end
17
+
18
+ class Trap < Error
19
+ STACK_OVERFLOW = :stack_overflow
20
+ HEAP_MISALIGNED = :heap_misaligned
21
+ TABLE_OUT_OF_BOUNDS = :table_out_of_bounds
22
+ INDIRECT_CALL_TO_NULL = :indirect_call_to_null
23
+ BAD_SIGNATURE = :bad_signature
24
+ INTEGER_OVERFLOW = :integer_overflow
25
+ INTEGER_DIVISION_BY_ZERO = :integer_division_by_zero
26
+ BAD_CONVERSION_TO_INTEGER = :bad_conversion_to_integer
27
+ UNREACHABLE_CODE_REACHED = :unreachable_code_reached
28
+ INTERRUPT = :interrupt
29
+ ALWAYS_TRAP_ADAPTER = :always_trap_adapter
30
+ UNKNOWN = :unknown
31
+ end
32
+ end
metadata CHANGED
@@ -1,50 +1,74 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wasmtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
- - David Cristofaro
7
+ - The Wasmtime Project Developers
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-19 00:00:00.000000000 Z
12
- dependencies: []
13
- description:
11
+ date: 2022-11-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rb_sys
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.39
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.39
27
+ description: A Ruby binding for Wasmtime, a WebAssembly runtime.
14
28
  email:
15
- - david@dtcristo.com
29
+ - hello@bytecodealliance.org
16
30
  executables: []
17
31
  extensions:
18
- - ext/wasmtime/extconf.rb
32
+ - ext/extconf.rb
19
33
  extra_rdoc_files: []
20
34
  files:
21
- - ".cargo/config"
22
- - CHANGELOG.md
23
35
  - Cargo.lock
24
36
  - Cargo.toml
25
37
  - LICENSE
26
38
  - README.md
27
- - ext/wasmtime/Makefile
28
- - ext/wasmtime/Rakefile
29
- - ext/wasmtime/extconf.rb
30
- - lib/tasks/compile.rake
39
+ - ext/Cargo.toml
40
+ - ext/extconf.rb
41
+ - ext/src/helpers/mod.rs
42
+ - ext/src/helpers/wrapped_struct.rs
43
+ - ext/src/lib.rs
44
+ - ext/src/ruby_api/config.rs
45
+ - ext/src/ruby_api/convert.rs
46
+ - ext/src/ruby_api/engine.rs
47
+ - ext/src/ruby_api/errors.rs
48
+ - ext/src/ruby_api/externals.rs
49
+ - ext/src/ruby_api/func.rs
50
+ - ext/src/ruby_api/func_type.rs
51
+ - ext/src/ruby_api/instance.rs
52
+ - ext/src/ruby_api/linker.rs
53
+ - ext/src/ruby_api/macros.rs
54
+ - ext/src/ruby_api/memory.rs
55
+ - ext/src/ruby_api/memory_type.rs
56
+ - ext/src/ruby_api/mod.rs
57
+ - ext/src/ruby_api/module.rs
58
+ - ext/src/ruby_api/params.rs
59
+ - ext/src/ruby_api/static_id.rs
60
+ - ext/src/ruby_api/store.rs
61
+ - ext/src/ruby_api/trap.rs
31
62
  - lib/wasmtime.rb
32
- - lib/wasmtime/refinements.rb
33
- - lib/wasmtime/require.rb
34
63
  - lib/wasmtime/version.rb
35
- - src/export.rs
36
- - src/func.rs
37
- - src/instance.rs
38
- - src/lib.rs
39
- - src/memory.rs
40
- - src/ruby_type.rs
41
- - src/vm.rs
42
- homepage: https://github.com/dtcristo/wasmtime-ruby
64
+ homepage: https://github.com/BytecodeAlliance/wasmtime-rb
43
65
  licenses:
44
- - Apache-2.0 WITH LLVM-exception
66
+ - Apache-2.0
45
67
  metadata:
46
- source_code_uri: https://github.com/dtcristo/wasmtime-ruby
47
- changelog_uri: https://github.com/dtcristo/wasmtime-ruby/blob/master/CHANGELOG.md
68
+ homepage_uri: https://github.com/BytecodeAlliance/wasmtime-rb
69
+ source_code_uri: https://github.com/BytecodeAlliance/wasmtime-rb
70
+ cargo_crate_name: ext
71
+ changelog_uri: https://github.com/bytecodealliance/wasmtime-rb/blob/main/CHANGELOG.md
48
72
  post_install_message:
49
73
  rdoc_options: []
50
74
  require_paths:
@@ -53,15 +77,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
53
77
  requirements:
54
78
  - - ">="
55
79
  - !ruby/object:Gem::Version
56
- version: 2.5.0
80
+ version: 2.7.0
57
81
  required_rubygems_version: !ruby/object:Gem::Requirement
58
82
  requirements:
59
83
  - - ">="
60
84
  - !ruby/object:Gem::Version
61
85
  version: '0'
62
86
  requirements: []
63
- rubygems_version: 3.1.2
87
+ rubygems_version: 3.3.7
64
88
  signing_key:
65
89
  specification_version: 4
66
- summary: Ruby bindings for Wasmtime, a WebAssembly runtime
90
+ summary: Wasmtime bindings for Ruby
67
91
  test_files: []
data/.cargo/config DELETED
@@ -1,4 +0,0 @@
1
- [target.x86_64-apple-darwin]
2
- rustflags = [
3
- "-C", "link-args=-undefined dynamic_lookup"
4
- ]
data/CHANGELOG.md DELETED
@@ -1,27 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [Unreleased]
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
-
16
- ## [0.1.0] - 2020-05-07
17
-
18
- ### Added
19
-
20
- - Initial release.
21
- - Support for calling exported functions on a module.
22
- - Support for 32 and 64-bit integers and floats in arguments and as return values.
23
- - Require patch for defining a Ruby module with functions for each export.
24
-
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
27
- [0.1.0]: https://github.com/dtcristo/wasmtime-ruby/releases/tag/v0.1.0
@@ -1,5 +0,0 @@
1
- clean:
2
- rake clean
3
-
4
- install:
5
- rake compile
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- import '../../lib/tasks/compile.rake'
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- unless system('rustup --version')
4
- abort 'Building native extention requires Rust with rustup (https://rustup.rs/).'
5
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rbconfig'
4
-
5
- SOEXT = RbConfig::CONFIG['SOEXT']
6
- DLEXT = RbConfig::CONFIG['DLEXT']
7
-
8
- SO = File.expand_path("../../target/release/libwasmtime_ruby.#{SOEXT}", __dir__)
9
- DL = File.expand_path("../wasmtime/native.#{DLEXT}", __dir__)
10
-
11
- desc 'Remove compile artifacts'
12
- task :clean do
13
- sh 'cargo clean'
14
- rm_rf SO
15
- rm_rf DL
16
- end
17
-
18
- desc 'Compile native extension'
19
- task :compile do
20
- unless `rustup target list`.include?('wasm32-unknown-unknown (installed)')
21
- sh 'rustup target add wasm32-unknown-unknown'
22
- end
23
-
24
- ENV['NO_LINK_RUTIE'] = '1'
25
- sh 'cargo build --release'
26
- cp SO, DL
27
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Wasmtime
4
- module Refinements
5
- refine String do
6
- def camelize(uppercase_first_letter = true)
7
- string = self
8
- if uppercase_first_letter
9
- string = string.sub(/^[a-z\d]*/, &:capitalize)
10
- else
11
- string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/, &:downcase)
12
- end
13
- string.gsub(%r{(?:_|(\/))([a-z\d]*)}) { "#{$1}#{$2.capitalize}" }.gsub(
14
- '/',
15
- '::'
16
- )
17
- end
18
- end
19
- end
20
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'wasmtime'
4
-
5
- using Wasmtime::Refinements
6
-
7
- module Kernel
8
- unless defined?(wasmtime_original_require)
9
- alias_method :wasmtime_original_require, :require
10
- private :wasmtime_original_require
11
- end
12
-
13
- def require(path)
14
- wasmtime_original_require(path)
15
- rescue LoadError => load_error
16
- try_load =
17
- Proc.new do |path, extention|
18
- path_with_extention =
19
- path.end_with?(".#{extention}") ? path : "#{path}.#{extention}"
20
-
21
- if path_with_extention.start_with?('.', '/', '~')
22
- absolute_path = File.expand_path(path_with_extention)
23
- return Wasmtime.load(absolute_path) if File.file?(absolute_path)
24
- end
25
- $LOAD_PATH.each do |load_dir|
26
- absolute_path = File.expand_path(path_with_extention, load_dir)
27
- return Wasmtime.load(absolute_path) if File.file?(absolute_path)
28
- end
29
- end
30
-
31
- try_load.call(path, 'wasm')
32
- try_load.call(path, 'wat')
33
-
34
- raise load_error
35
- end
36
-
37
- unless defined?(wasmtime_original_require_relative)
38
- alias_method :wasmtime_original_require_relative, :require_relative
39
- private :wasmtime_original_require_relative
40
- end
41
-
42
- def require_relative(path)
43
- absolute_path =
44
- File.expand_path(path, File.dirname(caller_locations[0].absolute_path))
45
- require(absolute_path)
46
- end
47
- end
48
-
49
- module Wasmtime
50
- module_function
51
-
52
- def load(absolute_path)
53
- return false if $LOADED_FEATURES.include?(absolute_path)
54
- filename = absolute_path.split(File::SEPARATOR).last
55
- module_name =
56
- if filename.end_with?('.wasm')
57
- filename.delete_suffix('.wasm')
58
- else
59
- filename.delete_suffix('.wat')
60
- end
61
- mod = Object.const_set(module_name.camelize, Module.new)
62
- instance = Wasmtime::Instance.new(absolute_path)
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
68
- end
69
- $LOADED_FEATURES << absolute_path
70
- true
71
- end
72
- end
data/src/export.rs DELETED
@@ -1,19 +0,0 @@
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
- }
data/src/func.rs DELETED
@@ -1,175 +0,0 @@
1
- use lazy_static::lazy_static;
2
- use rutie as r;
3
- use rutie::rubysys;
4
- use rutie::{
5
- class, methods, wrappable_struct, AnyObject, Array, Float, Hash, Integer, Module, NilClass,
6
- Object, RString, Symbol,
7
- };
8
- use std::mem;
9
- use wasmtime as w;
10
-
11
- use crate::ruby_type::RubyType;
12
- use crate::vm::raise;
13
-
14
- pub struct Func {
15
- func: w::Func,
16
- }
17
-
18
- impl Func {
19
- pub fn new(func: w::Func) -> Self {
20
- Func { func }
21
- }
22
-
23
- pub fn call(&mut self, args: &[w::Val]) -> Vec<w::Val> {
24
- self.func.call(args).expect("failed to call func").to_vec()
25
- }
26
-
27
- fn parse_param_types(&self) -> Vec<RubyType> {
28
- self.func
29
- .ty()
30
- .params()
31
- .iter()
32
- .map(|val_type| val_type.into())
33
- .collect()
34
- }
35
-
36
- fn parse_result_type(&self) -> RubyType {
37
- match self.func.ty().results().len() {
38
- 0 => RubyType::NilClass,
39
- 1 => self.func.ty().results().first().unwrap().into(),
40
- _ => raise("StandardError", "multiple return values are not supported"),
41
- }
42
- }
43
- }
44
-
45
- fn translate_incoming(args: Array, param_types: &[RubyType]) -> Vec<w::Val> {
46
- if args.length() != param_types.len() {
47
- raise(
48
- "ArgumentError",
49
- &format!(
50
- "wrong number of arguments (given {}, expected {})",
51
- args.length(),
52
- param_types.len()
53
- ),
54
- )
55
- }
56
- args.into_iter()
57
- .zip(param_types)
58
- .map(|(arg, param_type)| match param_type {
59
- RubyType::Integer32 => w::Val::I32(
60
- arg.try_convert_to::<Integer>()
61
- .expect("failed to convert integer")
62
- .to_i32(),
63
- ),
64
- RubyType::Integer64 => w::Val::I64(
65
- arg.try_convert_to::<Integer>()
66
- .expect("failed to convert integer")
67
- .to_i64(),
68
- ),
69
- RubyType::Float32 => w::Val::F32(
70
- (arg.try_convert_to::<Float>()
71
- .expect("failed to convert float")
72
- .to_f64() as f32)
73
- .to_bits(),
74
- ),
75
- RubyType::Float64 => w::Val::F64(
76
- arg.try_convert_to::<Float>()
77
- .expect("failed to convert float")
78
- .to_f64()
79
- .to_bits(),
80
- ),
81
- RubyType::NilClass | RubyType::Unsupported => raise(
82
- "StandardError",
83
- &format!("unsupported arg type: {:?}", param_type),
84
- ),
85
- })
86
- .collect()
87
- }
88
-
89
- fn translate_outgoing(native_results: Vec<w::Val>) -> AnyObject {
90
- let results: Vec<AnyObject> = native_results
91
- .into_iter()
92
- .map(|r| match r {
93
- w::Val::I32(v) => Integer::new(v.into()).into(),
94
- w::Val::I64(v) => Integer::new(v).into(),
95
- w::Val::F32(v) => Float::new(f32::from_bits(v).into()).into(),
96
- w::Val::F64(v) => Float::new(f64::from_bits(v)).into(),
97
- _ => raise("StandardError", &format!("unsupported value: {:?}", r)),
98
- })
99
- .collect();
100
-
101
- match results.len() {
102
- 0 => NilClass::new().into(),
103
- 1 => results.first().unwrap().into(),
104
- _ => raise("StandardError", "multiple return values are not supported"),
105
- }
106
- }
107
-
108
- wrappable_struct!(Func, FuncWrapper, FUNC_WRAPPER);
109
- class!(RubyFunc);
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
-
119
- #[rustfmt::skip]
120
- methods!(
121
- RubyFunc,
122
- itself,
123
-
124
- fn ruby_func_signature() -> Hash {
125
- let func = itself.get_data(&*FUNC_WRAPPER);
126
-
127
- let mut param_types = Array::new();
128
- for param_type in func.parse_param_types().iter() {
129
- param_types.push(RString::new_utf8(&format!("{:?}", param_type)));
130
- }
131
-
132
- let result_type: AnyObject = func.parse_result_type().into();
133
-
134
- let mut signature = Hash::new();
135
- signature.store(Symbol::new("params"), param_types);
136
- signature.store(Symbol::new("result"), result_type);
137
-
138
- signature
139
- }
140
- );
141
-
142
- pub extern "C" fn ruby_func_call(
143
- argc: r::types::Argc,
144
- argv: *const AnyObject,
145
- mut itself: AnyObject,
146
- ) -> AnyObject {
147
- // TODO: Remove this section when rutie `methods!` macro has support for variadic functions
148
- // https://github.com/danielpclark/rutie/blob/1c951b59e00944d305ca425267c54115c8c1bb86/README.md#variadic-functions--splat-operator
149
- let args_raw = r::types::Value::from(0);
150
- unsafe {
151
- let p_argv: *const r::types::Value = mem::transmute(argv);
152
- rubysys::class::rb_scan_args(
153
- argc,
154
- p_argv,
155
- r::util::str_to_cstring("*").as_ptr(),
156
- &args_raw,
157
- )
158
- };
159
- let args = Array::from(args_raw);
160
- // ---
161
- let func = itself.get_data_mut(&*FUNC_WRAPPER);
162
-
163
- let args_native = translate_incoming(args, &func.parse_param_types());
164
- let results_native = func.call(&args_native[..]);
165
- translate_outgoing(results_native)
166
- }
167
-
168
- pub fn ruby_init() {
169
- Module::from_existing("Wasmtime").define(|module| {
170
- module.define_nested_class("Func", None).define(|class| {
171
- class.def("signature", ruby_func_signature);
172
- class.def("call", ruby_func_call);
173
- });
174
- });
175
- }