Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request : new classes Uint64View, Int64View, Float32View, and Float64View #70

Open
kojix2 opened this issue Dec 10, 2022 · 1 comment
Labels
🎉 enhancement New feature or request

Comments

@kojix2
Copy link
Contributor

kojix2 commented Dec 10, 2022

Hi!
Thank you for creating very useful library.

Motivation

I am building a tool as a hobby to call WebAssembly functions generated by Crystal language from Ruby to speed up. When I tried to pass a Ruby array to Wasm, I noticed that int64_view, uint64_view, float32_view, and float64_view were not yet provided.

Proposed solution

new methods: uint64_view, int64_view, float32_view, and float64_view
new classes Uint64View, Int64View, Float32View, and Float64View

Alternatives

The use of binary strings is a possible alternative. In that case, Ruby methods such as pack and unpack could be used.

Additional context

You can find similar functionality in Python bindings.
wasmerio/wasmer-python@b484654

@kojix2 kojix2 added the 🎉 enhancement New feature or request label Dec 10, 2022
@kojix2
Copy link
Contributor Author

kojix2 commented Dec 17, 2022

The method mentioned in the "Alternative" section using a binary string with pack and unpack is the method used in wasmtime-rb.
These are Memory#read(offset, size) and Memory#write(offset, value). I think this is a very easy-to-use and highly versatile method. Therefore, it might be better to adopt this method rather than adding a new View.

I am a little unsure if the code below is completely correct, but it should work like this.

Write:

      memory.write(
        addr,
        case type
        when 'int8'    then arg.pack('c*')
        when 'uint8'   then arg.pack('C*')
        when 'int16'   then arg.pack('s*')
        when 'uint16'  then arg.pack('S*')
        when 'int32'   then arg.pack('l*')
        when 'uint32'  then arg.pack('L*')
        when 'int64'   then arg.pack('q*')
        when 'uint64'  then arg.pack('Q*')
        when 'float32' then arg.pack('e*')
        when 'float64' then arg.pack('E*')
        else raise "unsupported type: #{type}"
        end
      )

Read:

      case type
      when 'int8'    then memory.read(addr, len * 1).unpack('c*')
      when 'uint8'   then memory.read(addr, len * 1).unpack('C*')
      when 'int16'   then memory.read(addr, len * 2).unpack('s*')
      when 'uint16'  then memory.read(addr, len * 2).unpack('S*')
      when 'int32'   then memory.read(addr, len * 4).unpack('l*')
      when 'uint32'  then memory.read(addr, len * 4).unpack('L*')
      when 'int64'   then memory.read(addr, len * 8).unpack('q*')
      when 'uint64'  then memory.read(addr, len * 8).unpack('Q*')
      when 'float32' then memory.read(addr, len * 4).unpack('e*')
      when 'float64' then memory.read(addr, len * 8).unpack('E*')
      else raise "unsupported type: #{type}"
      end

Of course, the same thing can be done with the current version of wasmer-ruby using uint8_view.

Write:

      uint8_view = memory.uint8_view(addr)
      arg_uint8 = case type
                  when 'int8'    then arg.pack('c*')
                  when 'uint8'   then arg.pack('C*')
                  when 'int16'   then arg.pack('s*')
                  when 'uint16'  then arg.pack('S*')
                  when 'int32'   then arg.pack('l*')
                  when 'uint32'  then arg.pack('L*')
                  when 'int64'   then arg.pack('q*')
                  when 'uint64'  then arg.pack('Q*')
                  when 'float32' then arg.pack('e*')
                  when 'float64' then arg.pack('E*')
                  else raise "unsupported type: #{type}"
                  end.unpack('C*')
      arg_uint8.each_with_index do |a, i|
        uint8_view[i] = a
      end

Read:

      uint8_view = memory.uint8_view(addr)
      case type
      when 'int8'    then Array.new(len * 1) { |i| uint8_view[i] }.pack('C*').unpack('c*')
      when 'uint8'   then Array.new(len * 1) { |i| uint8_view[i] }.pack('C*').unpack('C*')
      when 'int16'   then Array.new(len * 2) { |i| uint8_view[i] }.pack('C*').unpack('s*')
      when 'uint16'  then Array.new(len * 2) { |i| uint8_view[i] }.pack('C*').unpack('S*')
      when 'int32'   then Array.new(len * 4) { |i| uint8_view[i] }.pack('C*').unpack('l*')
      when 'uint32'  then Array.new(len * 4) { |i| uint8_view[i] }.pack('C*').unpack('L*')
      when 'int64'   then Array.new(len * 8) { |i| uint8_view[i] }.pack('C*').unpack('q*')
      when 'uint64'  then Array.new(len * 8) { |i| uint8_view[i] }.pack('C*').unpack('Q*')
      when 'float32' then Array.new(len * 4) { |i| uint8_view[i] }.pack('C*').unpack('e*')
      when 'float64' then Array.new(len * 8) { |i| uint8_view[i] }.pack('C*').unpack('E*')
      else raise "unsupported type: #{type}"
      end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🎉 enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant