diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..a7998ec9 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,49 @@ +# Check https://circleci.com/docs/2.0/language-elixir/ for more details on CircleCI configuration +version: 2 +jobs: + build: + parallelism: 1 + docker: + - image: circleci/elixir:1.9.1 + environment: + MIX_ENV: test + + working_directory: ~/repo + steps: + - checkout + + - restore_cache: + keys: + - v1-dependency-cache-{{ checksum "mix.lock" }} + - v1-dependency-cache + + - run: mix local.hex --force # install Hex locally (without prompt) + - run: mix local.rebar --force # fetch a copy of rebar (without prompt) + - run: + name: "Install Rust" + command: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable -y + source $HOME/.cargo/env + rustup component add rustfmt + rustup target add wasm32-unknown-unknown # to compile our example WASM files for testing + + - run: + name: "Run Checks (Tests, Formatters, ..)" + command: | + source $HOME/.cargo/env + mix deps.get + mix test + mix format --check-formatted + cargo fmt --manifest-path native/wasmex/Cargo.toml -- --check + mix dialyzer + mix docs + + - save_cache: + key: v1-dependency-cache-{{ checksum "mix.lock" }} + paths: + - _build + - deps + - ~/.mix + + - store_test_results: + path: _build/test/lib/wasmex diff --git a/.gitignore b/.gitignore index 3f18ac48..765e6f2c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,4 @@ erl_crash.dump wasmex-*.tar # Cargo things in the Rust part of this package -Cargo.* priv/native/libwasmex.so diff --git a/README.md b/README.md index 1a45d966..138bdb2f 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,10 @@

- - Join the Wasmer Community - - + License + [![CircleCI](https://circleci.com/gh/tessi/wasmex.svg?style=svg)](https://circleci.com/gh/tessi/wasmex)

Wasmex is an Elixir library for executing WebAssembly binaries: @@ -42,7 +40,7 @@ The docs can be found at [https://hexdocs.pm/wasmex](https://hexdocs.pm/wasmex). # Example There is a toy WASM program in `test/wasm_source/src/lib.rs`, written in Rust (but could potentially be any other language that compiles to Wasm). -It defines many funtions we use for end-to-end testing, but also serves as example code. For example: +It defines many functions we use for end-to-end testing, but also serves as example code. For example: ```rust #[no_mangle] @@ -85,7 +83,7 @@ IO.puts result # 3 All exported functions are accessible via the `call_exported_function` function. Arguments of these functions are automatically casted to WebAssembly values. Note that WebAssembly only knows number datatypes (floats and integers of various sizes). -You can pass arbritrary data to WebAssembly, though, by writing this data into its memory. The `memory` function returns a `Memory` struct representing the memory of that particular instance, e.g.: +You can pass arbitrary data to WebAssembly, though, by writing this data into its memory. The `memory` function returns a `Memory` struct representing the memory of that particular instance, e.g.: ```elixir {:ok, memory} = Wasmex.Instance.memory(instance, :uint8, 0) @@ -126,7 +124,7 @@ IO.puts Wasmex.Memory.get(memory, index) # 42 The `Memory` struct views the WebAssembly memory of an instance as an array of values of different types. Possible types are: `uint8`, `int8`, `uint16`, `int16`, `uint32`, and `int32`. -The underlying data is not changed when viewed in different types - its just its represenation that changes. +The underlying data is not changed when viewed in different types - its just its representation that changes. | View memory buffer as a sequence of… | Bytes per element | |----------|---| @@ -137,7 +135,7 @@ The underlying data is not changed when viewed in different types - its just its | `int32` | 4 | | `uint32` | 4 | -This can also be resolved programmatically: +This can also be resolved at runtime: ```elixir {:ok, memory} = Wasmex.Instance.memory(instance, :uint16, 0) @@ -225,9 +223,9 @@ pub extern "C" fn string() -> *const u8 { ``` This function returns a pointer to its memory. -This memory location contains the String "Hellow, World!" (ending with a null-byte since in C-land all strings end with a null-byte to mark the end of the string). +This memory location contains the String "Hello, World!" (ending with a null-byte since in C-land all strings end with a null-byte to mark the end of the string). -Thsi is how we would receive this String in Elixir: +This is how we would receive this String in Elixir: ```elixir bytes = File.read!(TestHelper.wasm_file_path) diff --git a/lib/wasmex/instance.ex b/lib/wasmex/instance.ex index f0c0c908..e92e7957 100644 --- a/lib/wasmex/instance.ex +++ b/lib/wasmex/instance.ex @@ -18,7 +18,7 @@ defmodule Wasmex.Instance do All exported functions are accessible via the `call_exported_function` function. Arguments of these functions are automatically casted to WebAssembly values. Note that WebAssembly only knows number datatypes (floats and integers of various sizes). - You can pass arbritrary data to WebAssembly, though, by writing this data into its memory. The `memory` function returns a `Memory` struct representing the memory of that particular instance, e.g.: + You can pass arbitrary data to WebAssembly, though, by writing this data into its memory. The `memory` function returns a `Memory` struct representing the memory of that particular instance, e.g.: ```elixir {:ok, memory} = Wasmex.Instance.memory(instance, :uint8, 0) @@ -35,7 +35,7 @@ defmodule Wasmex.Instance do # Normally the compiler will happily do stuff like inlining the # resource in attributes. This will convert the resource into an # empty binary with no warning. This will make that harder to - # accidentaly do. + # accidentally do. # It also serves as a handy way to tell file handles apart. reference: nil @@ -70,7 +70,8 @@ defmodule Wasmex.Instance do Wasmex.Native.instance_call_exported_function(resource, name, params) end - @spec memory(__MODULE__.t(), atom(), pos_integer()) :: {:error, binary()} | {:ok, Wasmex.Memory.t()} + @spec memory(__MODULE__.t(), atom(), pos_integer()) :: + {:error, binary()} | {:ok, Wasmex.Memory.t()} def memory(%__MODULE__{} = instance, size, offset) when size in [:uint8, :int8, :uint16, :int16, :uint32, :int32] do Wasmex.Memory.from_instance(instance, size, offset) diff --git a/lib/wasmex/memory.ex b/lib/wasmex/memory.ex index bbff88d3..9d1043ec 100644 --- a/lib/wasmex/memory.ex +++ b/lib/wasmex/memory.ex @@ -29,7 +29,7 @@ defmodule Wasmex.Memory do The `Memory` struct views the WebAssembly memory of an instance as an array of values of different types. Possible types are: `uint8`, `int8`, `uint16`, `int16`, `uint32`, and `int32`. - The underlying data is not changed when viewed in different types - its just its represenation that changes. + The underlying data is not changed when viewed in different types - its just its representation that changes. | View memory buffer as a sequence of… | Bytes per element | |----------|---| @@ -51,7 +51,7 @@ defmodule Wasmex.Memory do # Normally the compiler will happily do stuff like inlining the # resource in attributes. This will convert the resource into an # empty binary with no warning. This will make that harder to - # accidentaly do. + # accidentally do. # It also serves as a handy way to tell file handles apart. reference: nil, size: nil, @@ -62,7 +62,8 @@ defmodule Wasmex.Memory do from_instance(instance, :uint8, 0) end - @spec from_instance(Wasmex.Instance.t(), atom(), non_neg_integer()) :: {:error, binary()} | {:ok, __MODULE__.t()} + @spec from_instance(Wasmex.Instance.t(), atom(), non_neg_integer()) :: + {:error, binary()} | {:ok, __MODULE__.t()} def from_instance(%Wasmex.Instance{resource: resource}, size, offset) when size in [:uint8, :int8, :uint16, :int16, :uint32, :int32] do case Wasmex.Native.memory_from_instance(resource) do @@ -185,7 +186,8 @@ defmodule Wasmex.Memory do write_binary(memory, memory.size, memory.offset, index, str) end - @spec write_binary(__MODULE__.t(), atom(), non_neg_integer(), non_neg_integer(), binary()) :: :ok + @spec write_binary(__MODULE__.t(), atom(), non_neg_integer(), non_neg_integer(), binary()) :: + :ok def write_binary(%Wasmex.Memory{resource: resource}, size, offset, index, str) when is_binary(str) do # strings a null-byte terminated in C-land diff --git a/mix.exs b/mix.exs index 26473db1..476646a3 100644 --- a/mix.exs +++ b/mix.exs @@ -31,8 +31,8 @@ defmodule Wasmex.MixProject do defp deps do [ {:rustler, "~> 0.21.0"}, - {:ex_doc, "~> 0.21.2", only: :dev}, - {:dialyxir, "~> 1.0.0-rc.7", only: [:dev], runtime: false} + {:ex_doc, "~> 0.21.2", only: [:dev, :test]}, + {:dialyxir, "~> 1.0.0-rc.7", only: [:dev, :test], runtime: false} ] end diff --git a/test/wasm_source/Cargo.lock b/test/wasm_source/Cargo.lock new file mode 100644 index 00000000..417f9c93 --- /dev/null +++ b/test/wasm_source/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "wasmex_test" +version = "0.1.0" diff --git a/test/wasm_source/Cargo.toml b/test/wasm_source/Cargo.toml new file mode 100644 index 00000000..df2b3614 --- /dev/null +++ b/test/wasm_source/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "wasmex_test" +version = "0.1.0" +authors = ["Philipp Tessenow "] +edition = "2018" + +[dependencies] + +[lib] +crate-type =["cdylib"]