Add js version of runtime that supports interface types and runs in browser (#137)

This commit is contained in:
Valery Antopol
2022-02-18 18:26:06 +03:00
committed by GitHub
parent 6dfeecd572
commit bbd006ed3c
69 changed files with 11489 additions and 283 deletions

View File

@ -1,4 +1,7 @@
version: 2.1 version: 2.1
orbs:
node: circleci/node@5.0.0
jobs: jobs:
marine: marine:
docker: docker:
@ -12,6 +15,10 @@ jobs:
- restore_cache: - restore_cache:
keys: keys:
- marine04-{{ checksum "Cargo.lock" }} - marine04-{{ checksum "Cargo.lock" }}
- node/install:
node-version: '16.14'
- run: | - run: |
rustup toolchain install nightly-2021-05-21 rustup toolchain install nightly-2021-05-21
rustup default nightly-2021-05-21 rustup default nightly-2021-05-21
@ -21,17 +28,31 @@ jobs:
rustup component add clippy --toolchain nightly-2021-05-21 rustup component add clippy --toolchain nightly-2021-05-21
rustup target add wasm32-wasi rustup target add wasm32-wasi
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
cargo install --path tools/cli cargo install --path tools/cli
cargo fmt --all -- --check --color always cargo fmt --all -- --check --color always
cargo check -v --all-features -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl cargo check -v --all-features -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl
(
cd web-runtime
./build.sh
cd npm-package
npm i
npm run build
)
(cd ./examples; ./build.sh) (cd ./examples; ./build.sh)
(cd ./fluence-faas/tests/wasm_tests; ./build.sh) (cd ./fluence-faas/tests/wasm_tests; ./build.sh)
cargo test --release -v --all-features -p marine-it-generator -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl cargo test --release -v --all-features -p marine-it-generator -p marine-runtime -p fluence-faas -p fluence-app-service -p marine -p mrepl
cargo clippy cargo clippy
(
cd web-runtime/npm-package
npm run test
)
- save_cache: - save_cache:
paths: paths:
- ~/.cargo - ~/.cargo

144
.github/workflows/publish_npm_dev.yml vendored Normal file
View File

@ -0,0 +1,144 @@
# run locally like this:
# act -b -P ubuntu-latest=nektos/act-environments-ubuntu:18.04 -j publish-npm-branch -s "NPM_TOKEN=uuid-uuid-uuid-uuid"
name: "publish-npm-branch"
on:
push:
branches-ignore:
- master
jobs:
npm-publish-dev:
name: "Publish marine-js package to NPM"
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
### Extract branch name
- name: Extract branch name
if: github.event_name != 'pull_request'
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
id: extract_branch
- name: Extract branch name
if: github.event_name == 'pull_request'
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v2
### Prepare cargo & toolchains
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin
key: ${{ runner.os }}-cargo-v2-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust toolchain with wasm32-unknown-unknown
uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2022-01-25
target: wasm32-unknown-unknown
profile: minimal
override: true
- uses: actions-rs/cargo@v1
with:
toolchain: nightly-2022-01-25
command: update
args: --aggressive
### Calculate FINAL_VERSION
- name: Install jq & sponge
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq moreutils
- name: Install cargo-show & toml-cli
run: cargo install cargo-show toml-cli || true
- name: Get versions from npm & crates.io, and take the highest one
run: |
set -x
# install semver and add it to PATH
yarn global add semver
PATH="$(yarn global bin):$PATH"
MARINE_JS_CARGO_TOML="web-runtime/Cargo.toml"
CARGO_TOML="web-runtime/Cargo.toml"
PACKAGE_JSON="web-runtime/npm-package/package.json"
# sanitize branch name so it can be used as a semver suffix (replace [^0-9a-zA-Z-] with hyphen)
SANITIZED_BRANCH="$(echo -n "${{ env.BRANCH_NAME }}" | tr -C '[:alnum:]-' -)"
# JQ Version regex pattern
PAT="\\\\d+.\\\\d+.\\\\d+-$SANITIZED_BRANCH.\\\\d+"
# get package name from Cargo.toml
PKG_NAME="$(toml get "$CARGO_TOML" package.name | tr -d \")"
# get package name from package.json
JS_PKG_NAME="$(cat "$PACKAGE_JSON" | jq -r .name)"
### NPM
# take all versions from npm and replace single quotes with double quotes
NPM_VERSIONS=$(yarn info --silent "$JS_PKG_NAME" versions 2>/dev/null | tr \' \")
# take only versions that contain branch name
NPM_VERSIONS_FILTERED=$(echo $NPM_VERSIONS | jq -r ".[] | select(test(\"$PAT\"))")
# flatten into a single line
NPM_VERSIONS_FLATTENED=$(echo $NPM_VERSIONS_FILTERED | awk '{print}' ORS=' ')
# sort versions according to semver, take highest (last)
LAST_NPM_VERSION="$(semver -p $(echo $NPM_VERSIONS_FLATTENED) | tail -n1 || true)"
# increment prerelease part of the version
PRERELEASE_NPM_VERSION="$(semver --increment prerelease --preid "$SANITIZED_BRANCH" "${LAST_NPM_VERSION}" || true)"
### CRATES.IO
CRATE_VERSIONS=$(cargo show --json "$PKG_NAME")
CRATE_VERSIONS_FILTERED=$(echo $CRATE_VERSIONS | jq -r ".versions[] | .num | select(test(\"$PAT\"))")
CRATE_VERSIONS_FLATTENED=$(echo $CRATE_VERSIONS_FILTERED | awk '{print}' ORS=' ')
LAST_CRATE_VERSION="$(semver -p $(echo $CRATE_VERSIONS_FLATTENED) | tail -n1 || true)"
PRERELEASE_CRATE_VERSION="$(semver --increment prerelease --preid "$SANITIZED_BRANCH" "${LAST_CRATE_VERSION}" || true)"
### LOCAL
### (NOTE: the following code assumes that local versions do not contain prerelease suffix; existing suffix will be ignored)
# take local Rust version
LOCAL_RUST_VERSION="$(toml get "$CARGO_TOML" package.version | tr -d \")"
MARINE_JS_RUST_VERSION="$(toml get "$MARINE_JS_CARGO_TOML" package.version | tr -d \")"
MAX_RUST_VERSION="$(semver "$LOCAL_RUST_VERSION" "MARINE_JS_RUST_VERSION" | tail -n1)"
LOCAL_RUST_PRERELEASE_VERSION="$(semver --increment prerelease --preid "$SANITIZED_BRANCH" "${MAX_RUST_VERSION}-0")" # added '-0' here to avoid semver erroneously increment patch octet. Any suffix works, '-0' is chosen deliberately.
### SAVE FINAL VERSION TO ENV
# take the highest version
MAX_VERSION="$(semver "$LOCAL_RUST_PRERELEASE_VERSION" "$PRERELEASE_NPM_VERSION" "$PRERELEASE_CRATE_VERSION" | tail -n1)"
# save info to env
echo "FINAL_VERSION=$MAX_VERSION" | tee -a $GITHUB_ENV
echo "PKG_NAME=$PKG_NAME" | tee -a $GITHUB_ENV
echo "JS_PKG_NAME=$JS_PKG_NAME" | tee -a $GITHUB_ENV
### === JavaScript package release ===
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
continue-on-error: true
- name: Build npm package
working-directory: web-runtime
run: |
./build.sh
cd npm-package
npm i
npm run build
### Set version to FINAL_VERSION
- run: yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version || true
working-directory: web-runtime/npm-package
### Publish to NPM registry
- uses: actions/setup-node@v1
with:
node-version: "16"
registry-url: "https://registry.npmjs.org"
- run: npm publish --access public --tag=beta
working-directory: web-runtime/npm-package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -0,0 +1,120 @@
# run locally like this:
# act -b -P ubuntu-latest=nektos/act-environments-ubuntu:18.04 -j publish-interpreter -s "NPM_TOKEN=uuid-uuid-uuid-uuid"
name: "publish-npm-release"
on:
push:
branches:
- "master"
jobs:
npm-publish:
name: "Publish web-runtime to NPM"
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v2
### Prepare cargo & toolchains
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin
target
key: ${{ runner.os }}-cargo-v2-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust toolchain with wasm32-unknown-unknown
uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2022-01-25
target: wasm32-unknown-unknown
profile: minimal
override: true
- uses: actions-rs/cargo@v1
with:
toolchain: nightly-2022-01-25
command: update
args: --aggressive
### Calculate FINAL_VERSION
- name: Install jq & sponge
run: sudo apt-get update && sudo apt-get --yes --force-yes install jq moreutils
- name: Install cargo-show & toml-cli
run: cargo install cargo-show toml-cli || true
- name: Get versions from npm & crates.io, and take the highest one
run: |
set -x
# install semver and add it to PATH
yarn global add semver
PATH="$(yarn global bin):$PATH"
# JQ version regex pattern
PAT="\\\\d+.\\\\d+.\\\\d+"
MARINE_JS_CARGO_TOML="web-runtime/Cargo.toml"
CARGO_TOML="web-runtime/Cargo.toml"
PACKAGE_JSON="web-runtime/npm-package/package.json"
# get package name from Cargo.toml
RS_PKG_NAME="$(toml get "$CARGO_TOML" package.name | tr -d \")"
# get package name from package.json
JS_PKG_NAME="$(cat "$PACKAGE_JSON" | jq -r .name)"
# get version from Cargo.toml
MARINE_JS_RUST_VERSION="$(toml get "$MARINE_JS_CARGO_TOML" package.version | tr -d \")"
LOCAL_RUST_VERSION="$(toml get "$CARGO_TOML" package.version | tr -d \")"
# get & increment version from NPM
JS_VERSIONS=$(yarn info --silent "$JS_PKG_NAME" versions | tr \' \" | jq -r ".[] | select(test(\"$PAT\"))" || true)
JS_VERSION="$(semver -p $JS_VERSIONS | tail -n1)"
NEXT_JS_VERSION="$(semver --increment patch "$JS_VERSION" || true)"
# get & increment version from crates.io
CRATE_VERSIONS=$(cargo show --json "$RS_PKG_NAME")
CRATE_VERSIONS_FILTERED=$(echo $CRATE_VERSIONS | jq -r ".versions[] | .num | select(test(\"$PAT\"))")
MAX_RS_VERSION="$(semver -p $CRATE_VERSIONS_FILTERED | tail -n1 || true)"
NEXT_RS_VERSION="$(semver --increment patch "$MAX_RS_VERSION" || true)"
# take the highest version
MAX_VERSION="$(semver "$NEXT_JS_VERSION" "$NEXT_RS_VERSION" "$LOCAL_RUST_VERSION" "MARINE_JS_RUST_VERSION" | tail -n1)"
echo "FINAL_VERSION=$MAX_VERSION" | tee -a $GITHUB_ENV
echo "JS_PKG_NAME=$JS_PKG_NAME" | tee -a $GITHUB_ENV
### === JavaScript package release ===
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
continue-on-error: true
- name: Build npm package
working-directory: web-runtime
run: |
./build.sh
cd npm-package
npm i
npm run build
### Set version
- name: Set version to ${{ env.FINAL_VERSION }}
run: yarn version --new-version ${{ env.FINAL_VERSION }} --no-git-tag-version
working-directory: web-runtime/npm-package
### Publish to NPM registry
- uses: actions/setup-node@v1
with:
node-version: "16"
registry-url: "https://registry.npmjs.org"
- run: npm publish --access public
working-directory: web-runtime/npm-package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

365
Cargo.lock generated
View File

@ -92,9 +92,9 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
@ -218,9 +218,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.72" version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -243,7 +243,7 @@ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
"reqwest 0.11.9", "reqwest 0.11.9",
"semver 1.0.4", "semver 1.0.5",
"serde", "serde",
] ]
@ -291,6 +291,16 @@ version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "475bd7aa7680b4ed8f6bb59745e882bcbaeb39326532bb79ffb1716480d9a274" checksum = "475bd7aa7680b4ed8f6bb59745e882bcbaeb39326532bb79ffb1716480d9a274"
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen",
]
[[package]] [[package]]
name = "constant_time_eq" name = "constant_time_eq"
version = "0.1.5" version = "0.1.5"
@ -306,9 +316,9 @@ dependencies = [
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.2" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -403,9 +413,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.6" version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"crossbeam-utils", "crossbeam-utils",
@ -416,9 +426,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.6" version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"lazy_static", "lazy_static",
@ -776,11 +786,12 @@ dependencies = [
[[package]] [[package]]
name = "fluence-app-service" name = "fluence-app-service"
version = "0.13.0" version = "0.14.0"
dependencies = [ dependencies = [
"fluence-faas 0.12.0", "fluence-faas 0.13.0",
"log", "log",
"maplit", "maplit",
"marine-min-it-version",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@ -797,7 +808,7 @@ dependencies = [
"cmd_lib", "cmd_lib",
"itertools 0.9.0", "itertools 0.9.0",
"log", "log",
"marine-module-interface 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "marine-module-interface 0.1.6",
"marine-rs-sdk", "marine-rs-sdk",
"marine-rs-sdk-main", "marine-rs-sdk-main",
"marine-runtime 0.7.2", "marine-runtime 0.7.2",
@ -808,7 +819,7 @@ dependencies = [
"serde_json", "serde_json",
"thiserror", "thiserror",
"toml", "toml",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.20.2",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
"wasmer-runtime-fl", "wasmer-runtime-fl",
"wasmer-wasi-fl", "wasmer-wasi-fl",
@ -816,17 +827,17 @@ dependencies = [
[[package]] [[package]]
name = "fluence-faas" name = "fluence-faas"
version = "0.12.0" version = "0.13.0"
dependencies = [ dependencies = [
"bytesize", "bytesize",
"cmd_lib", "cmd_lib",
"env_logger 0.7.1", "env_logger 0.7.1",
"itertools 0.9.0", "itertools 0.9.0",
"log", "log",
"marine-module-interface 0.1.6", "marine-module-interface 0.2.0",
"marine-rs-sdk", "marine-rs-sdk",
"marine-rs-sdk-main", "marine-rs-sdk-main",
"marine-runtime 0.10.0", "marine-runtime 0.11.0",
"marine-utils 0.4.0", "marine-utils 0.4.0",
"once_cell", "once_cell",
"pretty_assertions", "pretty_assertions",
@ -837,7 +848,7 @@ dependencies = [
"serde_with", "serde_with",
"thiserror", "thiserror",
"toml", "toml",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.21.1",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
"wasmer-runtime-fl", "wasmer-runtime-fl",
"wasmer-wasi-fl", "wasmer-wasi-fl",
@ -905,42 +916,42 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.19" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
dependencies = [ dependencies = [
"futures-core", "futures-core",
] ]
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.19" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.19" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.19" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.19" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.19" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-io", "futures-io",
@ -1072,7 +1083,7 @@ dependencies = [
"http", "http",
"indexmap", "indexmap",
"slab", "slab",
"tokio 1.16.1", "tokio 1.17.0",
"tokio-util 0.6.9", "tokio-util 0.6.9",
"tracing", "tracing",
] ]
@ -1141,9 +1152,9 @@ dependencies = [
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.5.1" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
[[package]] [[package]]
name = "httpdate" name = "httpdate"
@ -1192,9 +1203,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.16" version = "0.14.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"futures-channel", "futures-channel",
@ -1205,10 +1216,10 @@ dependencies = [
"http-body 0.4.4", "http-body 0.4.4",
"httparse", "httparse",
"httpdate 1.0.2", "httpdate 1.0.2",
"itoa 0.4.8", "itoa 1.0.1",
"pin-project-lite 0.2.8", "pin-project-lite 0.2.8",
"socket2 0.4.4", "socket2 0.4.4",
"tokio 1.16.1", "tokio 1.17.0",
"tower-service", "tower-service",
"tracing", "tracing",
"want", "want",
@ -1234,9 +1245,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"hyper 0.14.16", "hyper 0.14.17",
"native-tls", "native-tls",
"tokio 1.16.1", "tokio 1.17.0",
"tokio-native-tls", "tokio-native-tls",
] ]
@ -1336,6 +1347,28 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "it-lilo"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4779ed9b3289f03294743f26112366a59eb53c5d05b5b6afbfd7ce8780944cfd"
dependencies = [
"fluence-it-types",
"it-memory-traits",
"log",
"paste",
"thiserror",
]
[[package]]
name = "it-memory-traits"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b1f9aa4bd18db30d0ed34e0119486f21cf49f08bfe96e44cb54930c4db403af"
dependencies = [
"thiserror",
]
[[package]] [[package]]
name = "it-to-bytes" name = "it-to-bytes"
version = "0.1.0" version = "0.1.0"
@ -1418,9 +1451,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.116" version = "0.2.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74" checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94"
[[package]] [[package]]
name = "local_storage" name = "local_storage"
@ -1457,7 +1490,7 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "marine" name = "marine"
version = "0.6.13" version = "0.7.0"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"anyhow", "anyhow",
@ -1465,8 +1498,8 @@ dependencies = [
"check-latest", "check-latest",
"clap", "clap",
"exitfailure", "exitfailure",
"marine-it-generator 0.5.6", "marine-it-generator 0.6.0",
"marine-it-parser 0.6.8", "marine-it-parser 0.7.0",
"marine-module-info-parser 0.2.2", "marine-module-info-parser 0.2.2",
"semver 0.11.0", "semver 0.11.0",
"serde", "serde",
@ -1488,9 +1521,11 @@ dependencies = [
[[package]] [[package]]
name = "marine-it-generator" name = "marine-it-generator"
version = "0.5.6" version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "890b228b9151e9dff213501986f564445a2f9ca5a706088b5d900f5ecf67f7e7"
dependencies = [ dependencies = [
"cargo_toml", "cargo_toml",
"it-lilo", "it-lilo 0.1.0",
"marine-it-parser 0.6.8", "marine-it-parser 0.6.8",
"marine-macro-impl", "marine-macro-impl",
"once_cell", "once_cell",
@ -1498,33 +1533,23 @@ dependencies = [
"serde_json", "serde_json",
"thiserror", "thiserror",
"walrus", "walrus",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.20.2",
] ]
[[package]] [[package]]
name = "marine-it-generator" name = "marine-it-generator"
version = "0.5.6" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "890b228b9151e9dff213501986f564445a2f9ca5a706088b5d900f5ecf67f7e7"
dependencies = [ dependencies = [
"cargo_toml", "cargo_toml",
"it-lilo", "it-lilo 0.2.0",
"marine-it-parser 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-parser 0.7.0",
"marine-macro-impl", "marine-macro-impl",
"once_cell", "once_cell",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
"walrus", "walrus",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.21.1",
]
[[package]]
name = "marine-it-interfaces"
version = "0.4.1"
dependencies = [
"multimap",
"wasmer-interface-types-fl",
] ]
[[package]] [[package]]
@ -1534,24 +1559,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42e229143e72ba20e754de4766ff0d02e0cf176001f7471593f82b16c72dc26d" checksum = "42e229143e72ba20e754de4766ff0d02e0cf176001f7471593f82b16c72dc26d"
dependencies = [ dependencies = [
"multimap", "multimap",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.20.2",
] ]
[[package]] [[package]]
name = "marine-it-parser" name = "marine-it-interfaces"
version = "0.6.8" version = "0.5.0"
dependencies = [ dependencies = [
"anyhow", "multimap",
"itertools 0.10.3", "wasmer-interface-types-fl 0.21.1",
"marine-it-interfaces 0.4.1",
"marine-module-interface 0.1.6",
"nom",
"semver 0.11.0",
"serde",
"thiserror",
"walrus",
"wasmer-interface-types-fl",
"wasmer-runtime-core-fl",
] ]
[[package]] [[package]]
@ -1562,14 +1578,31 @@ checksum = "edd97bd85072fc540763769be153a7c8ee83391e668b37ef96d6c48decec2cd5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.10.3", "itertools 0.10.3",
"marine-it-interfaces 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-interfaces 0.4.1",
"marine-module-interface 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "marine-module-interface 0.1.6",
"nom", "nom",
"semver 0.11.0", "semver 0.11.0",
"serde", "serde",
"thiserror", "thiserror",
"walrus", "walrus",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.20.2",
"wasmer-runtime-core-fl",
]
[[package]]
name = "marine-it-parser"
version = "0.7.0"
dependencies = [
"anyhow",
"itertools 0.10.3",
"marine-it-interfaces 0.5.0",
"marine-module-interface 0.2.0",
"nom",
"semver 0.11.0",
"serde",
"thiserror",
"walrus",
"wasmer-interface-types-fl 0.21.1",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
] ]
@ -1597,6 +1630,14 @@ dependencies = [
"uuid", "uuid",
] ]
[[package]]
name = "marine-min-it-version"
version = "0.1.0"
dependencies = [
"once_cell",
"semver 0.11.0",
]
[[package]] [[package]]
name = "marine-module-info-parser" name = "marine-module-info-parser"
version = "0.2.2" version = "0.2.2"
@ -1630,6 +1671,8 @@ dependencies = [
[[package]] [[package]]
name = "marine-module-interface" name = "marine-module-interface"
version = "0.1.6" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06bc36ef268bf7436916f1fa9b0c84104692a717ea5eef3c90b9f25c3407f6b7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.10.3", "itertools 0.10.3",
@ -1639,26 +1682,23 @@ dependencies = [
"serde", "serde",
"thiserror", "thiserror",
"walrus", "walrus",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.20.2",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
] ]
[[package]] [[package]]
name = "marine-module-interface" name = "marine-module-interface"
version = "0.1.6" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06bc36ef268bf7436916f1fa9b0c84104692a717ea5eef3c90b9f25c3407f6b7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.10.3", "itertools 0.10.3",
"marine-it-interfaces 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-interfaces 0.5.0",
"nom", "nom",
"semver 0.11.0", "semver 0.11.0",
"serde", "serde",
"thiserror", "thiserror",
"walrus", "walrus",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.21.1",
"wasmer-runtime-core-fl",
] ]
[[package]] [[package]]
@ -1706,13 +1746,13 @@ checksum = "983262d394c59d4321b141e303eb55015bc412f319d54bbad7f253e4583253b2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"boolinator", "boolinator",
"it-lilo", "it-lilo 0.1.0",
"log", "log",
"marine-it-generator 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-generator 0.5.6",
"marine-it-interfaces 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-interfaces 0.4.1",
"marine-it-parser 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-parser 0.6.8",
"marine-module-info-parser 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "marine-module-info-parser 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"marine-module-interface 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "marine-module-interface 0.1.6",
"marine-utils 0.2.0", "marine-utils 0.2.0",
"multimap", "multimap",
"once_cell", "once_cell",
@ -1722,7 +1762,7 @@ dependencies = [
"semver 0.11.0", "semver 0.11.0",
"serde", "serde",
"thiserror", "thiserror",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.20.2",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
"wasmer-runtime-fl", "wasmer-runtime-fl",
"wasmer-wasi-fl", "wasmer-wasi-fl",
@ -1730,19 +1770,21 @@ dependencies = [
[[package]] [[package]]
name = "marine-runtime" name = "marine-runtime"
version = "0.10.0" version = "0.11.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"boolinator", "boolinator",
"bytes 0.5.6", "bytes 0.5.6",
"bytesize", "bytesize",
"it-lilo", "it-lilo 0.2.0",
"it-memory-traits",
"log", "log",
"marine-it-generator 0.5.6", "marine-it-generator 0.6.0",
"marine-it-interfaces 0.4.1", "marine-it-interfaces 0.5.0",
"marine-it-parser 0.6.8", "marine-it-parser 0.7.0",
"marine-min-it-version",
"marine-module-info-parser 0.2.2", "marine-module-info-parser 0.2.2",
"marine-module-interface 0.1.6", "marine-module-interface 0.2.0",
"marine-utils 0.4.0", "marine-utils 0.4.0",
"multimap", "multimap",
"once_cell", "once_cell",
@ -1754,7 +1796,7 @@ dependencies = [
"serde", "serde",
"thiserror", "thiserror",
"tokio 0.2.25", "tokio 0.2.25",
"wasmer-interface-types-fl", "wasmer-interface-types-fl 0.21.1",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
"wasmer-runtime-fl", "wasmer-runtime-fl",
"wasmer-wasi-fl", "wasmer-wasi-fl",
@ -1791,7 +1833,7 @@ dependencies = [
"darling 0.12.4", "darling 0.12.4",
"fluence-app-service 0.10.2", "fluence-app-service 0.10.2",
"itertools 0.10.3", "itertools 0.10.3",
"marine-it-parser 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "marine-it-parser 0.6.8",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1820,6 +1862,41 @@ checksum = "8dc5838acba84ce4d802d672afd0814fae0ae7098021ae5b06d975e70d09f812"
name = "marine-utils" name = "marine-utils"
version = "0.4.0" version = "0.4.0"
[[package]]
name = "marine-web-runtime"
version = "0.1.0"
dependencies = [
"anyhow",
"boolinator",
"bytesize",
"console_error_panic_hook",
"fluence-it-types",
"it-lilo 0.2.0",
"it-memory-traits",
"itertools 0.10.3",
"log",
"maplit",
"marine-it-interfaces 0.5.0",
"marine-min-it-version",
"marine-module-interface 0.2.0",
"marine-rs-sdk",
"marine-utils 0.4.0",
"multimap",
"nom",
"once_cell",
"paste",
"semver 0.11.0",
"serde",
"serde_derive",
"serde_json",
"serde_with",
"thiserror",
"toml",
"wasm-bindgen",
"wasmer-interface-types-fl 0.21.1",
"web-sys",
]
[[package]] [[package]]
name = "matches" name = "matches"
version = "0.1.9" version = "0.1.9"
@ -1859,9 +1936,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]] [[package]]
name = "mime_guess" name = "mime_guess"
version = "2.0.3" version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
dependencies = [ dependencies = [
"mime", "mime",
"unicase", "unicase",
@ -1898,9 +1975,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.7.14" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@ -1932,13 +2009,13 @@ dependencies = [
[[package]] [[package]]
name = "mrepl" name = "mrepl"
version = "0.12.0" version = "0.13.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"check-latest", "check-latest",
"clap", "clap",
"env_logger 0.7.1", "env_logger 0.7.1",
"fluence-app-service 0.13.0", "fluence-app-service 0.14.0",
"itertools 0.9.0", "itertools 0.9.0",
"log", "log",
"marine-rs-sdk-main", "marine-rs-sdk-main",
@ -2048,9 +2125,9 @@ dependencies = [
[[package]] [[package]]
name = "ntapi" name = "ntapi"
version = "0.3.6" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
dependencies = [ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -2140,9 +2217,9 @@ dependencies = [
[[package]] [[package]]
name = "output_vt100" name = "output_vt100"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
dependencies = [ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -2537,7 +2614,7 @@ dependencies = [
"h2 0.3.11", "h2 0.3.11",
"http", "http",
"http-body 0.4.4", "http-body 0.4.4",
"hyper 0.14.16", "hyper 0.14.17",
"hyper-tls 0.5.0", "hyper-tls 0.5.0",
"ipnet", "ipnet",
"js-sys", "js-sys",
@ -2550,7 +2627,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"tokio 1.16.1", "tokio 1.17.0",
"tokio-native-tls", "tokio-native-tls",
"url", "url",
"wasm-bindgen", "wasm-bindgen",
@ -2658,9 +2735,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.6.0" version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac" checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"core-foundation", "core-foundation",
@ -2671,9 +2748,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework-sys" name = "security-framework-sys"
version = "2.6.0" version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c" checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -2699,9 +2776,9 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -2762,9 +2839,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.78" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [ dependencies = [
"itoa 1.0.1", "itoa 1.0.1",
"ryu", "ryu",
@ -2785,9 +2862,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "1.11.0" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3" checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc"
dependencies = [ dependencies = [
"rustversion", "rustversion",
"serde", "serde",
@ -3075,16 +3152,17 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.16.1" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"libc", "libc",
"memchr", "memchr",
"mio 0.7.14", "mio 0.8.0",
"num_cpus", "num_cpus",
"pin-project-lite 0.2.8", "pin-project-lite 0.2.8",
"socket2 0.4.4",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -3106,7 +3184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
dependencies = [ dependencies = [
"native-tls", "native-tls",
"tokio 1.16.1", "tokio 1.17.0",
] ]
[[package]] [[package]]
@ -3144,7 +3222,7 @@ dependencies = [
"futures-sink", "futures-sink",
"log", "log",
"pin-project-lite 0.2.8", "pin-project-lite 0.2.8",
"tokio 1.16.1", "tokio 1.17.0",
] ]
[[package]] [[package]]
@ -3164,9 +3242,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.29" version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"log", "log",
@ -3176,9 +3254,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.21" version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@ -3275,9 +3353,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.8.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
@ -3575,7 +3653,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14ba3b5a07989987994b96bf5cc7ac2947005f9ff6123d71b7064232f07d28fa" checksum = "14ba3b5a07989987994b96bf5cc7ac2947005f9ff6123d71b7064232f07d28fa"
dependencies = [ dependencies = [
"fluence-it-types", "fluence-it-types",
"it-lilo", "it-lilo 0.1.0",
"it-to-bytes",
"itertools 0.10.3",
"log",
"nom",
"safe-transmute",
"semver 0.11.0",
"serde",
"serde_json",
"thiserror",
"wast",
]
[[package]]
name = "wasmer-interface-types-fl"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b44e5721c2d42996a6ce9aa3ae75fb8b32433e3bb8aa0942fe27087a9966175"
dependencies = [
"fluence-it-types",
"it-lilo 0.2.0",
"it-memory-traits",
"it-to-bytes", "it-to-bytes",
"itertools 0.10.3", "itertools 0.10.3",
"log", "log",

View File

@ -3,6 +3,7 @@ members = [
"crates/it-generator", "crates/it-generator",
"crates/it-interfaces", "crates/it-interfaces",
"crates/it-parser", "crates/it-parser",
"crates/min-it-version",
"crates/module-info-parser", "crates/module-info-parser",
"crates/module-interface", "crates/module-interface",
"crates/utils", "crates/utils",
@ -27,6 +28,7 @@ members = [
"fluence-faas/tests/wasm_tests/arrays_passing", "fluence-faas/tests/wasm_tests/arrays_passing",
"fluence-faas/tests/wasm_tests/records_passing", "fluence-faas/tests/wasm_tests/records_passing",
"runtime", "runtime",
"web-runtime",
"tools/cli", "tools/cli",
"tools/repl", "tools/repl",
] ]

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-it-generator" name = "marine-it-generator"
description = "Fluence Marine interface types generator" description = "Fluence Marine interface types generator"
version = "0.5.6" version = "0.6.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -11,11 +11,11 @@ name = "marine_it_generator"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
marine-it-parser = { path = "../it-parser", version = "0.6.8"} marine-it-parser = { path = "../it-parser", version = "0.7.0"}
marine-macro-impl = "0.6.10" marine-macro-impl = "0.6.10"
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
it-lilo = "0.1.0" it-lilo = "0.2.0"
thiserror = "1.0.24" thiserror = "1.0.24"
walrus = "0.18.0" walrus = "0.18.0"

View File

@ -152,8 +152,7 @@ pub(crate) fn generate_raw_args(signature: &FnSignature) -> Rc<Vec<IFunctionArg>
let raw_inputs = signature let raw_inputs = signature
.arguments .arguments
.iter() .iter()
.map(to_raw_input_types) .flat_map(to_raw_input_types)
.flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Rc::new(raw_inputs) Rc::new(raw_inputs)
@ -163,13 +162,12 @@ pub(crate) fn generate_raw_output_type(signature: &FnSignature) -> Rc<Vec<IType>
let raw_outputs = signature let raw_outputs = signature
.output_types .output_types
.iter() .iter()
.map(|ty| { .flat_map(|ty| {
to_raw_output_type(ty) to_raw_output_type(ty)
.iter() .iter()
.map(wtype_to_itype) .map(wtype_to_itype)
.collect::<Vec<_>>() .collect::<Vec<_>>()
}) })
.flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Rc::new(raw_outputs) Rc::new(raw_outputs)

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-it-interfaces" name = "marine-it-interfaces"
description = "Fluence Marine interface types helper crate" description = "Fluence Marine interface types helper crate"
version = "0.4.1" version = "0.5.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -11,5 +11,5 @@ name = "marine_it_interfaces"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
multimap = "0.8.1" multimap = "0.8.1"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-it-parser" name = "marine-it-parser"
description = "Fluence Marine interface types parser" description = "Fluence Marine interface types parser"
version = "0.6.8" version = "0.7.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -11,13 +11,13 @@ name = "marine_it_parser"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
marine-it-interfaces = { path = "../it-interfaces", version = "0.4.1" } marine-it-interfaces = { path = "../it-interfaces", version = "0.5.0" }
marine-module-interface = { path = "../module-interface", version = "0.1.6" } marine-module-interface = { path = "../module-interface", version = "0.2.0" }
anyhow = "1.0.31" anyhow = "1.0.31"
walrus = "0.18.0" walrus = "0.18.0"
wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1"} wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1"}
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1"}
nom = "5.1" nom = "5.1"
itertools = "0.10.0" itertools = "0.10.0"

View File

@ -0,0 +1,15 @@
[package]
name = "marine-min-it-version"
version = "0.1.0"
description = "Fluence Marine interface types minimum supported version checker"
authors = ["Fluence Labs"]
license = "Apache-2.0"
edition = "2018"
[lib]
name = "marine_min_it_version"
path = "src/lib.rs"
[dependencies]
once_cell = "1.7.2"
semver = "0.11.0"

View File

@ -0,0 +1,50 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![warn(rust_2018_idioms)]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
use once_cell::sync::Lazy;
use std::str::FromStr;
static MINIMAL_SUPPORTED_SDK_VERSION: Lazy<semver::Version> = Lazy::new(|| {
semver::Version::from_str("0.6.0").expect("invalid minimal sdk version specified")
});
static MINIMAL_SUPPORTED_IT_VERSION: Lazy<semver::Version> = Lazy::new(|| {
semver::Version::from_str("0.20.0").expect("invalid minimal sdk version specified")
});
// These locals intended for check that set versions are correct at the start of an application.
thread_local!(static MINIMAL_SUPPORTED_SDK_VERSION_CHECK: &'static semver::Version = Lazy::force(&MINIMAL_SUPPORTED_SDK_VERSION));
thread_local!(static MINIMAL_SUPPORTED_IT_VERSION_CHECK: &'static semver::Version = Lazy::force(&MINIMAL_SUPPORTED_IT_VERSION));
/// Return minimal support version of interface types.
pub fn min_it_version() -> &'static semver::Version {
Lazy::force(&MINIMAL_SUPPORTED_IT_VERSION)
}
/// Return minimal support version of SDK.
pub fn min_sdk_version() -> &'static semver::Version {
Lazy::force(&MINIMAL_SUPPORTED_SDK_VERSION)
}

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-module-interface" name = "marine-module-interface"
description = "Fluence Marine module interface" description = "Fluence Marine module interface"
version = "0.1.6" version = "0.2.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -11,12 +11,11 @@ name = "marine_module_interface"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
marine-it-interfaces = { path = "../it-interfaces", version = "0.4.1" } marine-it-interfaces = { path = "../it-interfaces", version = "0.5.0" }
anyhow = "1.0.31" anyhow = "1.0.31"
walrus = "0.18.0" walrus = "0.18.0"
wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1"} wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1"}
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" }
nom = "5.1" nom = "5.1"
itertools = "0.10.0" itertools = "0.10.0"

View File

@ -41,7 +41,7 @@ pub fn get_export_funcs_descriptors<'i>(
mit.exports_by_type(*core_function_type) mit.exports_by_type(*core_function_type)
.map(|export_function_name| (adapter_function_type, export_function_name)) .map(|export_function_name| (adapter_function_type, export_function_name))
}) })
.map(|(&adapter_function_type, export_function_names)| { .flat_map(|(&adapter_function_type, export_function_names)| {
export_function_names export_function_names
.iter() .iter()
.map(move |name| ITExportFuncDescriptor { .map(move |name| ITExportFuncDescriptor {
@ -49,7 +49,6 @@ pub fn get_export_funcs_descriptors<'i>(
name, name,
}) })
}) })
.flatten()
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }

View File

@ -1,13 +1,14 @@
[package] [package]
name = "fluence-app-service" name = "fluence-app-service"
description = "Fluence Application Service" description = "Fluence Application Service"
version = "0.13.0" version = "0.14.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
fluence-faas = { path = "../fluence-faas", version = "0.12.0" } fluence-faas = { path = "../fluence-faas", version = "0.13.0" }
marine-min-it-version = { path = "../crates/min-it-version", version = "0.1.0" }
maplit = "1.0.2" maplit = "1.0.2"
log = "0.4.8" log = "0.4.8"

View File

@ -64,8 +64,8 @@ pub use fluence_faas::ModuleMemoryStat;
pub use fluence_faas::MemoryStats; pub use fluence_faas::MemoryStats;
pub use fluence_faas::ne_vec; pub use fluence_faas::ne_vec;
pub use fluence_faas::min_sdk_version; pub use marine_min_it_version::min_sdk_version;
pub use fluence_faas::min_it_version; pub use marine_min_it_version::min_it_version;
pub use fluence_faas::CallParameters; pub use fluence_faas::CallParameters;
pub use fluence_faas::SecurityTetraplet; pub use fluence_faas::SecurityTetraplet;

View File

@ -1,14 +1,14 @@
[package] [package]
name = "fluence-faas" name = "fluence-faas"
description = "Fluence FaaS" description = "Fluence FaaS"
version = "0.12.0" version = "0.13.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
marine-runtime = { path = "../runtime", version = "0.10.0" } marine-runtime = { path = "../runtime", version = "0.11.0" }
marine-module-interface = { path = "../crates/module-interface", version = "0.1.6" } marine-module-interface = { path = "../crates/module-interface", version = "0.2.0" }
marine-utils = { path = "../crates/utils", version = "0.4.0" } marine-utils = { path = "../crates/utils", version = "0.4.0" }
marine-rs-sdk-main = { version = "0.6.15", features = ["logger"] } marine-rs-sdk-main = { version = "0.6.15", features = ["logger"] }
marine-rs-sdk = { version = "0.6.15", features = ["logger"] } marine-rs-sdk = { version = "0.6.15", features = ["logger"] }
@ -17,7 +17,7 @@ wasmer-runtime = { package = "wasmer-runtime-fl", version = "=0.17.1" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc # dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1", features = ["dynamicfunc-fat-closures"] } wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1", features = ["dynamicfunc-fat-closures"] }
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" } wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
toml = "0.5.6" toml = "0.5.6"
serde = { version = "1.0.118", features = ["derive"] } serde = { version = "1.0.118", features = ["derive"] }

View File

@ -65,8 +65,6 @@ pub use marine::HostImportError;
pub use marine::to_interface_value; pub use marine::to_interface_value;
pub use marine::from_interface_values; pub use marine::from_interface_values;
pub use marine::ne_vec; pub use marine::ne_vec;
pub use marine::min_sdk_version;
pub use marine::min_it_version;
pub use marine_module_interface::interface::itype_text_view; pub use marine_module_interface::interface::itype_text_view;

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-runtime" name = "marine-runtime"
description = "Marine is the Fluence Compute Runtime" description = "Marine is the Fluence Compute Runtime"
version = "0.10.0" version = "0.11.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -12,17 +12,19 @@ path = "src/lib.rs"
[dependencies] [dependencies]
marine-module-info-parser = { path = "../crates/module-info-parser", version = "0.2.2" } marine-module-info-parser = { path = "../crates/module-info-parser", version = "0.2.2" }
marine-it-interfaces = { path = "../crates/it-interfaces", version = "0.4.1" } marine-it-interfaces = { path = "../crates/it-interfaces", version = "0.5.0" }
marine-it-parser = { path = "../crates/it-parser", version = "0.6.8" } marine-it-parser = { path = "../crates/it-parser", version = "0.7.0" }
marine-it-generator = { path = "../crates/it-generator", version = "0.5.6" } marine-it-generator = { path = "../crates/it-generator", version = "0.6.0" }
marine-module-interface = { path = "../crates/module-interface", version = "0.1.6" } marine-module-interface = { path = "../crates/module-interface", version = "0.2.0" }
marine-utils = { path = "../crates/utils", version = "0.4.0" } marine-utils = { path = "../crates/utils", version = "0.4.0" }
marine-min-it-version = { path = "../crates/min-it-version", version = "0.1.0"}
wasmer-runtime = { package = "wasmer-runtime-fl", version = "=0.17.1" } wasmer-runtime = { package = "wasmer-runtime-fl", version = "=0.17.1" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc # dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1", features = ["dynamicfunc-fat-closures"] } wasmer-core = { package = "wasmer-runtime-core-fl", version = "=0.17.1", features = ["dynamicfunc-fat-closures"] }
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
it-lilo = "0.1.0" it-lilo = "0.2.0"
it-memory-traits = "0.1.0"
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" } wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" }
bytesize = "1.1.0" bytesize = "1.1.0"

View File

@ -51,9 +51,11 @@ impl Marine {
func_name: FN, func_name: FN,
arguments: &[IValue], arguments: &[IValue],
) -> MResult<Vec<IValue>> { ) -> MResult<Vec<IValue>> {
self.modules.get_mut(module_name.as_ref()).map_or_else( let module_name = module_name.as_ref();
|| Err(MError::NoSuchModule(module_name.as_ref().to_string())),
|module| module.call(module_name.as_ref(), func_name.as_ref(), arguments), self.modules.get_mut(module_name).map_or_else(
|| Err(MError::NoSuchModule(module_name.to_string())),
|module| module.call(module_name, func_name.as_ref(), arguments),
) )
} }

View File

@ -26,6 +26,7 @@ use crate::MRecordTypes;
use crate::init_wasm_func_once; use crate::init_wasm_func_once;
use crate::call_wasm_func; use crate::call_wasm_func;
use crate::HostImportDescriptor; use crate::HostImportDescriptor;
use crate::module::wit_prelude::WITMemoryView;
use wasmer_core::Func; use wasmer_core::Func;
use wasmer_core::vm::Ctx; use wasmer_core::vm::Ctx;
@ -37,7 +38,6 @@ use it_lilo::lowerer::ILowerer;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::ops::Deref;
pub(crate) fn create_host_import_func( pub(crate) fn create_host_import_func(
descriptor: HostImportDescriptor, descriptor: HostImportDescriptor,
@ -63,27 +63,31 @@ pub(crate) fn create_host_import_func(
let raw_output = itypes_output_to_wtypes(&output_type_to_types(output_type)); let raw_output = itypes_output_to_wtypes(&output_type_to_types(output_type));
let func = move |ctx: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> { let func = move |ctx: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
let memory_index = 0; let result = {
let view = ctx.memory(memory_index).view::<u8>(); let memory_index = 0;
let memory = view.deref(); let memory = ctx.memory(memory_index);
let memory_view = WITMemoryView(memory.view::<u8>());
let li_helper = LiHelper::new(record_types.clone());
let lifter = ILifter::new(memory_view, &li_helper);
let li_helper = LiHelper::new(record_types.clone()); match wvalues_to_ivalues(&lifter, inputs, &argument_types) {
let lifter = ILifter::new(memory, &li_helper); Ok(ivalues) => host_exported_func(ctx, ivalues),
Err(e) => {
let result = match wvalues_to_ivalues(&lifter, inputs, &argument_types) { log::error!("error occurred while lifting values in host import: {}", e);
Ok(ivalues) => host_exported_func(ctx, ivalues), error_handler
Err(e) => { .as_ref()
log::error!("error occurred while lifting values in host import: {}", e); .map_or_else(|| default_error_handler(&e), |h| h(&e))
error_handler }
.as_ref()
.map_or_else(|| default_error_handler(&e), |h| h(&e))
} }
}; };
init_wasm_func_once!(allocate_func, ctx, (i32, i32), i32, ALLOCATE_FUNC_NAME, 2); init_wasm_func_once!(allocate_func, ctx, (i32, i32), i32, ALLOCATE_FUNC_NAME, 2);
let lo_helper = LoHelper::new(ctx, &allocate_func); let memory_index = 0;
let t = ILowerer::new(&lo_helper) let memory = ctx.memory(memory_index);
let memory_view = WITMemoryView(memory.view::<u8>());
let lo_helper = LoHelper::new(&allocate_func);
let t = ILowerer::new(memory_view, &lo_helper)
.map_err(HostImportError::LowererError) .map_err(HostImportError::LowererError)
.and_then(|lowerer| ivalue_to_wvalues(&lowerer, result)); .and_then(|lowerer| ivalue_to_wvalues(&lowerer, result));

View File

@ -43,8 +43,8 @@ macro_rules! simple_wvalue_to_ivalue {
}}; }};
} }
pub(crate) fn wvalues_to_ivalues<R: RecordResolvable>( pub(crate) fn wvalues_to_ivalues<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
lifter: &ILifter<'_, '_, R>, lifter: &ILifter<'_, R, MV>,
wvalues: &[WValue], wvalues: &[WValue],
itypes: &[IType], itypes: &[IType],
) -> HostImportResult<Vec<IValue>> { ) -> HostImportResult<Vec<IValue>> {

View File

@ -19,38 +19,20 @@ use crate::call_wasm_func;
use it_lilo::traits::Allocatable; use it_lilo::traits::Allocatable;
use it_lilo::traits::AllocatableError; use it_lilo::traits::AllocatableError;
use wasmer_core::vm::Ctx;
use wasmer_core::vm::LocalMemory;
use std::cell::Cell;
pub(crate) struct LoHelper<'c> { pub(crate) struct LoHelper<'c> {
ctx: &'c Ctx,
allocate_func: &'c AllocateFunc, allocate_func: &'c AllocateFunc,
} }
impl<'c> LoHelper<'c> { impl<'c> LoHelper<'c> {
pub(crate) fn new(ctx: &'c Ctx, allocate_func: &'c AllocateFunc) -> Self { pub(crate) fn new(allocate_func: &'c AllocateFunc) -> Self {
Self { ctx, allocate_func } Self { allocate_func }
} }
} }
impl Allocatable for LoHelper<'_> { impl<'s> Allocatable for LoHelper<'s> {
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError> { fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError> {
let offset = call_wasm_func!(self.allocate_func, size as _, type_tag as _); let offset = call_wasm_func!(self.allocate_func, size as _, type_tag as _);
Ok(offset as _) Ok(offset as _)
} }
fn memory_slice(&self, memory_index: usize) -> Result<&[Cell<u8>], AllocatableError> {
let memory = self.ctx.memory(memory_index as _);
let LocalMemory { base, .. } = unsafe { *memory.vm_local_memory() };
let length = memory.size().bytes().0 / std::mem::size_of::<u8>();
let mut_slice: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(base, length) };
let cell_slice: &Cell<[u8]> = Cell::from_mut(mut_slice);
let slice = cell_slice.as_slice_of_cells();
Ok(slice)
}
} }

View File

@ -20,9 +20,10 @@ use crate::IValue;
use it_lilo::lowerer::*; use it_lilo::lowerer::*;
use it_lilo::traits::Allocatable; use it_lilo::traits::Allocatable;
use it_memory_traits::SequentialMemoryView;
pub(crate) fn ivalue_to_wvalues<A: Allocatable>( pub(crate) fn ivalue_to_wvalues<A: Allocatable, MV: for<'a> SequentialMemoryView<'a>>(
lowerer: &ILowerer<'_, A>, lowerer: &ILowerer<'_, A, MV>,
ivalue: Option<IValue>, ivalue: Option<IValue>,
) -> HostImportResult<Vec<WValue>> { ) -> HostImportResult<Vec<WValue>> {
let result = match ivalue { let result = match ivalue {

View File

@ -99,29 +99,27 @@ where
pub(super) fn itypes_args_to_wtypes(itypes: &[IType]) -> Vec<WType> { pub(super) fn itypes_args_to_wtypes(itypes: &[IType]) -> Vec<WType> {
itypes itypes
.iter() .iter()
.map(|itype| match itype { .flat_map(|itype| match itype {
IType::F32 => vec![WType::F32], IType::F32 => vec![WType::F32],
IType::F64 => vec![WType::F64], IType::F64 => vec![WType::F64],
IType::I64 | IType::U64 => vec![WType::I64], IType::I64 | IType::U64 => vec![WType::I64],
IType::String | IType::Array(_) => vec![WType::I32, WType::I32], IType::String | IType::Array(_) => vec![WType::I32, WType::I32],
_ => vec![WType::I32], _ => vec![WType::I32],
}) })
.flatten() .collect()
.collect::<Vec<_>>()
} }
pub(super) fn itypes_output_to_wtypes(itypes: &[IType]) -> Vec<WType> { pub(super) fn itypes_output_to_wtypes(itypes: &[IType]) -> Vec<WType> {
itypes itypes
.iter() .iter()
.map(|itype| match itype { .flat_map(|itype| match itype {
IType::F32 => vec![WType::F32], IType::F32 => vec![WType::F32],
IType::F64 => vec![WType::F64], IType::F64 => vec![WType::F64],
IType::I64 | IType::U64 => vec![WType::I64], IType::I64 | IType::U64 => vec![WType::I64],
IType::String | IType::Array(_) | IType::Record(_) => vec![], IType::String | IType::Array(_) | IType::Record(_) => vec![],
_ => vec![WType::I32], _ => vec![WType::I32],
}) })
.flatten() .collect()
.collect::<Vec<_>>()
} }
#[macro_export] // https://github.com/rust-lang/rust/issues/57966#issuecomment-461077932 #[macro_export] // https://github.com/rust-lang/rust/issues/57966#issuecomment-461077932

View File

@ -59,27 +59,3 @@ pub mod ne_vec {
} }
pub(crate) type MResult<T> = std::result::Result<T, MError>; pub(crate) type MResult<T> = std::result::Result<T, MError>;
use once_cell::sync::Lazy;
use std::str::FromStr;
static MINIMAL_SUPPORTED_SDK_VERSION: Lazy<semver::Version> = Lazy::new(|| {
semver::Version::from_str("0.6.0").expect("invalid minimal sdk version specified")
});
static MINIMAL_SUPPORTED_IT_VERSION: Lazy<semver::Version> = Lazy::new(|| {
semver::Version::from_str("0.20.0").expect("invalid minimal sdk version specified")
});
// These locals intended for check that set versions are correct at the start of an application.
thread_local!(static MINIMAL_SUPPORTED_SDK_VERSION_CHECK: &'static semver::Version = Lazy::force(&MINIMAL_SUPPORTED_SDK_VERSION));
thread_local!(static MINIMAL_SUPPORTED_IT_VERSION_CHECK: &'static semver::Version = Lazy::force(&MINIMAL_SUPPORTED_IT_VERSION));
/// Return minimal support version of interface types.
pub fn min_it_version() -> &'static semver::Version {
Lazy::force(&MINIMAL_SUPPORTED_IT_VERSION)
}
/// Return minimal support version of SDK.
pub fn min_sdk_version() -> &'static semver::Version {
Lazy::force(&MINIMAL_SUPPORTED_SDK_VERSION)
}

View File

@ -18,6 +18,8 @@ use super::PrepareResult;
use super::PrepareError; use super::PrepareError;
use marine_module_info_parser::sdk_version; use marine_module_info_parser::sdk_version;
use marine_min_it_version::min_sdk_version;
use marine_min_it_version::min_it_version;
use wasmer_core::Module; use wasmer_core::Module;
@ -31,7 +33,7 @@ pub(crate) fn check_sdk_version(
None => return Err(PrepareError::ModuleWithoutVersion(name.into())), None => return Err(PrepareError::ModuleWithoutVersion(name.into())),
}; };
let required_version = crate::min_sdk_version(); let required_version = min_sdk_version();
if module_version < *required_version { if module_version < *required_version {
return Err(PrepareError::IncompatibleSDKVersions { return Err(PrepareError::IncompatibleSDKVersions {
module_name: name.into(), module_name: name.into(),
@ -47,7 +49,7 @@ pub(crate) fn check_it_version(
name: impl Into<String>, name: impl Into<String>,
it_version: &semver::Version, it_version: &semver::Version,
) -> PrepareResult<()> { ) -> PrepareResult<()> {
let required_version = crate::min_it_version(); let required_version = min_it_version();
if it_version < required_version { if it_version < required_version {
return Err(PrepareError::IncompatibleITVersions { return Err(PrepareError::IncompatibleITVersions {
module_name: name.into(), module_name: name.into(),

View File

@ -369,12 +369,11 @@ impl MModule {
wit.imports_by_type(*core_function_type) wit.imports_by_type(*core_function_type)
.map(|import| (adapter_function_type, import)) .map(|import| (adapter_function_type, import))
}) })
.map(|(adapter_function_type, import_function_names)| { .flat_map(|(adapter_function_type, import_function_names)| {
import_function_names import_function_names
.iter() .iter()
.map(move |import_function_name| (*adapter_function_type, import_function_name)) .map(move |import_function_name| (*adapter_function_type, import_function_name))
}) })
.flatten()
.map(|(adapter_function_type, (import_namespace, import_name))| { .map(|(adapter_function_type, (import_namespace, import_name))| {
let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?; let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?;
let wit_type = wit.type_by_idx_r(adapter_function_type)?; let wit_type = wit.type_by_idx_r(adapter_function_type)?;

View File

@ -14,20 +14,21 @@
* limitations under the License. * limitations under the License.
*/ */
use std::cell::Cell;
use std::ops::Deref;
use wasmer_it::interpreter::wasm; use wasmer_it::interpreter::wasm;
use wasmer_core::memory::{Memory, MemoryView}; use wasmer_core::memory::{Memory, MemoryView};
use wasmer_core::vm::LocalMemory;
use crate::module::WasmerSequentialReader;
pub(super) struct WITMemoryView<'a>(pub(super) MemoryView<'a, u8>); use crate::module::WasmerSequentialWriter;
impl<'a> std::ops::Deref for WITMemoryView<'a> {
type Target = [std::cell::Cell<u8>];
fn deref(&self) -> &Self::Target { use it_memory_traits::{MemoryAccessError};
self.0.deref()
} pub(crate) struct WITMemoryView<'a>(pub(crate) MemoryView<'a, u8>);
}
#[derive(Clone)] #[derive(Clone)]
pub(super) struct WITMemory(pub(super) Memory); pub(crate) struct WITMemory(pub(super) Memory);
impl std::ops::Deref for WITMemory { impl std::ops::Deref for WITMemory {
type Target = Memory; type Target = Memory;
@ -36,12 +37,69 @@ impl std::ops::Deref for WITMemory {
} }
} }
impl wasm::structures::MemoryView for WITMemoryView<'_> {} impl WITMemoryView<'_> {
fn check_bounds(
&self,
offset: usize,
size: usize,
memory_size: usize,
) -> Result<(), MemoryAccessError> {
if offset + size >= memory_size {
Err(MemoryAccessError::OutOfBounds {
offset,
size,
memory_size,
})
} else {
Ok(())
}
}
}
impl<'s, 'v> wasm::structures::SequentialMemoryView<'v> for WITMemoryView<'s> {
type SR = WasmerSequentialReader<'v>;
type SW = WasmerSequentialWriter<'v>;
fn sequential_writer(
&'v self,
offset: usize,
size: usize,
) -> Result<Self::SW, MemoryAccessError> {
let view = &self.0;
let slice = view.deref();
self.check_bounds(offset, size, slice.len())?;
let writer = WasmerSequentialWriter {
offset,
slice,
current_offset: Cell::new(offset),
};
Ok(writer)
}
fn sequential_reader(
&'v self,
offset: usize,
size: usize,
) -> Result<Self::SR, MemoryAccessError> {
let view = &self.0;
let slice: &[Cell<u8>] = view.deref();
self.check_bounds(offset, size, slice.len())?;
let reader = WasmerSequentialReader {
memory: slice,
offset: Cell::new(offset),
};
Ok(reader)
}
}
impl<'a> wasm::structures::Memory<WITMemoryView<'a>> for WITMemory { impl<'a> wasm::structures::Memory<WITMemoryView<'a>> for WITMemory {
fn view(&self) -> WITMemoryView<'a> { fn view(&self) -> WITMemoryView<'a> {
use wasmer_core::vm::LocalMemory;
let LocalMemory { base, .. } = unsafe { *self.0.vm_local_memory() }; let LocalMemory { base, .. } = unsafe { *self.0.vm_local_memory() };
let length = self.0.size().bytes().0 / std::mem::size_of::<u8>(); let length = self.0.size().bytes().0 / std::mem::size_of::<u8>();

View File

@ -0,0 +1,137 @@
use std::cell::Cell;
use it_memory_traits::{SequentialReader, SequentialWriter};
#[macro_export]
macro_rules! value_der {
($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => {
[$($self.memory[$offset + $ids].get()),+]
};
($self:expr, $offset:expr, 1) => {
crate::value_der!($self, $offset, @seq_start 0 @seq_end);
};
($self:expr, $offset:expr, 2) => {
crate::value_der!($self, $offset, @seq_start 0, 1 @seq_end);
};
($self:expr, $offset:expr, 4) => {
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end);
};
($self:expr, $offset:expr, 8) => {
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end);
};
($self:expr, $offset:expr, 16) => {
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @seq_end);
};
}
#[macro_export]
macro_rules! read_ty {
($func_name:ident, $ty:ty, 1) => {
fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 1));
self.offset.set(offset + 1);
result
}
};
($func_name:ident, $ty:ty, 2) => {
fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 2));
self.offset.set(offset + 2);
result
}
};
($func_name:ident, $ty:ty, 4) => {
fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 4));
self.offset.set(offset + 4);
result
}
};
($func_name:ident, $ty:ty, 8) => {
fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 8));
self.offset.set(offset + 8);
result
}
};
($func_name:ident, $ty:ty, 16) => {
fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 16));
self.offset.set(offset + 16);
result
}
};
}
pub(crate) struct WasmerSequentialReader<'s> {
pub memory: &'s [Cell<u8>],
pub offset: Cell<usize>,
}
pub(crate) struct WasmerSequentialWriter<'s> {
pub offset: usize,
pub slice: &'s [Cell<u8>],
pub current_offset: Cell<usize>,
}
impl SequentialReader for WasmerSequentialReader<'_> {
fn read_byte(&self) -> u8 {
let offset = self.offset.get();
let result = self.memory[offset].get();
self.offset.set(offset + 1);
result
}
// needed because clippy suggests using an iterator which looks worse
#[allow(clippy::needless_range_loop)]
fn read_bytes<const COUNT: usize>(&self) -> [u8; COUNT] {
let offset = self.offset.get();
let mut result = [0u8; COUNT];
for index in 0..COUNT {
result[index] = self.memory[offset + index].get();
}
self.offset.set(offset + COUNT);
result
}
}
impl SequentialWriter for WasmerSequentialWriter<'_> {
fn start_offset(&self) -> usize {
self.offset
}
fn write_u8(&self, value: u8) {
let offset = self.current_offset.get();
self.slice[offset].set(value);
self.current_offset.set(offset + 1);
}
fn write_u32(&self, value: u32) {
self.write_bytes(&value.to_le_bytes());
}
fn write_bytes(&self, bytes: &[u8]) {
for byte in bytes {
self.write_u8(*byte)
}
}
}

View File

@ -17,6 +17,7 @@
mod exports; mod exports;
mod marine_module; mod marine_module;
mod memory; mod memory;
mod memory_access;
mod wit_function; mod wit_function;
mod wit_instance; mod wit_instance;
mod type_converters; mod type_converters;
@ -29,6 +30,9 @@ pub use wasmer_it::IValue;
pub use wasmer_it::from_interface_values; pub use wasmer_it::from_interface_values;
pub use wasmer_it::to_interface_value; pub use wasmer_it::to_interface_value;
pub(crate) use memory_access::WasmerSequentialWriter;
pub(crate) use memory_access::WasmerSequentialReader;
use serde::Serialize; use serde::Serialize;
use serde::Deserialize; use serde::Deserialize;
use std::rc::Rc; use std::rc::Rc;
@ -46,11 +50,12 @@ pub(self) use wasmer_core::types::Type as WType;
pub(self) use wasmer_core::types::Value as WValue; pub(self) use wasmer_core::types::Value as WValue;
// types that often used together // types that often used together
pub(self) mod wit_prelude { pub(crate) mod wit_prelude {
pub(super) use super::wit_instance::ITInstance; pub(super) use super::wit_instance::ITInstance;
pub(super) use super::exports::ITExport; pub(super) use super::exports::ITExport;
pub(super) use crate::MError; pub(super) use crate::MError;
pub(super) use super::wit_function::WITFunction; pub(super) use super::wit_function::WITFunction;
pub(super) use super::memory::WITMemoryView;
pub(super) use super::memory::WITMemory; pub(crate) use super::memory::WITMemoryView;
pub(crate) use super::memory::WITMemory;
} }

View File

@ -22,11 +22,10 @@ use crate::MResult;
use marine_it_interfaces::MITInterfaces; use marine_it_interfaces::MITInterfaces;
use marine_it_interfaces::ITAstType; use marine_it_interfaces::ITAstType;
use wasmer_it::interpreter::wasm; use wasmer_it::interpreter::wasm;
use wasmer_it::interpreter::wasm::structures::{LocalImportIndex, TypedIndex}; use wasmer_it::interpreter::wasm::structures::{LocalImportIndex, Memory, TypedIndex};
use wasmer_core::Instance as WasmerInstance; use wasmer_core::Instance as WasmerInstance;
use std::collections::HashMap; use std::collections::HashMap;
use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
pub type MRecordTypes = HashMap<u64, Rc<IRecordType>>; pub type MRecordTypes = HashMap<u64, Rc<IRecordType>>;
@ -176,7 +175,7 @@ impl ITInstance {
} }
} }
impl wasm::structures::Instance<ITExport, WITFunction, WITMemory, WITMemoryView<'_>> impl<'v> wasm::structures::Instance<ITExport, WITFunction, WITMemory, WITMemoryView<'v>>
for ITInstance for ITInstance
{ {
fn export(&self, _export_name: &str) -> Option<&ITExport> { fn export(&self, _export_name: &str) -> Option<&ITExport> {
@ -196,22 +195,14 @@ impl wasm::structures::Instance<ITExport, WITFunction, WITMemory, WITMemoryView<
} }
} }
fn memory_slice(&self, index: usize) -> Option<&[Cell<u8>]> { fn memory_view(&self, index: usize) -> Option<WITMemoryView<'static>> {
use wasmer_core::vm::LocalMemory;
if index >= self.memories.len() { if index >= self.memories.len() {
return None; return None;
} }
let memory = &self.memories[index]; let memory = &self.memories[index];
let LocalMemory { base, .. } = unsafe { *memory.0.vm_local_memory() }; let view: WITMemoryView<'static> = memory.view();
let length = memory.0.size().bytes().0 / std::mem::size_of::<u8>(); Some(view)
let mut_slice: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(base, length) };
let cell_slice: &Cell<[u8]> = Cell::from_mut(mut_slice);
let slice = cell_slice.as_slice_of_cells();
Some(slice)
} }
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>> { fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>> {

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine" name = "marine"
description = "Fluence Marine command line tool" description = "Fluence Marine command line tool"
version = "0.6.13" version = "0.7.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
repository = "https://github.com/fluencelabs/marine/tools/cli" repository = "https://github.com/fluencelabs/marine/tools/cli"
license = "Apache-2.0" license = "Apache-2.0"
@ -12,8 +12,8 @@ name = "marine"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
marine-it-generator = { path = "../../crates/it-generator", version = "0.5.6" } marine-it-generator = { path = "../../crates/it-generator", version = "0.6.0" }
marine-it-parser = { path = "../../crates/it-parser", version = "0.6.8" } marine-it-parser = { path = "../../crates/it-parser", version = "0.7.0" }
marine-module-info-parser = { path = "../../crates/module-info-parser", version = "0.2.2" } marine-module-info-parser = { path = "../../crates/module-info-parser", version = "0.2.2" }
semver = "0.11.0" semver = "0.11.0"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "mrepl" name = "mrepl"
description = "Fluence Marine REPL intended for testing purposes" description = "Fluence Marine REPL intended for testing purposes"
version = "0.12.0" version = "0.13.0"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
repository = "https://github.com/fluencelabs/marine/tools/repl" repository = "https://github.com/fluencelabs/marine/tools/repl"
license = "Apache-2.0" license = "Apache-2.0"
@ -12,7 +12,7 @@ name = "mrepl"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence-app-service = { path = "../../fluence-app-service", version = "0.13.0", features = ["raw-module-api"] } fluence-app-service = { path = "../../fluence-app-service", version = "0.14.0", features = ["raw-module-api"] }
marine-rs-sdk-main = { version = "0.6.15", features = ["logger"] } marine-rs-sdk-main = { version = "0.6.15", features = ["logger"] }
anyhow = "1.0.31" anyhow = "1.0.31"

View File

@ -25,6 +25,7 @@ use fluence_app_service::FaaSModuleConfig;
use fluence_app_service::TomlAppServiceConfig; use fluence_app_service::TomlAppServiceConfig;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value as JValue;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
@ -56,7 +57,7 @@ struct CallModuleArguments<'args> {
module_name: &'args str, module_name: &'args str,
func_name: &'args str, func_name: &'args str,
show_result_arg: bool, show_result_arg: bool,
args: serde_json::Value, args: JValue,
call_parameters: CallParameters, call_parameters: CallParameters,
} }
@ -258,7 +259,7 @@ fn parse_call_module_arguments<'args>(
let module_arg: String = args.join(" "); let module_arg: String = args.join(" ");
let mut de = serde_json::Deserializer::from_str(&module_arg); let mut de = serde_json::Deserializer::from_str(&module_arg);
let args = match serde_json::Value::deserialize(&mut de) { let args = match JValue::deserialize(&mut de) {
Ok(args) => args, Ok(args) => args,
Err(e) => return Err(format!("invalid args: {}", e)), Err(e) => return Err(format!("invalid args: {}", e)),
}; };

43
web-runtime/Cargo.toml Normal file
View File

@ -0,0 +1,43 @@
[package]
name = "marine-web-runtime"
version = "0.1.0"
edition = "2018"
description = "Web version of marine-runtime"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
marine-it-interfaces = { path = "../crates/it-interfaces", version = "0.5.0" }
marine-module-interface = { path = "../crates/module-interface", version = "0.2.0" }
marine-utils = { path = "../crates/utils", version = "0.4.0" }
marine-min-it-version = { path = "../crates/min-it-version", version = "0.1.0"}
marine-rs-sdk = "0.6.15"
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
fluence-it-types = {version = "0.3.1", features = ["impls"] }
it-lilo = "0.2.0"
it-memory-traits = "0.1.0"
wasm-bindgen = "0.2"
nom = "5.1"
itertools = "0.10.1"
multimap = "0.8.1"
boolinator = "2.4.0"
bytesize = {version = "1.1.0", features = ["serde"]}
console_error_panic_hook = "0.1.7"
once_cell = "1.7.2"
semver = "0.11.0"
serde = { version = "1.0.118", features = ["derive"] }
serde_json = "1.0.53"
serde_derive = "1.0.118"
serde_with = "1.11.0"
log = "0.4.8"
toml = "0.5.8"
paste = "1.0.5"
anyhow = "1.0.31"
thiserror = "1.0.24"
maplit = "1.0.2"
web-sys = {version = "0.3.56", features = ["console"]}

