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