8
web-runtime/build.sh Executable file
View File

@ -0,0 +1,8 @@
#! /bin/bash
wasm-pack build -d marine-web-pkg --target web
MARINE_JS_JS_DEST=npm-package/src/snippets/marine-web-runtime-6faa67b8af9cc173/
mkdir -p $MARINE_JS_JS_DEST
cp marine-js.js $MARINE_JS_JS_DEST

124
web-runtime/marine-js.js Normal file
View File

@ -0,0 +1,124 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Internal API if marine-web. Only these functions are used for interacting with WebAssembly.Instance
// None of the functions below performs error-checking
// It is caller's responsibility to ensure that the instance is valid and has all the exports and required memory size
/**
* Calls an export function from wasm module
*
* @param {WebAssembly.Instance} instance instance which will be called
* @param {string} export_name name of the export
* @param {string} args JSON array of args
* @returns {string} JSON array of results
* */
export function call_export(instance, export_name, args) {
let parsed_args = JSON.parse(args);
let prepared_args = [];
for (let arg_index = 0; arg_index < parsed_args.length; arg_index++) {
let arg = parsed_args[arg_index];
if (arg["I32"] !== undefined) {
prepared_args.push(arg["I32"])
}
if (arg["I64"] !== undefined) {;
let val = BigInt(arg["I64"]);
prepared_args.push(val)
}
if (arg["F32"] !== undefined) {
prepared_args.push(arg["F32"])
}
if (arg["F64"] !== undefined) {
prepared_args.push(arg["F64"])
}
}
let result = instance.exports[export_name](...prepared_args);
let json_result = "[]";
if (result !== undefined) {
if (typeof result == "bigint") {
json_result = "[" + result.toString() + "]"
} else {
json_result = "[" + JSON.stringify(result) + "]"
}
}
return json_result
}
/**
* Gets size of the wasm memory
*
* @param {WebAssembly.Instance} instance instance which will be called
* @returns {number} size of data
* */
export function get_memory_size(instance) {
let buf = new Uint8Array(instance.exports.memory.buffer);
return buf.byteLength
}
/**
* Reads one byte from wasm memory
*
* @param {WebAssembly.Instance} instance instance which will be used
* @param {number} offset offset in wasm memory
* @returns {number} byte from wasm memory
* */
export function read_byte(instance, offset) {
let buf = new Uint8Array(instance.exports.memory.buffer);
return buf[offset];
}
/**
* Writes one byte to wasm memory
*
* @param {WebAssembly.Instance} instance instance which will be used
* @param {number} offset offset in wasm memory
* @param {number} value value to write in memory
* */
export function write_byte(instance, offset, value) {
let buf = new Uint8Array(instance.exports.memory.buffer);
buf[offset] = value;
}
/**
* Writes byte range to wasm memory
*
* @param {WebAssembly.Instance} instance instance which will be used
* @param {number} offset offset in wasm memory
* @param {Uint8Array} slice array with bytes to write into memory
* */
export function write_byte_range(instance, offset, slice) {
let buf = new Uint8Array(instance.exports.memory.buffer);
for (let byte_index = 0; byte_index < slice.length; byte_index++) {
buf[offset + byte_index] = slice[byte_index]
}
}
/**
* Reads byte range from wasm memory
*
* @param {WebAssembly.Instance} instance instance which will be used
* @param {number} offset offset in wasm memory
* @param {Uint8Array} slice array to place read bytes
* */
export function read_byte_range(instance, offset, slice) {
let buf = new Uint8Array(instance.exports.memory.buffer);
for (let byte_index = 0; byte_index < slice.length; byte_index++) {
slice[byte_index] = buf[offset + byte_index];
}
}

6
web-runtime/npm-package/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
dist
node_modules
*.tgz
# auto-generated files
src/*.wasm

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

View File

@ -0,0 +1,4 @@
module.exports = {
testEnvironment: 'node',
testPathIgnorePatterns: ['src'],
};

7461
web-runtime/npm-package/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
{
"name": "@fluencelabs/marine-js",
"description": "Marine-js",
"version": "0.1.0",
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
"repository": "https://github.com/fluencelabs/marine",
"author": "Fluence Labs",
"license": "Apache 2.0",
"files": [
"dist/*",
"!lib/__test__/*"
],
"bin": {
"copy-marine": "./dist/copyMarine.js"
},
"scripts": {
"build": "tsc",
"postbuild": "cp ../marine-web-pkg/marine_web_runtime_bg.wasm ./dist/marine-js.wasm",
"test": "jest"
},
"private": false,
"devDependencies": {
"@wasmer/wasi": "^0.12.0",
"@wasmer/wasmfs": "^0.12.0",
"@fluencelabs/avm": "0.20.0-marine-web-adapted.1",
"@types/jest": "^27.4.0",
"@types/node": "^14.0.0",
"jest": "^27.2.4",
"typescript": "^4.0.0"
}
}

View File

@ -0,0 +1,95 @@
import { init } from '..';
import fs from 'fs';
import path from 'path';
import { WASI } from '@wasmer/wasi';
import { WasmFs } from '@wasmer/wasmfs';
import bindings from '@wasmer/wasi/lib/bindings/browser';
const createModule = async (path: string) => {
const file = fs.readFileSync(path);
return await WebAssembly.compile(file);
};
const invokeJson = (air: any, prevData: any, data: any, paramsToPass: any, callResultsToPass: any) => {
return JSON.stringify([
air,
Array.from(prevData),
Array.from(data),
paramsToPass,
Array.from(Buffer.from(JSON.stringify(callResultsToPass))),
]);
};
const b = (s: string) => {
return Buffer.from(s);
};
const defaultAvmFileName = 'avm.wasm';
const avmPackageName = '@fluencelabs/avm';
const vmPeerId = '12D3KooWNzutuy8WHXDKFqFsATvCR6j9cj2FijYbnd47geRKaQZS';
const _wasmFs = new WasmFs();
const _wasi = new WASI({
// Arguments passed to the Wasm Module
// The first argument is usually the filepath to the executable WASI module
// we want to run.
args: [],
// Environment variables that are accesible to the WASI module
env: {},
// Bindings that are used by the WASI Instance (fs, path, etc...)
bindings: {
...bindings,
fs: _wasmFs.fs,
},
});
describe('Tests', () => {
it('should work', async () => {
const fluencePath = eval('require').resolve(avmPackageName);
const avmPath = path.join(path.dirname(fluencePath), defaultAvmFileName);
const controlModule = await createModule(path.join(__dirname, '../marine-js.wasm'));
const avmModule = await createModule(avmPath);
const marineInstance = await init(controlModule);
const avmInstance = await WebAssembly.instantiate(avmModule, {
..._wasi.getImports(avmModule),
host: {
log_utf8_string: (level: any, target: any, offset: any, size: any) => {
console.log('logging, logging, logging');
},
},
});
_wasi.start(avmInstance);
const customSections = WebAssembly.Module.customSections(avmModule, 'interface-types');
const itcustomSections = new Uint8Array(customSections[0]);
let result = marineInstance.register_module('avm', itcustomSections, avmInstance);
expect(result).toEqual("{\"error\":\"\"}");
const s = `(seq
(par
(call "${vmPeerId}" ("local_service_id" "local_fn_name") [] result_1)
(call "remote_peer_id" ("service_id" "fn_name") [] g)
)
(call "${vmPeerId}" ("local_service_id" "local_fn_name") [] result_2)
)`;
const params = { init_peer_id: vmPeerId, current_peer_id: vmPeerId };
const json = invokeJson(s, b(''), b(''), params, {});
let res: any = marineInstance.call_module('avm', 'invoke', json);
res = JSON.parse(res);
console.log(res);
expect(res.error).toEqual("");
expect(res.result).toMatchObject({
ret_code: 0,
error_message: '',
});
});
});

View File

@ -0,0 +1,49 @@
#! /usr/bin/env node
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fs from 'fs';
import path from 'path';
const firstArgument = process.argv[2];
if (!firstArgument) {
console.log(`Expected exactly 1 argument, got 0. Usage: ${path.basename(process.argv[1])} <destination directory>`);
process.exit(1);
}
let destPath = firstArgument;
if (!path.isAbsolute(destPath)) {
destPath = path.join(process.cwd(), destPath);
}
const wasmName = 'marine-js.wasm';
const packageName = '@fluencelabs/marine-js';
const modulePath = require.resolve(packageName);
const source = path.join(path.dirname(modulePath), wasmName);
const dest = path.join(destPath, wasmName);
console.log('ensure directory exists: ', destPath);
fs.mkdirSync(destPath, { recursive: true });
console.log('copying marine-js wasm');
console.log('from: ', source);
console.log('to: ', dest);
fs.copyFileSync(source, dest);
console.log('done!');

View File

@ -0,0 +1,18 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { init } from './marine_web_runtime';

View File

@ -0,0 +1,292 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This is patched generated by wasm-pack file
import {
call_export,
read_byte,
write_byte,
get_memory_size,
read_byte_range,
write_byte_range
} from './snippets/marine-web-runtime-6faa67b8af9cc173/marine-js.js';
export async function init(module) {
let wasm;
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
function getObject(idx) {
return heap[idx];
}
let heap_next = heap.length;
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
let WASM_VECTOR_LEN = 0;
let cachedTextEncoder = new TextEncoder('utf-8');
const encodeString =
typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length,
};
};
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0()
.subarray(ptr, ptr + buf.length)
.set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
}
function getArrayU8FromWasm0(ptr, len) {
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
/**
*/
function main() {
wasm.main();
}
function passArray8ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 1);
getUint8Memory0().set(arg, ptr / 1);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
/**
* Registers a module insite web-runtime.
*
* # Arguments
*
* * `name` - name of module to register
* * `wit_section_bytes` - bytes of "interface-types" custom section from wasm file
* * `instance` - `WebAssembly::Instance` made from target wasm file
*
* # Return value
*
* JSON object with field "error". If error is empty, module is registered.
* otherwise, it contaits error message.
* @param {string} name
* @param {Uint8Array} wit_section_bytes
* @param {any} wasm_instance
* @returns {string}
*/
function register_module(name, wit_section_bytes, wasm_instance) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
var ptr1 = passArray8ToWasm0(wit_section_bytes, wasm.__wbindgen_malloc);
var len1 = WASM_VECTOR_LEN;
wasm.register_module(retptr, ptr0, len0, ptr1, len1, addHeapObject(wasm_instance));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
return getStringFromWasm0(r0, r1);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_free(r0, r1);
}
}
/**
* Calls a function from a module.
*
* # Arguments
*
* * module_name - name of registered module
* * function_name - name of the function to call
* * args - JSON array of function arguments
*
* # Return value
*
* JSON object with fields "error" and "result". If "error" is empty string,
* "result" contains a function return value. Othervise, "error" contains error message.
* @param {string} module_name
* @param {string} function_name
* @param {string} args
* @returns {string}
*/
function call_module(module_name, function_name, args) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
var ptr0 = passStringToWasm0(module_name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
var ptr1 = passStringToWasm0(function_name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
var ptr2 = passStringToWasm0(args, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len2 = WASM_VECTOR_LEN;
wasm.call_module(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
return getStringFromWasm0(r0, r1);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_free(r0, r1);
}
}
async function init(wasmModule) {
const imports = {};
imports.wbg = {};
imports.wbg.__wbg_getmemorysize_385fa0bd4e2d9ff6 = function(arg0) {
var ret = get_memory_size(getObject(arg0));
return ret;
};
imports.wbg.__wbg_new_693216e109162396 = function() {
var ret = new Error();
return addHeapObject(ret);
};
imports.wbg.__wbg_stack_0ddaca5d1abfb52f = function(arg0, arg1) {
var ret = getObject(arg1).stack;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_error_09919627ac0992f5 = function(arg0, arg1) {
try {
console.error(getStringFromWasm0(arg0, arg1));
} finally {
wasm.__wbindgen_free(arg0, arg1);
}
};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbg_writebyte_81064940ca9059c1 = function(arg0, arg1, arg2) {
write_byte(getObject(arg0), arg1 >>> 0, arg2);
};
imports.wbg.__wbg_writebyterange_313d990e0a3436b6 = function(arg0, arg1, arg2, arg3) {
write_byte_range(getObject(arg0), arg1 >>> 0, getArrayU8FromWasm0(arg2, arg3));
};
imports.wbg.__wbg_readbyterange_ebea9d02dea05828 = function(arg0, arg1, arg2, arg3) {
read_byte_range(getObject(arg0), arg1 >>> 0, getArrayU8FromWasm0(arg2, arg3));
};
imports.wbg.__wbg_callexport_cb1a6ee1197892bd = function(arg0, arg1, arg2, arg3, arg4, arg5) {
var ret = call_export(getObject(arg1), getStringFromWasm0(arg2, arg3), getStringFromWasm0(arg4, arg5));
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
const instance = await WebAssembly.instantiate(wasmModule, imports);
wasm = instance.exports;
// strange line from autogenerated code. No idea why it's needed
init.__wbindgen_wasm_module = module;
// calls main() function. Used to set up
wasm.__wbindgen_start();
return wasm;
}
await init(module);
return {
wasm: wasm,
register_module,
call_module,
};
}

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"lib": [
"es2015",
"dom"
],
"outDir": "./dist/",
"target": "es5",
"module": "commonjs",
"allowJs": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": false,
"sourceMap": true,
},
"exclude": [
"node_modules",
"dist"
],
"include": [
"src"
],
}

136
web-runtime/src/api.rs Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::faas::FluenceFaaS;
use crate::global_state::INSTANCE;
use crate::global_state::MODULES;
use marine_rs_sdk::CallParameters;
use wasm_bindgen::prelude::*;
use serde_json::Value as JValue;
use serde::{Serialize, Deserialize};
use maplit::hashmap;
#[derive(Serialize, Deserialize)]
struct RegisterModuleResult {
error: String,
}
#[derive(Serialize, Deserialize)]
struct CallModuleResult {
error: String,
result: JValue,
}
/// Registers a module inside web-runtime.
///
/// # Arguments
///
/// * `name` - name of module to register
/// * `wit_section_bytes` - bytes of "interface-types" custom section from wasm file
/// * `instance` - `WebAssembly::Instance` made from target wasm file
///
/// # Return value
///
/// JSON object with field "error". If error is empty, module is registered.
/// otherwise, it contains error message.
#[allow(unused)] // needed because clippy marks this function as unused
#[wasm_bindgen]
pub fn register_module(name: &str, wit_section_bytes: &[u8], wasm_instance: JsValue) -> String {
let modules = hashmap! {
name.to_string() => wit_section_bytes.to_vec(),
};
let faas = match FluenceFaaS::with_modules(modules) {
Ok(faas) => faas,
Err(e) => return make_register_module_result(e.to_string().as_str()),
};
MODULES.with(|modules| modules.replace(Some(faas)));
INSTANCE.with(|instance| instance.replace(Some(wasm_instance)));
make_register_module_result("")
}
/// Calls a function from a module.
///
/// # Arguments
///
/// * module_name - name of registered module
/// * function_name - name of the function to call
/// * args - JSON array of function arguments
///
/// # Return value
///
/// JSON object with fields "error" and "result". If "error" is empty string,
/// "result" contains a function return value. Otherwise, "error" contains error message.
#[allow(unused)] // needed because clippy marks this function as unused
#[wasm_bindgen]
pub fn call_module(module_name: &str, function_name: &str, args: &str) -> String {
MODULES.with(|modules| {
let mut modules = modules.borrow_mut();
let modules = match modules.as_mut() {
Some(modules) => modules,
None => {
return make_call_module_result(
JValue::Null,
"attempt to run a function when module is not loaded",
)
}
};
let args: JValue = match serde_json::from_str(args) {
Ok(args) => args,
Err(e) => {
return make_call_module_result(
JValue::Null,
&format!("Error deserializing args: {}", e),
)
}
};
match modules.call_with_json(module_name, function_name, args, CallParameters::default()) {
Ok(result) => make_call_module_result(result, ""),
Err(e) => make_call_module_result(
JValue::Null,
&format!("Error calling module function: {}", e),
),
}
})
}
#[allow(unused)] // needed because clippy marks this function as unused
fn make_register_module_result(error: &str) -> String {
let result = RegisterModuleResult {
error: error.to_string(),
};
// unwrap is safe because Serialize is derived for that struct and it does not contain maps with non-string keys
serde_json::ser::to_string(&result).unwrap()
}
#[allow(unused)] // needed because clippy marks this function as unused
fn make_call_module_result(result: JValue, error: &str) -> String {
let result = CallModuleResult {
error: error.to_string(),
result,
};
// unwrap is safe because Serialize is derived for that struct and it does not contain maps with non-string keys
serde_json::ser::to_string(&result).unwrap()
}

145
web-runtime/src/engine.rs Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::module::MRecordTypes;
use crate::module::MModule;
use crate::module::MFunctionSignature;
use crate::MResult;
use crate::MError;
use crate::IValue;
use crate::IRecordType;
use serde::Serialize;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::rc::Rc;
/// Represent Marine module interface.
#[derive(PartialEq, Eq, Debug, Clone, Serialize)]
pub struct MModuleInterface<'a> {
pub record_types: &'a MRecordTypes,
pub function_signatures: Vec<MFunctionSignature>,
}
/// The base struct of Marine, the Fluence compute runtime.
pub struct Marine {
// set of modules registered inside Marine
modules: HashMap<String, MModule>,
}
// these methods will be used when decoupling common code from marine-runtime end web-marine-runtime
#[allow(unused)]
impl Marine {
pub fn new() -> Self {
Self {
modules: HashMap::new(),
}
}
/// Invoke a function of a module inside Marine by given function name with given arguments.
pub fn call<MN: AsRef<str>, FN: AsRef<str>>(
&mut self,
module_name: MN,
func_name: FN,
arguments: &[IValue],
) -> MResult<Vec<IValue>> {
let module_name = module_name.as_ref();
self.modules.get_mut(module_name).map_or_else(
|| Err(MError::NoSuchModule(module_name.to_string())),
|module| module.call(module_name, func_name.as_ref(), arguments),
)
}
/// Load a new module inside Marine.
pub fn load_module<S: Into<String>>(
&mut self,
name: S,
wit_section_bytes: &[u8],
) -> MResult<()> {
self.load_module_(name.into(), wit_section_bytes)
}
fn load_module_(&mut self, name: String, wit_section_bytes: &[u8]) -> MResult<()> {
let module = MModule::new(&name, wit_section_bytes)?;
match self.modules.entry(name) {
Entry::Vacant(entry) => {
entry.insert(module);
Ok(())
}
Entry::Occupied(entry) => Err(MError::NonUniqueModuleName(entry.key().clone())),
}
}
/// Unload previously loaded module.
pub fn unload_module<S: AsRef<str>>(&mut self, name: S) -> MResult<()> {
// TODO: clean up all reference from adaptors after adding support of lazy linking
self.modules
.remove(name.as_ref())
.map(|_| ())
.ok_or_else(|| MError::NoSuchModule(name.as_ref().to_string()))
}
/// Return function signatures of all loaded info Marine modules with their names.
pub fn interface(&self) -> impl Iterator<Item = (&str, MModuleInterface<'_>)> {
self.modules
.iter()
.map(|(module_name, module)| (module_name.as_str(), Self::get_module_interface(module)))
}
/// Return function signatures exported by module with given name.
pub fn module_interface<S: AsRef<str>>(&self, module_name: S) -> Option<MModuleInterface<'_>> {
self.modules
.get(module_name.as_ref())
.map(Self::get_module_interface)
}
/// Return record types exported by module with given name.
pub fn module_record_types<S: AsRef<str>>(&self, module_name: S) -> Option<&MRecordTypes> {
self.modules
.get(module_name.as_ref())
.map(|module| module.export_record_types())
}
/// Return record type for supplied record id exported by module with given name.
pub fn module_record_type_by_id<S: AsRef<str>>(
&self,
module_name: S,
record_id: u64,
) -> Option<&Rc<IRecordType>> {
self.modules
.get(module_name.as_ref())
.and_then(|module| module.export_record_type_by_id(record_id))
}
fn get_module_interface(module: &MModule) -> MModuleInterface<'_> {
let record_types = module.export_record_types();
let function_signatures = module.get_exports_signatures().collect::<Vec<_>>();
MModuleInterface {
record_types,
function_signatures,
}
}
}
impl Default for Marine {
fn default() -> Self {
Self::new()
}
}

95
web-runtime/src/errors.rs Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use marine_it_interfaces::MITInterfacesError;
use marine_module_interface::it_interface::ITInterfaceError;
use thiserror::Error as ThisError;
// TODO: refactor errors
// these errors most likely will be used while moving wasm compilation/instantiation into marine-web
#[allow(unused)]
#[derive(Debug, ThisError)]
pub enum MError {
/// Errors related to failed resolving of records.
#[error("{0}")]
RecordResolveError(String),
/// Errors occurred inside marine-module-interface crate.
#[error(transparent)]
ModuleInterfaceError(#[from] ITInterfaceError),
/// Error arisen during execution of Wasm modules (especially, interface types).
#[error("Execution error: {0}")]
ITInstructionError(#[from] wasmer_it::errors::InstructionError),
/// Indicates that there is already a module with such name.
#[error("module with name '{0}' already loaded into Marine, please specify another name")]
NonUniqueModuleName(String),
/// Returns when there is no module with such name.
#[error("module with name '{0}' doesn't have function with name {1}")]
NoSuchFunction(String, String),
/// Returns when there is no module with such name.
#[error("module with name '{0}' isn't loaded into Marine")]
NoSuchModule(String),
/// Incorrect IT section.
#[error("{0}")]
IncorrectWIT(String),
/// Provided module doesn't contain a sdk version that is necessary.
#[error("module with name '{0}' doesn't contain a version of sdk, probably it's compiled with an old one")]
ModuleWithoutVersion(String),
/// Module sdk versions are incompatible.
#[error("module with name '{module_name}' compiled with {provided} sdk version, but at least {required} required")]
IncompatibleSDKVersions {
module_name: String,
required: semver::Version,
provided: semver::Version,
},
/// Module IT versions are incompatible.
#[error("module with name '{module_name}' compiled with {provided} IT version, but at least {required} required")]
IncompatibleITVersions {
module_name: String,
required: semver::Version,
provided: semver::Version,
},
#[error("some error expressed as string: {0}")]
StringError(String),
}
impl From<MITInterfacesError> for MError {
fn from(err: MITInterfacesError) -> Self {
MError::IncorrectWIT(format!("{}", err))
}
}
impl From<String> for MError {
fn from(err: String) -> Self {
MError::StringError(err)
}
}
impl From<()> for MError {
fn from(_err: ()) -> Self {
MError::IncorrectWIT("failed to parse instructions for adapter type".to_string())
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::MError;
use thiserror::Error;
use std::io::Error as IOError;
#[derive(Debug, Error)]
pub enum FaaSError {
/// Various errors related to file i/o.
#[error("IOError: {0}")]
IOError(String),
/// A function with specified name is missing.
#[error("function with name `{0}` is missing")]
MissingFunctionError(String),
/// Returns when there is no module with such name.
#[error(r#"module with name "{0}" is missing"#)]
NoSuchModule(String),
/// Provided arguments aren't compatible with a called function signature.
#[error("arguments from json deserialization error: {0}")]
JsonArgumentsDeserializationError(String),
/// Returned outputs aren't compatible with a called function signature.
#[error("output to json serialization error: {0}")]
JsonOutputSerializationError(String),
/// Errors related to invalid config.
#[error("parsing config error: {0}")]
ParseConfigError(#[from] toml::de::Error),
/// Marine errors.
#[error("engine error: {0}")]
EngineError(#[from] MError),
}
impl From<IOError> for FaaSError {
fn from(err: IOError) -> Self {
FaaSError::IOError(format!("{}", err))
}
}
impl From<std::convert::Infallible> for FaaSError {
fn from(_: std::convert::Infallible) -> Self {
unreachable!()
}
}

View File

@ -0,0 +1,177 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::faas::faas_interface::FaaSInterface;
use crate::faas::FaaSError;
use crate::faas::Result;
use crate::IValue;
use crate::IType;
use crate::Marine;
use crate::IFunctionArg;
use crate::MRecordTypes;
//use marine_utils::SharedString;
use marine_rs_sdk::CallParameters;
use serde_json::Value as JValue;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
type MFunctionSignature = (Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>);
type MModuleInterface = (Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>, Rc<MRecordTypes>);
struct ModuleInterface {
function_signatures: HashMap<String, MFunctionSignature>,
record_types: Rc<MRecordTypes>,
}
// TODO: remove and use mutex instead
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for FluenceFaaS {}
pub struct FluenceFaaS {
/// Marine instance.
marine: Marine,
/// Parameters of call accessible by Wasm modules.
call_parameters: Rc<RefCell<CallParameters>>,
/// Cached module interfaces by names.
module_interfaces_cache: HashMap<String, ModuleInterface>,
}
#[allow(unused)]
impl FluenceFaaS {
/// Creates FaaS with given modules.
pub fn with_modules(modules: HashMap<String, Vec<u8>>) -> Result<Self> {
let mut marine = Marine::new();
let call_parameters = Rc::new(RefCell::new(CallParameters::default()));
for (name, wit_section_bytes) in modules {
marine.load_module(name, &wit_section_bytes)?;
}
Ok(Self {
marine,
call_parameters,
module_interfaces_cache: HashMap::new(),
})
}
/// Call a specified function of loaded on a startup module by its name.
pub fn call_with_ivalues<MN: AsRef<str>, FN: AsRef<str>>(
&mut self,
module_name: MN,
func_name: FN,
args: &[IValue],
call_parameters: marine_rs_sdk::CallParameters,
) -> Result<Vec<IValue>> {
self.call_parameters.replace(call_parameters);
self.marine
.call(module_name, func_name, args)
.map_err(Into::into)
}
/// Call a specified function of loaded on a startup module by its name.
pub fn call_with_json<MN: AsRef<str>, FN: AsRef<str>>(
&mut self,
module_name: MN,
func_name: FN,
json_args: JValue,
call_parameters: marine_rs_sdk::CallParameters,
) -> Result<JValue> {
use crate::faas::json::json_to_ivalues;
use crate::faas::json::ivalues_to_json;
let module_name = module_name.as_ref();
let func_name = func_name.as_ref();
let (func_signature, output_types, record_types) =
self.lookup_module_interface(module_name, func_name)?;
let iargs = json_to_ivalues(
json_args,
func_signature.iter().map(|arg| (&arg.name, &arg.ty)),
&record_types,
)?;
self.call_parameters.replace(call_parameters);
let result = self.marine.call(module_name, func_name, &iargs)?;
ivalues_to_json(result, &output_types, &record_types)
}
/// Return all export functions (name and signatures) of loaded modules.
pub fn get_interface(&self) -> FaaSInterface<'_> {
let modules = self.marine.interface().collect();
FaaSInterface { modules }
}
/// At first, tries to find function signature and record types in module_interface_cache,
/// if there is no them, tries to look
fn lookup_module_interface<'faas>(
&'faas mut self,
module_name: &str,
func_name: &str,
) -> Result<MModuleInterface> {
use FaaSError::NoSuchModule;
use FaaSError::MissingFunctionError;
if let Some(module_interface) = self.module_interfaces_cache.get(module_name) {
if let Some(function) = module_interface.function_signatures.get(func_name) {
return Ok((
function.0.clone(),
function.1.clone(),
module_interface.record_types.clone(),
));
}
return Err(MissingFunctionError(func_name.to_string()));
}
let module_interface = self
.marine
.module_interface(module_name)
.ok_or_else(|| NoSuchModule(module_name.to_string()))?;
let function_signatures = module_interface
.function_signatures
.iter()
.cloned()
.map(|f| (f.name.to_string(), (f.arguments, f.outputs)))
.collect::<HashMap<_, _>>();
let (arg_types, output_types) = function_signatures
.get(func_name)
.ok_or_else(|| MissingFunctionError(func_name.to_string()))?;
let arg_types = arg_types.clone();
let output_types = output_types.clone();
let record_types = Rc::new(module_interface.record_types.clone());
let module_interface = ModuleInterface {
function_signatures,
record_types: record_types.clone(),
};
self.module_interfaces_cache
.insert(func_name.to_string(), module_interface);
Ok((arg_types, output_types, record_types))
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::IRecordType;
use super::itype_text_view;
use crate::faas::FaaSModuleInterface;
use itertools::Itertools;
use serde::Serialize;
use std::fmt;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct FaaSInterface<'a> {
pub modules: HashMap<&'a str, FaaSModuleInterface<'a>>,
}
impl<'a> fmt::Display for FaaSInterface<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
print_record_types(self.modules.values(), f)?;
print_functions_sign(self.modules.iter(), f)
}
}
fn print_record_types<'r>(
modules: impl Iterator<Item = &'r FaaSModuleInterface<'r>>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
use std::collections::HashSet;
let mut printed_record_types: HashSet<&IRecordType> = HashSet::new();
for module in modules {
for (_, record_type) in module.record_types.iter() {
if !printed_record_types.insert(record_type) {
// do not print record if it has been already printed
continue;
}
writeln!(f, "data {}:", record_type.name)?;
for field in record_type.fields.iter() {
writeln!(
f,
" {}: {}",
field.name,
itype_text_view(&field.ty, module.record_types)
)?;
}
}
}
writeln!(f)
}
fn print_functions_sign<'r>(
modules: impl Iterator<Item = (&'r &'r str, &'r FaaSModuleInterface<'r>)>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
for (name, module_interface) in modules {
writeln!(f, "{}:", *name)?;
for function_signature in module_interface.function_signatures.iter() {
write!(f, " fn {}(", function_signature.name)?;
let args = function_signature
.arguments
.iter()
.map(|arg| {
format!(
"{}: {}",
arg.name,
itype_text_view(&arg.ty, module_interface.record_types)
)
})
.join(", ");
let outputs = &function_signature.outputs;
if outputs.is_empty() {
writeln!(f, "{})", args)?;
} else if outputs.len() == 1 {
writeln!(
f,
"{}) -> {}",
args,
itype_text_view(&outputs[0], module_interface.record_types)
)?;
} else {
// At now, multi values aren't supported - only one output type is possible
unimplemented!()
}
}
}
Ok(())
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::IValue;
use crate::IType;
use crate::faas::Result;
use crate::faas::errors::FaaSError::JsonOutputSerializationError as OutputDeError;
use crate::MRecordTypes;
use serde_json::Value as JValue;
pub(crate) fn ivalues_to_json(
mut ivalues: Vec<IValue>,
outputs: &[IType],
record_types: &MRecordTypes,
) -> Result<JValue> {
if outputs.len() != ivalues.len() {
return Err(OutputDeError(format!(
"resulted values {:?} and function signature {:?} aren't compatible",
ivalues, outputs
)));
}
match ivalues.len() {
0 => Ok(JValue::Null),
1 => ivalue_to_json(ivalues.remove(0), outputs.first().unwrap(), record_types),
_ => unimplemented!(
"multi-values aren't supported now - more then one result values aren't possible"
),
}
}
fn ivalue_to_json(ivalue: IValue, output: &IType, record_types: &MRecordTypes) -> Result<JValue> {
use serde_json::json;
// clone here needed because binding by-value and by-ref in the same pattern in unstable
match (ivalue, output.clone()) {
(IValue::Boolean(value), IType::Boolean) => Ok(json!(value)),
(IValue::S8(value), IType::S8) => Ok(json!(value)),
(IValue::S16(value), IType::S16) => Ok(json!(value)),
(IValue::S32(value), IType::S32) => Ok(json!(value)),
(IValue::S64(value), IType::S64) => Ok(json!(value)),
(IValue::U8(value), IType::U8) => Ok(json!(value)),
(IValue::U16(value), IType::U16) => Ok(json!(value)),
(IValue::U32(value), IType::U32) => Ok(json!(value)),
(IValue::U64(value), IType::U64) => Ok(json!(value)),
(IValue::I32(value), IType::I32) => Ok(json!(value)),
(IValue::I64(value), IType::I64) => Ok(json!(value)),
(IValue::F32(value), IType::F32) => Ok(json!(value)),
(IValue::F64(value), IType::F64) => Ok(json!(value)),
(IValue::String(value), IType::String) => Ok(json!(value)),
(IValue::ByteArray(value), IType::ByteArray) => {
let result = value.into_iter().map(|v| json!(v)).collect();
Ok(JValue::Array(result))
}
(IValue::Array(value), IType::ByteArray) => {
let result: Result<Vec<_>> = value
.into_iter()
.map(|v| ivalue_to_json(v, &IType::U8, record_types))
.collect();
Ok(JValue::Array(result?))
}
(IValue::ByteArray(value), IType::Array(array_ty)) => {
let result: Result<Vec<_>> = value
.into_iter()
.map(|v| ivalue_to_json(IValue::U8(v), &array_ty, record_types))
.collect();
Ok(JValue::Array(result?))
}
(IValue::Array(value), IType::Array(array_ty)) => {
let result: Result<Vec<_>> = value
.into_iter()
.map(|v| ivalue_to_json(v, &array_ty, record_types))
.collect();
Ok(JValue::Array(result?))
}
(IValue::Record(field_values), IType::Record(record_id)) => {
let record_type = record_types.get(&record_id).ok_or_else(|| {
OutputDeError(format!(
"record id {} wasn't found in module record types",
record_id
))
})?;
let field_types = &record_type.fields;
if field_values.len() != field_types.len() {
return Err(OutputDeError(format!(
"output record {:?} isn't compatible to output record fields {:?}",
field_values, field_types
)));
}
let field_values = field_values.into_vec();
let mut result = serde_json::Map::with_capacity(field_values.len());
for (field_value, field_type) in field_values.into_iter().zip(field_types.iter()) {
let json_field_value = ivalue_to_json(field_value, &field_type.ty, record_types)?;
result.insert(field_type.name.clone(), json_field_value);
}
Ok(JValue::Object(result))
}
(ivalue, itype) => Err(OutputDeError(format!(
"value {:?} is incompatible to type {:?}",
ivalue, itype
))),
}
}

View File

@ -0,0 +1,244 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::IValue;
use crate::IType;
use crate::faas::Result;
use crate::faas::FaaSError::JsonArgumentsDeserializationError as ArgDeError;
use crate::MRecordTypes;
use wasmer_it::NEVec;
use serde_json::Value as JValue;
use std::collections::HashMap;
use std::iter::ExactSizeIterator;
/// Convert json to an array of ivalues according to the supplied argument types.
pub(crate) fn json_to_ivalues<'a, 'b>(
json_args: JValue,
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
record_types: &'b MRecordTypes,
) -> Result<Vec<IValue>> {
let ivalues = match json_args {
JValue::Object(json_map) => json_map_to_ivalues(json_map, arg_types, record_types)?,
JValue::Array(json_array) => {
json_array_to_ivalues(json_array, arg_types.map(|arg| arg.1), record_types)?
}
JValue::Null => json_null_to_ivalues(arg_types)?,
json_value => json_value_to_ivalues(json_value, arg_types)?,
};
Ok(ivalues)
}
/// Convert json map to an array of ivalues according to the supplied argument types.
fn json_map_to_ivalues<'a, 'b>(
mut json_map: serde_json::Map<String, JValue>,
arg_types: impl Iterator<Item = (&'a String, &'a IType)>,
record_types: &'b MRecordTypes,
) -> Result<Vec<IValue>> {
let mut iargs = Vec::new();
for (arg_name, arg_type) in arg_types {
let json_value = json_map
.remove(arg_name)
.ok_or_else(|| ArgDeError(format!("missing argument with name {}", arg_name)))?;
let iarg = jvalue_to_ivalue(json_value, arg_type, record_types)?;
iargs.push(iarg);
}
if !json_map.is_empty() {
return Err(ArgDeError(format!(
"function requires {} arguments, {} provided",
iargs.len(),
iargs.len() + json_map.len()
)));
}
Ok(iargs)
}
/// Convert json array to an array of ivalues according to the supplied argument types.
fn json_array_to_ivalues<'a, 'b>(
json_array: Vec<JValue>,
arg_types: impl Iterator<Item = &'a IType> + ExactSizeIterator,
record_types: &'b MRecordTypes,
) -> Result<Vec<IValue>> {
if json_array.len() != arg_types.len() {
return Err(ArgDeError(format!(
"function requires {} arguments, {} provided",
arg_types.len(),
json_array.len()
)));
}
let iargs = json_array
.into_iter()
.zip(arg_types)
.map(|(json_value, arg_type)| jvalue_to_ivalue(json_value, arg_type, record_types))
.collect::<Result<Vec<_>>>()?;
Ok(iargs)
}
/// Convert json value (Number, String or Bool) to an array of ivalues according to the supplied argument types.
fn json_value_to_ivalues<'a>(
json_value: JValue,
mut arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
) -> Result<Vec<IValue>> {
if arg_types.len() != 1 {
return Err(ArgDeError(format!(
"called function has the following signature: '{:?}', and it isn't suitable for an argument '{:?}' provided",
arg_types.collect::<Vec<_>>(),
json_value,
)));
}
// unwrap is safe here because iterator size's been checked
let arg_type = arg_types.next().unwrap().1;
let ivalue = jvalue_to_ivalue(json_value, arg_type, &HashMap::new())?;
Ok(vec![ivalue])
}
/// Convert json Null to an empty array of ivalues.
fn json_null_to_ivalues<'a>(
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
) -> Result<Vec<IValue>> {
if arg_types.len() != 0 {
return Err(ArgDeError(format!(
"the called function has the following signature: {:?}, but no arguments is provided",
arg_types.collect::<Vec<_>>()
)));
}
Ok(vec![])
}
/// Convert one JValue to an array of ivalues according to the supplied argument type.
fn jvalue_to_ivalue(jvalue: JValue, ty: &IType, record_types: &MRecordTypes) -> Result<IValue> {
macro_rules! to_ivalue(
($json_value:expr, $ty:ident) => {
{
let value = match $json_value {
// if there is an array with only one element try to implicitly flatten it,
// this is needed mostly because jsonpath lib returns Vec<&JValue> and
// could be changed in future
JValue::Array(mut json_array) if json_array.len() == 1 => {
serde_json::from_value(json_array.remove(0))
},
jvalue => serde_json::from_value(jvalue),
}.map_err(|e|
ArgDeError(format!("error {:?} occurred while deserialize output result to a json value",e))
)?;
Ok(IValue::$ty(value))
}
}
);
match ty {
IType::Boolean => to_ivalue!(jvalue, Boolean),
IType::S8 => to_ivalue!(jvalue, S8),
IType::S16 => to_ivalue!(jvalue, S16),
IType::S32 => to_ivalue!(jvalue, S32),
IType::S64 => to_ivalue!(jvalue, S64),
IType::U8 => to_ivalue!(jvalue, U8),
IType::U16 => to_ivalue!(jvalue, U16),
IType::U32 => to_ivalue!(jvalue, U32),
IType::U64 => to_ivalue!(jvalue, U64),
IType::F32 => to_ivalue!(jvalue, F32),
IType::F64 => to_ivalue!(jvalue, F64),
IType::String => to_ivalue!(jvalue, String),
IType::ByteArray => {
let value = match jvalue {
JValue::Array(json_array) => {
let iargs = json_array
.into_iter()
.map(|json_value| jvalue_to_ivalue(json_value, &IType::U8, record_types))
.collect::<Result<Vec<_>>>()?;
Ok(iargs)
}
_ => Err(ArgDeError(format!("expected bytearray, got {:?}", jvalue))),
}?;
Ok(IValue::Array(value))
}
IType::Array(value_type) => {
let value = match jvalue {
JValue::Array(json_array) => {
let iargs = json_array
.into_iter()
.map(|json_value| jvalue_to_ivalue(json_value, value_type, record_types))
.collect::<Result<Vec<_>>>()?;
Ok(iargs)
}
_ => Err(ArgDeError(format!(
"expected array of {:?} types, got {:?}",
value_type, jvalue
))),
}?;
Ok(IValue::Array(value))
}
IType::I32 => to_ivalue!(jvalue, I32),
IType::I64 => to_ivalue!(jvalue, I64),
IType::Record(record_type_id) => {
let value = json_record_type_to_ivalue(jvalue, record_type_id, record_types)?;
Ok(IValue::Record(value))
}
}
}
#[allow(clippy::ptr_arg)]
/// Convert JValue of array or object types to an IValue record type.
// TODO: after introducing new Record type wrapper change the result type
fn json_record_type_to_ivalue(
json_value: JValue,
record_type_id: &u64,
record_types: &MRecordTypes,
) -> Result<NEVec<IValue>> {
let record_type = record_types.get(record_type_id).ok_or_else(|| {
ArgDeError(format!(
"record with type id `{}` wasn't found",
record_type_id
))
})?;
match json_value {
JValue::Object(json_map) => Ok(NEVec::new(json_map_to_ivalues(
json_map,
record_type
.fields
.iter()
.map(|field| (&field.name, &field.ty)),
record_types,
)?)
.unwrap()),
JValue::Array(json_array) => Ok(NEVec::new(json_array_to_ivalues(
json_array,
record_type.fields.iter().map(|field| (&field.ty)),
record_types,
)?)
.unwrap()),
_ => Err(ArgDeError(format!(
"record with type id `{}` should be encoded as array or map of fields",
record_type_id
))),
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod ivalues_to_json;
mod json_to_ivalues;
pub(crate) use ivalues_to_json::ivalues_to_json;
pub(crate) use json_to_ivalues::json_to_ivalues;

View File

@ -0,0 +1,36 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod json;
mod errors;
mod faas;
mod faas_interface;
pub(crate) type Result<T> = std::result::Result<T, FaaSError>;
pub use faas::FluenceFaaS;
pub use faas_interface::FaaSInterface;
pub use errors::FaaSError;
// Re-exports from Marine
pub(crate) use crate::IRecordType;
pub(crate) use crate::MModuleInterface as FaaSModuleInterface;
pub use marine_module_interface::interface::itype_text_view;
pub use marine_rs_sdk::CallParameters;
pub use marine_rs_sdk::SecurityTetraplet;

View File

@ -0,0 +1,26 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::faas::FluenceFaaS;
use wasm_bindgen::prelude::JsValue;
use std::cell::RefCell;
// two variables required because public api functions borrow_mut MODULES,
// and deep internal functions borrow_mut INSTANCE
// this is a bad design, and it will be refactored while moving wasm compilation inside marine-web
thread_local!(pub(crate) static MODULES: RefCell<Option<FluenceFaaS>> = RefCell::new(None));
thread_local!(pub(crate) static INSTANCE: RefCell<Option<JsValue>> = RefCell::new(None));

58
web-runtime/src/lib.rs Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![warn(rust_2018_idioms)]
#![feature(get_mut_unchecked)]
#![feature(new_uninit)]
#![feature(stmt_expr_attributes)]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
mod engine;
mod errors;
mod misc;
mod module;
mod faas;
mod global_state;
mod api; // contains public API functions exported to JS
mod marine_js;
pub(crate) use engine::MModuleInterface;
pub(crate) use engine::Marine;
pub(crate) use errors::MError;
pub(crate) use module::IValue;
pub(crate) use module::IRecordType;
pub(crate) use module::IFunctionArg;
pub(crate) use module::IType;
pub(crate) use module::MRecordTypes;
pub(crate) type MResult<T> = std::result::Result<T, MError>;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::prelude::JsValue;
#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
// prints human-readable stracktrace on panics, useful when investigating problems
console_error_panic_hook::set_once();
Ok(())
}

View File

@ -0,0 +1,334 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::module::type_converters::{itypes_args_to_wtypes, itypes_output_to_wtypes};
use crate::global_state::INSTANCE;
use marine_it_interfaces::MITInterfaces;
use wasmer_it::ast::FunctionArg;
use wasm_bindgen::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value as JValue;
use std::borrow::{Cow};
use std::rc::Rc;
const ALLOCATE_FUNC_NAME: &str = "allocate";
// marine-related imports
#[wasm_bindgen(module = "/marine-js.js")]
extern "C" {
pub fn call_export(module_name: &JsValue, export_name: &str, args: &str) -> String;
pub fn write_byte(module_name: &JsValue, module_offset: usize, value: u8);
pub fn read_byte(module_name: &JsValue, module_offset: usize) -> u8;
pub fn get_memory_size(module_name: &JsValue) -> i32;
pub fn read_byte_range(module_name: &JsValue, module_offset: usize, slice: &mut [u8]);
pub fn write_byte_range(module_name: &JsValue, module_offset: usize, slice: &[u8]);
}
#[derive(Clone)]
pub struct FuncSig {
params: Cow<'static, [WType]>,
returns: Cow<'static, [WType]>,
}
impl FuncSig {
pub fn params(&self) -> &[WType] {
&self.params
}
pub fn returns(&self) -> &[WType] {
&self.returns
}
}
pub struct Instance {
pub exports: Exports,
pub module_name: Rc<String>,
}
impl Instance {
pub fn new(mit: &MITInterfaces<'_>, module_name: Rc<String>) -> Self {
Self {
exports: Exports::new(mit, module_name.clone()),
module_name,
}
}
pub fn exports(&self) -> ExportIter<'_> {
ExportIter::new(&self.exports)
}
}
pub struct DynFunc {
pub(crate) signature: FuncSig,
pub name: Rc<String>,
pub module_name: Rc<String>,
}
impl DynFunc {
pub fn signature(&self) -> &FuncSig {
&self.signature
}
pub fn call(&self, args: &[WValue]) -> Result<Vec<WValue>, String> {
let args = match serde_json::ser::to_string(args) {
Ok(args) => args,
Err(e) => return Err(format!("cannot serialize call arguments, error: {}", e)),
};
// .unwrap() here is safe because this method can be called only if MODULES
// is Some, and register_module sets MODULES and INSTANCE to Some at the same time.
// And at the same time they are set to NONE at the start of the application
let output = INSTANCE
.with(|instance| call_export(instance.borrow().as_ref().unwrap(), &self.name, &args));
let value = serde_json::de::from_str::<JValue>(&output);
match value {
Ok(JValue::Array(values)) => {
if values.len() != self.signature.returns().len() {
return Err(format!(
"expected {} return values, got {}",
self.signature.returns().len(),
values.len()
));
}
values
.iter()
.zip(self.signature.returns())
.map(|(value, ty)| {
match ty {
WType::I32 => value.as_i64().map(|value| WValue::I32(value as i32)),
WType::I64 => value.as_i64().map(|value| WValue::I64(value)),
WType::F32 => value.as_f64().map(|value| WValue::F32(value as f32)),
WType::F64 => value.as_f64().map(|value| WValue::F64(value)),
WType::V128 => None,
}
.ok_or(format!("Cannot convert value {} to type {}", value, ty))
})
.collect::<Result<Vec<_>, String>>()
}
_ => Err("invalid json got".to_string()),
}
}
}
#[derive(Clone)]
pub enum Export {
Memory,
Function(ProcessedExport),
}
impl Export {
pub fn name(&self) -> &str {
match self {
Self::Memory => "memory",
Self::Function(func) => &func.name,
}
}
}
pub struct Exports {
exports: Vec<Export>,
module_name: Rc<String>,
}
impl Exports {
pub fn new(mit: &MITInterfaces<'_>, module_name: Rc<String>) -> Self {
let mut exports = mit
.exports()
.filter_map(|export| Self::process_export(export, mit))
.collect::<Vec<Export>>();
// Exports in marine-web are extracted from interface-definition. It is a hack, it is used
// because extracting exports from JS is harder than extracting it from interface-types.
// But interface-types do not have a "memory" export, so it is added here manually.
// TODO: refactor when wasm module creation is fully in control of marine-web.
exports.push(Export::Memory);
Self {
exports,
module_name,
}
}
fn process_export(
export: &wasmer_it::ast::Export<'_>,
mit: &MITInterfaces<'_>,
) -> Option<Export> {
use wasmer_it::ast::Type;
match mit.type_by_idx(export.function_type) {
Some(Type::Function {
arguments,
output_types,
}) => Some(Self::process_export_function(
arguments.as_slice(),
output_types.as_slice(),
export.name,
)),
Some(_) => None,
None => unreachable!("code should not reach that arm"),
}
}
fn process_export_function(
arguments: &[FunctionArg],
output_types: &[wasmer_it::IType],
function_name: &str,
) -> Export {
let mut arg_types = itypes_args_to_wtypes(arguments.iter().map(|arg| &arg.ty));
let output_types = itypes_output_to_wtypes(output_types.iter());
// raw export allocate function as a slightly different signature: it takes also "tag" argument
// it is used in marine-runtime, and interface-types pass an argument there
// so here signature is updated to match the expectations
if function_name == ALLOCATE_FUNC_NAME {
arg_types.push(WType::I32);
}
let sig = FuncSig {
params: Cow::Owned(arg_types),
returns: Cow::Owned(output_types),
};
Export::Function(ProcessedExport {
sig,
name: Rc::new(function_name.to_string()),
})
}
pub fn get(&self, name: &str) -> Result<DynFunc, String> {
let export = self.exports.iter().find(|export| match export {
Export::Function(func) => func.name.as_str() == name,
_ => false,
});
match export {
Some(Export::Function(function)) => Ok(DynFunc {
signature: function.sig.clone(),
name: function.name.clone(),
module_name: self.module_name.clone(),
}),
Some(_) | None => Err(format!("cannot find export {}", name)),
}
}
}
#[derive(Clone)]
pub struct ProcessedExport {
sig: FuncSig,
name: Rc<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WType {
/// The `i32` type.
I32,
/// The `i64` type.
I64,
/// The `f32` type.
F32,
/// The `f64` type.
F64,
/// The `v128` type.
V128,
}
impl std::fmt::Display for WType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
/// Represents a WebAssembly value.
///
/// As the number of types in WebAssembly expand,
/// this structure will expand as well.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WValue {
/// The `i32` type.
I32(i32),
/// The `i64` type.
I64(i64),
/// The `f32` type.
F32(f32),
/// The `f64` type.
F64(f64),
/// The `v128` type.
V128(u128),
}
/// An iterator to an instance's exports.
pub struct ExportIter<'a> {
exports: &'a Exports,
index: usize,
}
impl<'a> ExportIter<'a> {
pub(crate) fn new(exports: &'a Exports) -> Self {
Self { exports, index: 0 }
}
}
impl<'a> Iterator for ExportIter<'a> {
type Item = (&'a str, Export);
fn next(&mut self) -> Option<Self::Item> {
let export = self.exports.exports.get(self.index);
self.index += 1;
export.map(|export| (export.name(), export.clone()))
}
}
#[derive(Clone)]
pub struct JsWasmMemoryProxy {
pub module_name: Rc<String>,
}
// .unwrap() on INSTANCE in these methods is safe because they can be called only if MODULES
// is Some, and register_module sets MODULES and INSTANCE to Some at the same time.
// And at the same time they are set to NONE at the start of the application
impl JsWasmMemoryProxy {
pub fn new(module_name: Rc<String>) -> Self {
Self { module_name }
}
pub fn get(&self, index: usize) -> u8 {
INSTANCE.with(|instance| read_byte(instance.borrow().as_ref().unwrap(), index))
}
pub fn set(&self, index: usize, value: u8) {
INSTANCE.with(|instance| write_byte(instance.borrow().as_ref().unwrap(), index, value))
}
pub fn len(&self) -> usize {
INSTANCE.with(|instance| get_memory_size(instance.borrow().as_ref().unwrap()) as usize)
}
pub fn get_range(&self, offset: usize, size: usize) -> Vec<u8> {
INSTANCE.with(|instance| {
let mut result = vec![0; size];
read_byte_range(instance.borrow().as_ref().unwrap(), offset, &mut result);
result
})
}
pub fn set_range(&self, offset: usize, data: &[u8]) {
INSTANCE.with(|instance| {
write_byte_range(instance.borrow().as_ref().unwrap(), offset, data);
})
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod version_checker;
pub(crate) use version_checker::check_it_version;

View File

@ -0,0 +1,36 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::MResult;
use crate::MError;
use marine_min_it_version::min_it_version;
pub(crate) fn check_it_version(
name: impl Into<String>,
it_version: &semver::Version,
) -> MResult<()> {
let required_version = min_it_version();
if it_version < required_version {
return Err(MError::IncompatibleITVersions {
module_name: name.into(),
required: required_version.clone(),
provided: it_version.clone(),
});
}
Ok(())
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::IValue;
use super::IType;
use super::IFunctionArg;
use wasmer_it::interpreter::wasm;
// In current implementation export simply does nothing, because there is no more
// explicit instruction call-export in this version of wasmer-interface-types,
// but explicit Exports is still required by wasmer-interface-types::Interpreter.
#[derive(Clone)]
pub(crate) struct ITExport {
name: String,
arguments: Vec<IFunctionArg>,
outputs: Vec<IType>,
function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
}
impl ITExport {
#[allow(unused)]
pub(crate) fn new() -> Self {
Self {
name: String::new(),
arguments: vec![],
outputs: vec![],
function: |_| -> _ { Ok(vec![]) },
}
}
}
impl wasm::structures::Export for ITExport {
fn name(&self) -> &str {
self.name.as_str()
}
fn inputs_cardinality(&self) -> usize {
self.arguments.len()
}
fn outputs_cardinality(&self) -> usize {
self.outputs.len()
}
fn arguments(&self) -> &[IFunctionArg] {
&self.arguments
}
fn outputs(&self) -> &[IType] {
&self.outputs
}
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
(self.function)(arguments)
}
}

View File

@ -0,0 +1,185 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::wit_prelude::*;
use super::MFunctionSignature;
use super::MRecordTypes;
use super::{IType, IRecordType, IFunctionArg, IValue};
use crate::MResult;
use crate::marine_js::{Instance as WasmerInstance};
use crate::module::wit_function::WITFunction;
use marine_it_interfaces::MITInterfaces;
use marine_utils::SharedString;
use wasmer_it::interpreter::Interpreter;
use wasmer_it::ast::Interfaces;
use std::collections::HashMap;
use std::convert::TryInto;
use std::sync::Arc;
use std::rc::Rc;
type ITInterpreter = Interpreter<ITInstance, ITExport, WITFunction, WITMemory, WITMemoryView>;
#[derive(Clone)]
pub(super) struct ITModuleFunc {
interpreter: Arc<ITInterpreter>,
pub(super) arguments: Rc<Vec<IFunctionArg>>,
pub(super) output_types: Rc<Vec<IType>>,
}
#[derive(Clone)]
pub(super) struct Callable {
pub(super) it_instance: Arc<ITInstance>,
pub(super) it_module_func: ITModuleFunc,
}
impl Callable {
pub fn call(&mut self, args: &[IValue]) -> MResult<Vec<IValue>> {
use wasmer_it::interpreter::stack::Stackable;
let result = self
.it_module_func
.interpreter
.run(args, Arc::make_mut(&mut self.it_instance))?
.as_slice()
.to_owned();
Ok(result)
}
}
type ExportFunctions = HashMap<SharedString, Rc<Callable>>;
pub(crate) struct MModule {
// wasmer_instance is needed because WITInstance contains dynamic functions
// that internally keep pointer to it.
#[allow(unused)]
wasmer_instance: Box<WasmerInstance>,
// TODO: replace with dyn Trait
export_funcs: ExportFunctions,
// TODO: save refs instead copying of a record types HashMap.
/// Record types used in exported functions as arguments or return values.
export_record_types: MRecordTypes,
}
pub(crate) fn extract_it_from_bytes(wit_section_bytes: &[u8]) -> Result<Interfaces<'_>, String> {
match wasmer_it::decoders::binary::parse::<(&[u8], nom::error::ErrorKind)>(wit_section_bytes) {
Ok((remainder, it)) if remainder.is_empty() => Ok(it),
Ok(_) => Err("ITParserError::ITRemainderNotEmpty".to_string()),
Err(e) => Err(format!("ITParserError::CorruptedITSection({})", e)),
}
}
#[allow(unused)]
impl MModule {
pub(crate) fn new(name: &str, wit_section_bytes: &[u8]) -> MResult<Self> {
let it = extract_it_from_bytes(wit_section_bytes)?;
crate::misc::check_it_version(name, &it.version)?;
let mit = MITInterfaces::new(it);
let wasmer_instance = WasmerInstance::new(&mit, Rc::new(name.to_string()));
let it_instance = Arc::new(ITInstance::new(&wasmer_instance, &mit)?);
let (export_funcs, export_record_types) = Self::instantiate_exports(&it_instance, &mit)?;
Ok(Self {
wasmer_instance: Box::new(wasmer_instance),
export_funcs,
export_record_types,
})
}
pub(crate) fn call(
&mut self,
module_name: &str,
function_name: &str,
args: &[IValue],
) -> MResult<Vec<IValue>> {
self.export_funcs.get_mut(function_name).map_or_else(
|| {
Err(MError::NoSuchFunction(
module_name.to_string(),
function_name.to_string(),
))
},
|func| Rc::make_mut(func).call(args),
)
}
pub(crate) fn get_exports_signatures(&self) -> impl Iterator<Item = MFunctionSignature> + '_ {
self.export_funcs
.iter()
.map(|(func_name, func)| MFunctionSignature {
name: func_name.0.clone(),
arguments: func.it_module_func.arguments.clone(),
outputs: func.it_module_func.output_types.clone(),
})
}
pub(crate) fn export_record_types(&self) -> &MRecordTypes {
&self.export_record_types
}
pub(crate) fn export_record_type_by_id(&self, record_type: u64) -> Option<&Rc<IRecordType>> {
self.export_record_types.get(&record_type)
}
// TODO: change the cloning Callable behaviour after changes of Wasmer API
pub(super) fn get_callable(
&self,
module_name: &str,
function_name: &str,
) -> MResult<Rc<Callable>> {
match self.export_funcs.get(function_name) {
Some(func) => Ok(func.clone()),
None => Err(MError::NoSuchFunction(
module_name.to_string(),
function_name.to_string(),
)),
}
}
fn instantiate_exports(
it_instance: &Arc<ITInstance>,
mit: &MITInterfaces<'_>,
) -> MResult<(ExportFunctions, MRecordTypes)> {
let module_interface = marine_module_interface::it_interface::get_interface(mit)?;
let export_funcs = module_interface
.function_signatures
.into_iter()
.map(|sign| {
let adapter_instructions = mit.adapter_by_type_r(sign.adapter_function_type)?;
let interpreter: ITInterpreter = adapter_instructions.clone().try_into()?;
let it_module_func = ITModuleFunc {
interpreter: Arc::new(interpreter),
arguments: sign.arguments.clone(),
output_types: sign.outputs.clone(),
};
let shared_string = SharedString(sign.name);
let callable = Rc::new(Callable {
it_instance: it_instance.clone(),
it_module_func,
});
Ok((shared_string, callable))
})
.collect::<MResult<ExportFunctions>>()?;
Ok((export_funcs, module_interface.export_record_types))
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::marine_js::JsWasmMemoryProxy;
use it_memory_traits::{MemoryAccessError, SequentialWriter};
use it_memory_traits::SequentialReader;
use wasmer_it::interpreter::wasm;
use std::cell::Cell;
use std::rc::Rc;
pub(super) struct WITMemoryView {
module_name: Rc<String>,
}
impl WITMemoryView {
pub fn new(module_name: Rc<String>) -> Self {
Self { module_name }
}
fn check_bounds(
&self,
offset: usize,
size: usize,
memory_size: usize,
) -> Result<(), MemoryAccessError> {
if offset + size >= memory_size {
Err(MemoryAccessError::OutOfBounds {
offset,
size,
memory_size,
})
} else {
Ok(())
}
}
}
pub(super) struct JsSequentialReader {
offset: Cell<usize>,
data: Vec<u8>,
memory: JsWasmMemoryProxy,
start_offset: usize,
}
pub(super) struct JsSequentialWriter {
offset: usize,
current_offset: Cell<usize>,
memory: JsWasmMemoryProxy,
}
impl JsSequentialWriter {
pub fn new(offset: usize, memory: JsWasmMemoryProxy) -> Self {
Self {
offset,
current_offset: Cell::new(offset),
memory,
}
}
}
impl JsSequentialReader {
pub fn new(offset: usize, size: usize, memory: JsWasmMemoryProxy) -> Self {
let data = memory.get_range(offset, size);
Self {
offset: Cell::new(offset),
data,
memory,
start_offset: offset,
}
}
}
impl SequentialReader for JsSequentialReader {
fn read_byte(&self) -> u8 {
let offset = self.offset.get();
let result = self.memory.get(offset);
self.offset.set(offset + 1);
result
}
fn read_bytes<const COUNT: usize>(&self) -> [u8; COUNT] {
let offset = self.offset.get();
let start = offset - self.start_offset;
let mut result = [0u8; COUNT];
result.copy_from_slice(&self.data[start..start + COUNT]);
self.offset.set(offset + COUNT);
result
}
}
impl SequentialWriter for JsSequentialWriter {
fn start_offset(&self) -> usize {
self.offset
}
fn write_u8(&self, value: u8) {
let offset = self.current_offset.get();
self.memory.set(offset, value);
self.current_offset.set(offset + 1);
}
fn write_u32(&self, value: u32) {
let bytes = value.to_le_bytes();
self.write_bytes(&bytes);
}
fn write_bytes(&self, bytes: &[u8]) {
let offset = self.current_offset.get();
self.memory.set_range(offset, bytes);
self.current_offset.set(offset + bytes.len());
}
}
impl<'v> wasm::structures::SequentialMemoryView<'v> for WITMemoryView {
type SR = JsSequentialReader;
type SW = JsSequentialWriter;
fn sequential_writer(
&'v self,
offset: usize,
size: usize,
) -> Result<Self::SW, MemoryAccessError> {
let memory = JsWasmMemoryProxy::new(self.module_name.clone());
let memory_size = memory.len();
self.check_bounds(offset, size, memory_size)?;
Ok(JsSequentialWriter::new(offset, memory))
}
fn sequential_reader(
&'v self,
offset: usize,
size: usize,
) -> Result<Self::SR, MemoryAccessError> {
let memory = JsWasmMemoryProxy::new(self.module_name.clone());
let memory_size = memory.len();
self.check_bounds(offset, size, memory_size)?;
Ok(JsSequentialReader::new(offset, size, memory))
}
}
#[derive(Clone)]
pub(super) struct WITMemory {
module_name: Rc<String>,
}
impl WITMemory {
pub fn new(module_name: Rc<String>) -> Self {
Self { module_name }
}
}
impl wasm::structures::Memory<WITMemoryView> for WITMemory {
fn view(&self) -> WITMemoryView {
WITMemoryView::new(self.module_name.clone())
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod exports;
mod marine_module;
mod memory;
mod wit_function;
mod wit_instance;
pub mod type_converters;
pub use wit_instance::MRecordTypes;
pub use wasmer_it::IType;
pub use wasmer_it::IRecordType;
pub use wasmer_it::ast::FunctionArg as IFunctionArg;
pub use wasmer_it::IValue;
pub use wasmer_it::from_interface_values;
pub use wasmer_it::to_interface_value;
use serde::Serialize;
use serde::Deserialize;
use std::rc::Rc;
/// Represent a function type inside Marine module.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct MFunctionSignature {
pub name: Rc<String>,
pub arguments: Rc<Vec<IFunctionArg>>,
pub outputs: Rc<Vec<IType>>,
}
pub(crate) use marine_module::MModule;
pub(self) use crate::marine_js::WType;
pub(self) use crate::marine_js::WValue;
// types that often used together
pub(self) mod wit_prelude {
pub(super) use super::wit_instance::ITInstance;
pub(super) use super::exports::ITExport;
pub(super) use crate::MError;
pub(super) use super::wit_function::WITFunction;
pub(super) use super::memory::WITMemoryView;
pub(super) use super::memory::WITMemory;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// Contains converters of types and values between Wasmer and wasmer_interface_types.
use super::{WType, WValue, IType, IValue};
pub(crate) fn wtype_to_itype(ty: &WType) -> IType {
match ty {
WType::I32 => IType::I32,
WType::I64 => IType::I64,
WType::F32 => IType::F32,
WType::F64 => IType::F64,
WType::V128 => unimplemented!(),
}
}
pub(super) fn ival_to_wval(value: &IValue) -> WValue {
match value {
IValue::I32(v) => WValue::I32(*v),
IValue::I64(v) => WValue::I64(*v),
IValue::F32(v) => WValue::F32(*v),
IValue::F64(v) => WValue::F64(*v),
_ => {
unimplemented!()
}
}
}
pub(super) fn wval_to_ival(value: &WValue) -> IValue {
match value {
WValue::I32(v) => IValue::I32(*v),
WValue::I64(v) => IValue::I64(*v),
WValue::F32(v) => IValue::F32(*v),
WValue::F64(v) => IValue::F64(*v),
_ => unimplemented!(),
}
}
pub fn itypes_args_to_wtypes<'i>(itypes: impl Iterator<Item = &'i IType>) -> Vec<WType> {
itypes
.flat_map(|itype| match itype {
IType::F32 => vec![WType::F32],
IType::F64 => vec![WType::F64],
IType::I64 | IType::U64 | IType::S64 => vec![WType::I64],
IType::String | IType::Array(_) | IType::ByteArray => vec![WType::I32, WType::I32],
_ => vec![WType::I32],
})
.collect::<Vec<_>>()
}
pub fn itypes_output_to_wtypes<'i>(itypes: impl Iterator<Item = &'i IType>) -> Vec<WType> {
itypes
.flat_map(|itype| match itype {
IType::F32 => vec![WType::F32],
IType::F64 => vec![WType::F64],
IType::I64 | IType::U64 | IType::S64 => vec![WType::I64],
IType::String | IType::Array(_) | IType::ByteArray | IType::Record(_) => vec![],
_ => vec![WType::I32],
})
.collect::<Vec<_>>()
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::{IType, IFunctionArg, IValue, WValue};
use crate::MResult;
use crate::marine_js::DynFunc;
use wasmer_it::interpreter::wasm;
use std::rc::Rc;
#[derive(Clone)]
enum WITFunctionInner {
Export { func: Rc<DynFunc> },
}
/// Represents all import and export functions that could be called from IT context by call-core.
#[derive(Clone)]
pub(super) struct WITFunction {
name: String,
arguments: Rc<Vec<IFunctionArg>>,
outputs: Rc<Vec<IType>>,
inner: WITFunctionInner,
}
impl WITFunction {
/// Creates functions from a "usual" (not IT) module export.
pub(super) fn from_export(dyn_func: DynFunc, name: String) -> MResult<Self> {
use super::type_converters::wtype_to_itype;
let signature = dyn_func.signature();
let arguments = signature
.params()
.iter()
.map(|wtype| IFunctionArg {
// here it's considered as an anonymous arguments
name: String::new(),
ty: wtype_to_itype(wtype),
})
.collect::<Vec<_>>();
let outputs = signature
.returns()
.iter()
.map(wtype_to_itype)
.collect::<Vec<_>>();
let inner = WITFunctionInner::Export {
func: Rc::new(dyn_func),
};
let arguments = Rc::new(arguments);
let outputs = Rc::new(outputs);
Ok(Self {
name,
arguments,
outputs,
inner,
})
}
}
impl wasm::structures::LocalImport for WITFunction {
fn name(&self) -> &str {
self.name.as_str()
}
fn inputs_cardinality(&self) -> usize {
self.arguments.len()
}
fn outputs_cardinality(&self) -> usize {
self.outputs.len()
}
fn arguments(&self) -> &[IFunctionArg] {
&self.arguments
}
fn outputs(&self) -> &[IType] {
&self.outputs
}
fn call(&self, arguments: &[IValue]) -> std::result::Result<Vec<IValue>, ()> {
use super::type_converters::{ival_to_wval, wval_to_ival};
match &self.inner {
WITFunctionInner::Export { func, .. } => func
.as_ref()
.call(&arguments.iter().map(ival_to_wval).collect::<Vec<WValue>>())
.map(|result| result.iter().map(wval_to_ival).collect())
.map_err(|_| ()),
}
}
}

View File

@ -0,0 +1,143 @@
/*
* Copyright 2022 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::wit_prelude::*;
use super::IRecordType;
use crate::{MResult};
use crate::marine_js::{Instance as WasmerInstance};
use marine_it_interfaces::MITInterfaces;
use marine_it_interfaces::ITAstType;
use wasmer_it::interpreter::wasm;
use wasmer_it::interpreter::wasm::structures::{LocalImportIndex, Memory, TypedIndex};
use std::collections::HashMap;
use std::rc::Rc;
pub type MRecordTypes = HashMap<u64, Rc<IRecordType>>;
/// Contains all import and export functions that could be called from IT context by call-core.
#[derive(Clone)]
pub(super) struct ITInstance {
/// IT functions indexed by id.
funcs: HashMap<usize, WITFunction>,
/// IT memories.
memories: Vec<WITMemory>,
/// All record types that instance contains.
record_types_by_id: MRecordTypes,
}
impl ITInstance {
pub(super) fn new(wasmer_instance: &WasmerInstance, wit: &MITInterfaces<'_>) -> MResult<Self> {
let exports = Self::extract_raw_exports(wasmer_instance, wit)?;
let memories = Self::extract_memories(wasmer_instance);
let funcs = exports;
let record_types_by_id = Self::extract_record_types(wit);
Ok(Self {
funcs,
memories,
record_types_by_id,
})
}
fn extract_raw_exports(
wasmer_instance: &WasmerInstance,
it: &MITInterfaces<'_>,
) -> MResult<HashMap<usize, WITFunction>> {
let module_exports = &wasmer_instance.exports;
it.exports()
.enumerate()
.map(|(export_id, export)| {
let export_func = module_exports.get(export.name)?;
Ok((
export_id,
WITFunction::from_export(export_func, export.name.to_string())?,
))
})
.collect()
}
fn extract_memories(wasmer_instance: &WasmerInstance) -> Vec<WITMemory> {
use crate::marine_js::Export::Memory;
let memories = wasmer_instance
.exports()
.filter_map(|(_, export)| match export {
Memory => Some(WITMemory::new(wasmer_instance.module_name.clone())),
_ => None,
})
.collect::<Vec<_>>();
memories
}
fn extract_record_types(wit: &MITInterfaces<'_>) -> MRecordTypes {
let (record_types_by_id, _) = wit.types().fold(
(HashMap::new(), 0u64),
|(mut record_types_by_id, id), ty| {
match ty {
ITAstType::Record(record_type) => {
record_types_by_id.insert(id, record_type.clone());
}
ITAstType::Function { .. } => {}
};
(record_types_by_id, id + 1)
},
);
record_types_by_id
}
}
impl wasm::structures::Instance<ITExport, WITFunction, WITMemory, WITMemoryView> for ITInstance {
fn export(&self, _export_name: &str) -> Option<&ITExport> {
// exports aren't used in this version of IT
None
}
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&WITFunction> {
self.funcs.get(&index.index())
}
fn memory(&self, index: usize) -> Option<&WITMemory> {
if index >= self.memories.len() {
None
} else {
Some(&self.memories[index])
}
}
fn memory_view(&self, index: usize) -> Option<WITMemoryView> {
if index >= self.memories.len() {
return None;
}
let memory = &self.memories[index];
Some(memory.view())
}
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>> {
self.record_types_by_id.get(&index)
}
}