mirror of
https://github.com/fluencelabs/marine.git
synced 2025-06-24 04:01:37 +00:00
Add js version of runtime that supports interface types and runs in browser (#137)
This commit is contained in:
@ -1,4 +1,7 @@
|
||||
version: 2.1
|
||||
orbs:
|
||||
node: circleci/node@5.0.0
|
||||
|
||||
jobs:
|
||||
marine:
|
||||
docker:
|
||||
@ -12,6 +15,10 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- marine04-{{ checksum "Cargo.lock" }}
|
||||
|
||||
- node/install:
|
||||
node-version: '16.14'
|
||||
|
||||
- run: |
|
||||
rustup toolchain install 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 target add wasm32-wasi
|
||||
|
||||
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
cargo install --path tools/cli
|
||||
|
||||
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
|
||||
|
||||
(
|
||||
cd web-runtime
|
||||
./build.sh
|
||||
cd npm-package
|
||||
npm i
|
||||
npm run build
|
||||
)
|
||||
(cd ./examples; ./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 clippy
|
||||
|
||||
(
|
||||
cd web-runtime/npm-package
|
||||
npm run test
|
||||
)
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.cargo
|
||||
|
144
.github/workflows/publish_npm_dev.yml
vendored
Normal file
144
.github/workflows/publish_npm_dev.yml
vendored
Normal 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 }}
|
120
.github/workflows/publish_npm_release.yml
vendored
Normal file
120
.github/workflows/publish_npm_release.yml
vendored
Normal 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
365
Cargo.lock
generated
@ -92,9 +92,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
@ -218,9 +218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -243,7 +243,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"reqwest 0.11.9",
|
||||
"semver 1.0.4",
|
||||
"semver 1.0.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -291,6 +291,16 @@ version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
@ -306,9 +316,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -403,9 +413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.6"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
|
||||
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
@ -416,9 +426,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
|
||||
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
@ -776,11 +786,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fluence-app-service"
|
||||
version = "0.13.0"
|
||||
version = "0.14.0"
|
||||
dependencies = [
|
||||
"fluence-faas 0.12.0",
|
||||
"fluence-faas 0.13.0",
|
||||
"log",
|
||||
"maplit",
|
||||
"marine-min-it-version",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@ -797,7 +808,7 @@ dependencies = [
|
||||
"cmd_lib",
|
||||
"itertools 0.9.0",
|
||||
"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-main",
|
||||
"marine-runtime 0.7.2",
|
||||
@ -808,7 +819,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.20.2",
|
||||
"wasmer-runtime-core-fl",
|
||||
"wasmer-runtime-fl",
|
||||
"wasmer-wasi-fl",
|
||||
@ -816,17 +827,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fluence-faas"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"cmd_lib",
|
||||
"env_logger 0.7.1",
|
||||
"itertools 0.9.0",
|
||||
"log",
|
||||
"marine-module-interface 0.1.6",
|
||||
"marine-module-interface 0.2.0",
|
||||
"marine-rs-sdk",
|
||||
"marine-rs-sdk-main",
|
||||
"marine-runtime 0.10.0",
|
||||
"marine-runtime 0.11.0",
|
||||
"marine-utils 0.4.0",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
@ -837,7 +848,7 @@ dependencies = [
|
||||
"serde_with",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.21.1",
|
||||
"wasmer-runtime-core-fl",
|
||||
"wasmer-runtime-fl",
|
||||
"wasmer-wasi-fl",
|
||||
@ -905,42 +916,42 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
|
||||
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
|
||||
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
|
||||
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
@ -1072,7 +1083,7 @@ dependencies = [
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio 1.16.1",
|
||||
"tokio 1.17.0",
|
||||
"tokio-util 0.6.9",
|
||||
"tracing",
|
||||
]
|
||||
@ -1141,9 +1152,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.5.1"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
|
||||
checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
@ -1192,9 +1203,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.16"
|
||||
version = "0.14.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
|
||||
checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures-channel",
|
||||
@ -1205,10 +1216,10 @@ dependencies = [
|
||||
"http-body 0.4.4",
|
||||
"httparse",
|
||||
"httpdate 1.0.2",
|
||||
"itoa 0.4.8",
|
||||
"itoa 1.0.1",
|
||||
"pin-project-lite 0.2.8",
|
||||
"socket2 0.4.4",
|
||||
"tokio 1.16.1",
|
||||
"tokio 1.17.0",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
@ -1234,9 +1245,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"hyper 0.14.16",
|
||||
"hyper 0.14.17",
|
||||
"native-tls",
|
||||
"tokio 1.16.1",
|
||||
"tokio 1.17.0",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
@ -1336,6 +1347,28 @@ dependencies = [
|
||||
"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]]
|
||||
name = "it-to-bytes"
|
||||
version = "0.1.0"
|
||||
@ -1418,9 +1451,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.116"
|
||||
version = "0.2.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74"
|
||||
checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94"
|
||||
|
||||
[[package]]
|
||||
name = "local_storage"
|
||||
@ -1457,7 +1490,7 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
|
||||
[[package]]
|
||||
name = "marine"
|
||||
version = "0.6.13"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -1465,8 +1498,8 @@ dependencies = [
|
||||
"check-latest",
|
||||
"clap",
|
||||
"exitfailure",
|
||||
"marine-it-generator 0.5.6",
|
||||
"marine-it-parser 0.6.8",
|
||||
"marine-it-generator 0.6.0",
|
||||
"marine-it-parser 0.7.0",
|
||||
"marine-module-info-parser 0.2.2",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
@ -1488,9 +1521,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "marine-it-generator"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "890b228b9151e9dff213501986f564445a2f9ca5a706088b5d900f5ecf67f7e7"
|
||||
dependencies = [
|
||||
"cargo_toml",
|
||||
"it-lilo",
|
||||
"it-lilo 0.1.0",
|
||||
"marine-it-parser 0.6.8",
|
||||
"marine-macro-impl",
|
||||
"once_cell",
|
||||
@ -1498,33 +1533,23 @@ dependencies = [
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"walrus",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.20.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marine-it-generator"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "890b228b9151e9dff213501986f564445a2f9ca5a706088b5d900f5ecf67f7e7"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"cargo_toml",
|
||||
"it-lilo",
|
||||
"marine-it-parser 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"it-lilo 0.2.0",
|
||||
"marine-it-parser 0.7.0",
|
||||
"marine-macro-impl",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"walrus",
|
||||
"wasmer-interface-types-fl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marine-it-interfaces"
|
||||
version = "0.4.1"
|
||||
dependencies = [
|
||||
"multimap",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1534,24 +1559,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42e229143e72ba20e754de4766ff0d02e0cf176001f7471593f82b16c72dc26d"
|
||||
dependencies = [
|
||||
"multimap",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.20.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marine-it-parser"
|
||||
version = "0.6.8"
|
||||
name = "marine-it-interfaces"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.10.3",
|
||||
"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",
|
||||
"multimap",
|
||||
"wasmer-interface-types-fl 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1562,14 +1578,31 @@ checksum = "edd97bd85072fc540763769be153a7c8ee83391e668b37ef96d6c48decec2cd5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.10.3",
|
||||
"marine-it-interfaces 0.4.1 (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-it-interfaces 0.4.1",
|
||||
"marine-module-interface 0.1.6",
|
||||
"nom",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"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",
|
||||
]
|
||||
|
||||
@ -1597,6 +1630,14 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marine-min-it-version"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"semver 0.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marine-module-info-parser"
|
||||
version = "0.2.2"
|
||||
@ -1630,6 +1671,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "marine-module-interface"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06bc36ef268bf7436916f1fa9b0c84104692a717ea5eef3c90b9f25c3407f6b7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.10.3",
|
||||
@ -1639,26 +1682,23 @@ dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
"walrus",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.20.2",
|
||||
"wasmer-runtime-core-fl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marine-module-interface"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06bc36ef268bf7436916f1fa9b0c84104692a717ea5eef3c90b9f25c3407f6b7"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"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",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"walrus",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-runtime-core-fl",
|
||||
"wasmer-interface-types-fl 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1706,13 +1746,13 @@ checksum = "983262d394c59d4321b141e303eb55015bc412f319d54bbad7f253e4583253b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"boolinator",
|
||||
"it-lilo",
|
||||
"it-lilo 0.1.0",
|
||||
"log",
|
||||
"marine-it-generator 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"marine-it-interfaces 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"marine-it-parser 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"marine-it-generator 0.5.6",
|
||||
"marine-it-interfaces 0.4.1",
|
||||
"marine-it-parser 0.6.8",
|
||||
"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",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@ -1722,7 +1762,7 @@ dependencies = [
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.20.2",
|
||||
"wasmer-runtime-core-fl",
|
||||
"wasmer-runtime-fl",
|
||||
"wasmer-wasi-fl",
|
||||
@ -1730,19 +1770,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "marine-runtime"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"boolinator",
|
||||
"bytes 0.5.6",
|
||||
"bytesize",
|
||||
"it-lilo",
|
||||
"it-lilo 0.2.0",
|
||||
"it-memory-traits",
|
||||
"log",
|
||||
"marine-it-generator 0.5.6",
|
||||
"marine-it-interfaces 0.4.1",
|
||||
"marine-it-parser 0.6.8",
|
||||
"marine-it-generator 0.6.0",
|
||||
"marine-it-interfaces 0.5.0",
|
||||
"marine-it-parser 0.7.0",
|
||||
"marine-min-it-version",
|
||||
"marine-module-info-parser 0.2.2",
|
||||
"marine-module-interface 0.1.6",
|
||||
"marine-module-interface 0.2.0",
|
||||
"marine-utils 0.4.0",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@ -1754,7 +1796,7 @@ dependencies = [
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio 0.2.25",
|
||||
"wasmer-interface-types-fl",
|
||||
"wasmer-interface-types-fl 0.21.1",
|
||||
"wasmer-runtime-core-fl",
|
||||
"wasmer-runtime-fl",
|
||||
"wasmer-wasi-fl",
|
||||
@ -1791,7 +1833,7 @@ dependencies = [
|
||||
"darling 0.12.4",
|
||||
"fluence-app-service 0.10.2",
|
||||
"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-macro2",
|
||||
"quote",
|
||||
@ -1820,6 +1862,41 @@ checksum = "8dc5838acba84ce4d802d672afd0814fae0ae7098021ae5b06d975e70d09f812"
|
||||
name = "marine-utils"
|
||||
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]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
@ -1859,9 +1936,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.3"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
|
||||
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
@ -1898,9 +1975,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.14"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
|
||||
checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@ -1932,13 +2009,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mrepl"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"check-latest",
|
||||
"clap",
|
||||
"env_logger 0.7.1",
|
||||
"fluence-app-service 0.13.0",
|
||||
"fluence-app-service 0.14.0",
|
||||
"itertools 0.9.0",
|
||||
"log",
|
||||
"marine-rs-sdk-main",
|
||||
@ -2048,9 +2125,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
@ -2140,9 +2217,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
||||
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
@ -2537,7 +2614,7 @@ dependencies = [
|
||||
"h2 0.3.11",
|
||||
"http",
|
||||
"http-body 0.4.4",
|
||||
"hyper 0.14.16",
|
||||
"hyper 0.14.17",
|
||||
"hyper-tls 0.5.0",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
@ -2550,7 +2627,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio 1.16.1",
|
||||
"tokio 1.17.0",
|
||||
"tokio-native-tls",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@ -2658,9 +2735,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.6.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac"
|
||||
checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
@ -2671,9 +2748,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.6.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c"
|
||||
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -2699,9 +2776,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||
checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -2762,9 +2839,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.78"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085"
|
||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
||||
dependencies = [
|
||||
"itoa 1.0.1",
|
||||
"ryu",
|
||||
@ -2785,9 +2862,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "1.11.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3"
|
||||
checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
"serde",
|
||||
@ -3075,16 +3152,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.16.1"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a"
|
||||
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio 0.7.14",
|
||||
"mio 0.8.0",
|
||||
"num_cpus",
|
||||
"pin-project-lite 0.2.8",
|
||||
"socket2 0.4.4",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
@ -3106,7 +3184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio 1.16.1",
|
||||
"tokio 1.17.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3144,7 +3222,7 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite 0.2.8",
|
||||
"tokio 1.16.1",
|
||||
"tokio 1.17.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3164,9 +3242,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.29"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
|
||||
checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"log",
|
||||
@ -3176,9 +3254,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.21"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
|
||||
checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
@ -3275,9 +3353,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
@ -3575,7 +3653,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14ba3b5a07989987994b96bf5cc7ac2947005f9ff6123d71b7064232f07d28fa"
|
||||
dependencies = [
|
||||
"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",
|
||||
"itertools 0.10.3",
|
||||
"log",
|
||||
|
@ -3,6 +3,7 @@ members = [
|
||||
"crates/it-generator",
|
||||
"crates/it-interfaces",
|
||||
"crates/it-parser",
|
||||
"crates/min-it-version",
|
||||
"crates/module-info-parser",
|
||||
"crates/module-interface",
|
||||
"crates/utils",
|
||||
@ -27,6 +28,7 @@ members = [
|
||||
"fluence-faas/tests/wasm_tests/arrays_passing",
|
||||
"fluence-faas/tests/wasm_tests/records_passing",
|
||||
"runtime",
|
||||
"web-runtime",
|
||||
"tools/cli",
|
||||
"tools/repl",
|
||||
]
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "marine-it-generator"
|
||||
description = "Fluence Marine interface types generator"
|
||||
version = "0.5.6"
|
||||
version = "0.6.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
@ -11,11 +11,11 @@ name = "marine_it_generator"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[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"
|
||||
|
||||
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.2" }
|
||||
it-lilo = "0.1.0"
|
||||
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
|
||||
it-lilo = "0.2.0"
|
||||
|
||||
thiserror = "1.0.24"
|
||||
walrus = "0.18.0"
|
||||
|
@ -152,8 +152,7 @@ pub(crate) fn generate_raw_args(signature: &FnSignature) -> Rc<Vec<IFunctionArg>
|
||||
let raw_inputs = signature
|
||||
.arguments
|
||||
.iter()
|
||||
.map(to_raw_input_types)
|
||||
.flatten()
|
||||
.flat_map(to_raw_input_types)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Rc::new(raw_inputs)
|
||||
@ -163,13 +162,12 @@ pub(crate) fn generate_raw_output_type(signature: &FnSignature) -> Rc<Vec<IType>
|
||||
let raw_outputs = signature
|
||||
.output_types
|
||||
.iter()
|
||||
.map(|ty| {
|
||||
.flat_map(|ty| {
|
||||
to_raw_output_type(ty)
|
||||
.iter()
|
||||
.map(wtype_to_itype)
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Rc::new(raw_outputs)
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "marine-it-interfaces"
|
||||
description = "Fluence Marine interface types helper crate"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
@ -11,5 +11,5 @@ name = "marine_it_interfaces"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[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"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "marine-it-parser"
|
||||
description = "Fluence Marine interface types parser"
|
||||
version = "0.6.8"
|
||||
version = "0.7.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
@ -11,13 +11,13 @@ name = "marine_it_parser"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
marine-it-interfaces = { path = "../it-interfaces", version = "0.4.1" }
|
||||
marine-module-interface = { path = "../module-interface", version = "0.1.6" }
|
||||
marine-it-interfaces = { path = "../it-interfaces", version = "0.5.0" }
|
||||
marine-module-interface = { path = "../module-interface", version = "0.2.0" }
|
||||
|
||||
anyhow = "1.0.31"
|
||||
walrus = "0.18.0"
|
||||
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"
|
||||
|
||||
itertools = "0.10.0"
|
||||
|
15
crates/min-it-version/Cargo.toml
Normal file
15
crates/min-it-version/Cargo.toml
Normal 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"
|
50
crates/min-it-version/src/lib.rs
Normal file
50
crates/min-it-version/src/lib.rs
Normal 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)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "marine-module-interface"
|
||||
description = "Fluence Marine module interface"
|
||||
version = "0.1.6"
|
||||
version = "0.2.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
@ -11,12 +11,11 @@ name = "marine_module_interface"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[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"
|
||||
walrus = "0.18.0"
|
||||
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"
|
||||
|
||||
itertools = "0.10.0"
|
||||
|
@ -41,7 +41,7 @@ pub fn get_export_funcs_descriptors<'i>(
|
||||
mit.exports_by_type(*core_function_type)
|
||||
.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
|
||||
.iter()
|
||||
.map(move |name| ITExportFuncDescriptor {
|
||||
@ -49,7 +49,6 @@ pub fn get_export_funcs_descriptors<'i>(
|
||||
name,
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
[package]
|
||||
name = "fluence-app-service"
|
||||
description = "Fluence Application Service"
|
||||
version = "0.13.0"
|
||||
version = "0.14.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[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"
|
||||
log = "0.4.8"
|
||||
|
@ -64,8 +64,8 @@ pub use fluence_faas::ModuleMemoryStat;
|
||||
pub use fluence_faas::MemoryStats;
|
||||
pub use fluence_faas::ne_vec;
|
||||
|
||||
pub use fluence_faas::min_sdk_version;
|
||||
pub use fluence_faas::min_it_version;
|
||||
pub use marine_min_it_version::min_sdk_version;
|
||||
pub use marine_min_it_version::min_it_version;
|
||||
|
||||
pub use fluence_faas::CallParameters;
|
||||
pub use fluence_faas::SecurityTetraplet;
|
||||
|
@ -1,14 +1,14 @@
|
||||
[package]
|
||||
name = "fluence-faas"
|
||||
description = "Fluence FaaS"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
marine-runtime = { path = "../runtime", version = "0.10.0" }
|
||||
marine-module-interface = { path = "../crates/module-interface", version = "0.1.6" }
|
||||
marine-runtime = { path = "../runtime", version = "0.11.0" }
|
||||
marine-module-interface = { path = "../crates/module-interface", version = "0.2.0" }
|
||||
marine-utils = { path = "../crates/utils", version = "0.4.0" }
|
||||
marine-rs-sdk-main = { 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
|
||||
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-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"
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
|
@ -65,8 +65,6 @@ pub use marine::HostImportError;
|
||||
pub use marine::to_interface_value;
|
||||
pub use marine::from_interface_values;
|
||||
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;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "marine-runtime"
|
||||
description = "Marine is the Fluence Compute Runtime"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
authors = ["Fluence Labs"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
@ -12,17 +12,19 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
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-parser = { path = "../crates/it-parser", version = "0.6.8" }
|
||||
marine-it-generator = { path = "../crates/it-generator", version = "0.5.6" }
|
||||
marine-module-interface = { path = "../crates/module-interface", version = "0.1.6" }
|
||||
marine-it-interfaces = { path = "../crates/it-interfaces", version = "0.5.0" }
|
||||
marine-it-parser = { path = "../crates/it-parser", version = "0.7.0" }
|
||||
marine-it-generator = { path = "../crates/it-generator", version = "0.6.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"}
|
||||
|
||||
wasmer-runtime = { package = "wasmer-runtime-fl", version = "=0.17.1" }
|
||||
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
||||
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" }
|
||||
it-lilo = "0.1.0"
|
||||
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.21.1" }
|
||||
it-lilo = "0.2.0"
|
||||
it-memory-traits = "0.1.0"
|
||||
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.1" }
|
||||
bytesize = "1.1.0"
|
||||
|
||||
|
@ -51,9 +51,11 @@ impl Marine {
|
||||
func_name: FN,
|
||||
arguments: &[IValue],
|
||||
) -> MResult<Vec<IValue>> {
|
||||
self.modules.get_mut(module_name.as_ref()).map_or_else(
|
||||
|| Err(MError::NoSuchModule(module_name.as_ref().to_string())),
|
||||
|module| module.call(module_name.as_ref(), func_name.as_ref(), arguments),
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ use crate::MRecordTypes;
|
||||
use crate::init_wasm_func_once;
|
||||
use crate::call_wasm_func;
|
||||
use crate::HostImportDescriptor;
|
||||
use crate::module::wit_prelude::WITMemoryView;
|
||||
|
||||
use wasmer_core::Func;
|
||||
use wasmer_core::vm::Ctx;
|
||||
@ -37,7 +38,6 @@ use it_lilo::lowerer::ILowerer;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub(crate) fn create_host_import_func(
|
||||
descriptor: HostImportDescriptor,
|
||||
@ -63,14 +63,14 @@ pub(crate) fn create_host_import_func(
|
||||
let raw_output = itypes_output_to_wtypes(&output_type_to_types(output_type));
|
||||
|
||||
let func = move |ctx: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
|
||||
let result = {
|
||||
let memory_index = 0;
|
||||
let view = ctx.memory(memory_index).view::<u8>();
|
||||
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, &li_helper);
|
||||
let lifter = ILifter::new(memory_view, &li_helper);
|
||||
|
||||
let result = match wvalues_to_ivalues(&lifter, inputs, &argument_types) {
|
||||
match wvalues_to_ivalues(&lifter, inputs, &argument_types) {
|
||||
Ok(ivalues) => host_exported_func(ctx, ivalues),
|
||||
Err(e) => {
|
||||
log::error!("error occurred while lifting values in host import: {}", e);
|
||||
@ -78,12 +78,16 @@ pub(crate) fn create_host_import_func(
|
||||
.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);
|
||||
|
||||
let lo_helper = LoHelper::new(ctx, &allocate_func);
|
||||
let t = ILowerer::new(&lo_helper)
|
||||
let memory_index = 0;
|
||||
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)
|
||||
.and_then(|lowerer| ivalue_to_wvalues(&lowerer, result));
|
||||
|
||||
|
@ -43,8 +43,8 @@ macro_rules! simple_wvalue_to_ivalue {
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) fn wvalues_to_ivalues<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
pub(crate) fn wvalues_to_ivalues<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
wvalues: &[WValue],
|
||||
itypes: &[IType],
|
||||
) -> HostImportResult<Vec<IValue>> {
|
||||
|
@ -19,38 +19,20 @@ use crate::call_wasm_func;
|
||||
|
||||
use it_lilo::traits::Allocatable;
|
||||
use it_lilo::traits::AllocatableError;
|
||||
use wasmer_core::vm::Ctx;
|
||||
use wasmer_core::vm::LocalMemory;
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
pub(crate) struct LoHelper<'c> {
|
||||
ctx: &'c Ctx,
|
||||
allocate_func: &'c AllocateFunc,
|
||||
}
|
||||
|
||||
impl<'c> LoHelper<'c> {
|
||||
pub(crate) fn new(ctx: &'c Ctx, allocate_func: &'c AllocateFunc) -> Self {
|
||||
Self { ctx, allocate_func }
|
||||
pub(crate) fn new(allocate_func: &'c AllocateFunc) -> Self {
|
||||
Self { allocate_func }
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocatable for LoHelper<'_> {
|
||||
impl<'s> Allocatable for LoHelper<'s> {
|
||||
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError> {
|
||||
let offset = call_wasm_func!(self.allocate_func, size as _, type_tag 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)
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ use crate::IValue;
|
||||
|
||||
use it_lilo::lowerer::*;
|
||||
use it_lilo::traits::Allocatable;
|
||||
use it_memory_traits::SequentialMemoryView;
|
||||
|
||||
pub(crate) fn ivalue_to_wvalues<A: Allocatable>(
|
||||
lowerer: &ILowerer<'_, A>,
|
||||
pub(crate) fn ivalue_to_wvalues<A: Allocatable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lowerer: &ILowerer<'_, A, MV>,
|
||||
ivalue: Option<IValue>,
|
||||
) -> HostImportResult<Vec<WValue>> {
|
||||
let result = match ivalue {
|
||||
|
@ -99,29 +99,27 @@ where
|
||||
pub(super) fn itypes_args_to_wtypes(itypes: &[IType]) -> Vec<WType> {
|
||||
itypes
|
||||
.iter()
|
||||
.map(|itype| match itype {
|
||||
.flat_map(|itype| match itype {
|
||||
IType::F32 => vec![WType::F32],
|
||||
IType::F64 => vec![WType::F64],
|
||||
IType::I64 | IType::U64 => vec![WType::I64],
|
||||
IType::String | IType::Array(_) => vec![WType::I32, WType::I32],
|
||||
_ => vec![WType::I32],
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn itypes_output_to_wtypes(itypes: &[IType]) -> Vec<WType> {
|
||||
itypes
|
||||
.iter()
|
||||
.map(|itype| match itype {
|
||||
.flat_map(|itype| match itype {
|
||||
IType::F32 => vec![WType::F32],
|
||||
IType::F64 => vec![WType::F64],
|
||||
IType::I64 | IType::U64 => vec![WType::I64],
|
||||
IType::String | IType::Array(_) | IType::Record(_) => vec![],
|
||||
_ => vec![WType::I32],
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[macro_export] // https://github.com/rust-lang/rust/issues/57966#issuecomment-461077932
|
||||
|
@ -59,27 +59,3 @@ pub mod ne_vec {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ use super::PrepareResult;
|
||||
use super::PrepareError;
|
||||
|
||||
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;
|
||||
|
||||
@ -31,7 +33,7 @@ pub(crate) fn check_sdk_version(
|
||||
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 {
|
||||
return Err(PrepareError::IncompatibleSDKVersions {
|
||||
module_name: name.into(),
|
||||
@ -47,7 +49,7 @@ pub(crate) fn check_it_version(
|
||||
name: impl Into<String>,
|
||||
it_version: &semver::Version,
|
||||
) -> PrepareResult<()> {
|
||||
let required_version = crate::min_it_version();
|
||||
let required_version = min_it_version();
|
||||
if it_version < required_version {
|
||||
return Err(PrepareError::IncompatibleITVersions {
|
||||
module_name: name.into(),
|
||||
|
@ -369,12 +369,11 @@ impl MModule {
|
||||
wit.imports_by_type(*core_function_type)
|
||||
.map(|import| (adapter_function_type, import))
|
||||
})
|
||||
.map(|(adapter_function_type, import_function_names)| {
|
||||
.flat_map(|(adapter_function_type, import_function_names)| {
|
||||
import_function_names
|
||||
.iter()
|
||||
.map(move |import_function_name| (*adapter_function_type, import_function_name))
|
||||
})
|
||||
.flatten()
|
||||
.map(|(adapter_function_type, (import_namespace, import_name))| {
|
||||
let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?;
|
||||
let wit_type = wit.type_by_idx_r(adapter_function_type)?;
|
||||
|
@ -14,20 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::ops::Deref;
|
||||
use wasmer_it::interpreter::wasm;
|
||||
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>);
|
||||
impl<'a> std::ops::Deref for WITMemoryView<'a> {
|
||||
type Target = [std::cell::Cell<u8>];
|
||||
use crate::module::WasmerSequentialWriter;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
use it_memory_traits::{MemoryAccessError};
|
||||
|
||||
pub(crate) struct WITMemoryView<'a>(pub(crate) MemoryView<'a, u8>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) struct WITMemory(pub(super) Memory);
|
||||
pub(crate) struct WITMemory(pub(super) Memory);
|
||||
impl std::ops::Deref for WITMemory {
|
||||
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 {
|
||||
fn view(&self) -> WITMemoryView<'a> {
|
||||
use wasmer_core::vm::LocalMemory;
|
||||
|
||||
let LocalMemory { base, .. } = unsafe { *self.0.vm_local_memory() };
|
||||
let length = self.0.size().bytes().0 / std::mem::size_of::<u8>();
|
||||
|
||||
|
137
runtime/src/module/memory_access.rs
Normal file
137
runtime/src/module/memory_access.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
mod exports;
|
||||
mod marine_module;
|
||||
mod memory;
|
||||
mod memory_access;
|
||||
mod wit_function;
|
||||
mod wit_instance;
|
||||
mod type_converters;
|
||||
@ -29,6 +30,9 @@ pub use wasmer_it::IValue;
|
||||
pub use wasmer_it::from_interface_values;
|
||||
pub use wasmer_it::to_interface_value;
|
||||
|
||||
pub(crate) use memory_access::WasmerSequentialWriter;
|
||||
pub(crate) use memory_access::WasmerSequentialReader;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
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;
|
||||
|
||||
// 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::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;
|
||||
|
||||
pub(crate) use super::memory::WITMemoryView;
|
||||
pub(crate) use super::memory::WITMemory;
|
||||
}
|
||||
|
@ -22,11 +22,10 @@ use crate::MResult;
|
||||
use marine_it_interfaces::MITInterfaces;
|
||||
use marine_it_interfaces::ITAstType;
|
||||
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 std::collections::HashMap;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
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
|
||||
{
|
||||
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>]> {
|
||||
use wasmer_core::vm::LocalMemory;
|
||||
|
||||
fn memory_view(&self, index: usize) -> Option<WITMemoryView<'static>> {
|
||||
if index >= self.memories.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let memory = &self.memories[index];
|
||||
let LocalMemory { base, .. } = unsafe { *memory.0.vm_local_memory() };
|
||||
let length = memory.0.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();
|
||||
|
||||
Some(slice)
|
||||
let view: WITMemoryView<'static> = memory.view();
|
||||
Some(view)
|
||||
}
|
||||
|
||||
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "marine"
|
||||
description = "Fluence Marine command line tool"
|
||||
version = "0.6.13"
|
||||
version = "0.7.0"
|
||||
authors = ["Fluence Labs"]
|
||||
repository = "https://github.com/fluencelabs/marine/tools/cli"
|
||||
license = "Apache-2.0"
|
||||
@ -12,8 +12,8 @@ name = "marine"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
marine-it-generator = { path = "../../crates/it-generator", version = "0.5.6" }
|
||||
marine-it-parser = { path = "../../crates/it-parser", version = "0.6.8" }
|
||||
marine-it-generator = { path = "../../crates/it-generator", version = "0.6.0" }
|
||||
marine-it-parser = { path = "../../crates/it-parser", version = "0.7.0" }
|
||||
marine-module-info-parser = { path = "../../crates/module-info-parser", version = "0.2.2" }
|
||||
|
||||
semver = "0.11.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "mrepl"
|
||||
description = "Fluence Marine REPL intended for testing purposes"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
authors = ["Fluence Labs"]
|
||||
repository = "https://github.com/fluencelabs/marine/tools/repl"
|
||||
license = "Apache-2.0"
|
||||
@ -12,7 +12,7 @@ name = "mrepl"
|
||||
path = "src/main.rs"
|
||||
|
||||
[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"] }
|
||||
|
||||
anyhow = "1.0.31"
|
||||
|
@ -25,6 +25,7 @@ use fluence_app_service::FaaSModuleConfig;
|
||||
use fluence_app_service::TomlAppServiceConfig;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value as JValue;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
@ -56,7 +57,7 @@ struct CallModuleArguments<'args> {
|
||||
module_name: &'args str,
|
||||
func_name: &'args str,
|
||||
show_result_arg: bool,
|
||||
args: serde_json::Value,
|
||||
args: JValue,
|
||||
call_parameters: CallParameters,
|
||||
}
|
||||
|
||||
@ -258,7 +259,7 @@ fn parse_call_module_arguments<'args>(
|
||||
let module_arg: String = args.join(" ");
|
||||
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,
|
||||
Err(e) => return Err(format!("invalid args: {}", e)),
|
||||
};
|
||||
|
43
web-runtime/Cargo.toml
Normal file
43
web-runtime/Cargo.toml
Normal 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
8
web-runtime/build.sh
Executable 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
124
web-runtime/marine-js.js
Normal 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
6
web-runtime/npm-package/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
dist
|
||||
node_modules
|
||||
*.tgz
|
||||
|
||||
# auto-generated files
|
||||
src/*.wasm
|
8
web-runtime/npm-package/.prettierrc.js
Normal file
8
web-runtime/npm-package/.prettierrc.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
semi: true,
|
||||
trailingComma: 'all',
|
||||
singleQuote: true,
|
||||
printWidth: 120,
|
||||
tabWidth: 4,
|
||||
useTabs: false,
|
||||
};
|
4
web-runtime/npm-package/jest.config.js
Normal file
4
web-runtime/npm-package/jest.config.js
Normal file
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
testPathIgnorePatterns: ['src'],
|
||||
};
|
7461
web-runtime/npm-package/package-lock.json
generated
Normal file
7461
web-runtime/npm-package/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
web-runtime/npm-package/package.json
Normal file
32
web-runtime/npm-package/package.json
Normal 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"
|
||||
}
|
||||
}
|
95
web-runtime/npm-package/src/__test__/test.spec.ts
Normal file
95
web-runtime/npm-package/src/__test__/test.spec.ts
Normal 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: '',
|
||||
});
|
||||
});
|
||||
});
|
49
web-runtime/npm-package/src/copyMarine.ts
Normal file
49
web-runtime/npm-package/src/copyMarine.ts
Normal 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!');
|
18
web-runtime/npm-package/src/index.ts
Normal file
18
web-runtime/npm-package/src/index.ts
Normal 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';
|
292
web-runtime/npm-package/src/marine_web_runtime.js
Normal file
292
web-runtime/npm-package/src/marine_web_runtime.js
Normal 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,
|
||||
};
|
||||
}
|
26
web-runtime/npm-package/tsconfig.json
Normal file
26
web-runtime/npm-package/tsconfig.json
Normal 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
136
web-runtime/src/api.rs
Normal 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
145
web-runtime/src/engine.rs
Normal 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
95
web-runtime/src/errors.rs
Normal 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())
|
||||
}
|
||||
}
|
63
web-runtime/src/faas/errors.rs
Normal file
63
web-runtime/src/faas/errors.rs
Normal 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!()
|
||||
}
|
||||
}
|
177
web-runtime/src/faas/faas.rs
Normal file
177
web-runtime/src/faas/faas.rs
Normal 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))
|
||||
}
|
||||
}
|
109
web-runtime/src/faas/faas_interface.rs
Normal file
109
web-runtime/src/faas/faas_interface.rs
Normal 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(())
|
||||
}
|
123
web-runtime/src/faas/json/ivalues_to_json.rs
Normal file
123
web-runtime/src/faas/json/ivalues_to_json.rs
Normal 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
|
||||
))),
|
||||
}
|
||||
}
|
244
web-runtime/src/faas/json/json_to_ivalues.rs
Normal file
244
web-runtime/src/faas/json/json_to_ivalues.rs
Normal 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
|
||||
))),
|
||||
}
|
||||
}
|
21
web-runtime/src/faas/json/mod.rs
Normal file
21
web-runtime/src/faas/json/mod.rs
Normal 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;
|
36
web-runtime/src/faas/mod.rs
Normal file
36
web-runtime/src/faas/mod.rs
Normal 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;
|
26
web-runtime/src/global_state.rs
Normal file
26
web-runtime/src/global_state.rs
Normal 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
58
web-runtime/src/lib.rs
Normal 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(())
|
||||
}
|
334
web-runtime/src/marine_js.rs
Normal file
334
web-runtime/src/marine_js.rs
Normal 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);
|
||||
})
|
||||
}
|
||||
}
|
19
web-runtime/src/misc/mod.rs
Normal file
19
web-runtime/src/misc/mod.rs
Normal 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;
|
36
web-runtime/src/misc/version_checker.rs
Normal file
36
web-runtime/src/misc/version_checker.rs
Normal 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(())
|
||||
}
|
70
web-runtime/src/module/exports.rs
Normal file
70
web-runtime/src/module/exports.rs
Normal 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)
|
||||
}
|
||||
}
|
185
web-runtime/src/module/marine_module.rs
Normal file
185
web-runtime/src/module/marine_module.rs
Normal 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))
|
||||
}
|
||||
}
|
178
web-runtime/src/module/memory.rs
Normal file
178
web-runtime/src/module/memory.rs
Normal 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())
|
||||
}
|
||||
}
|
56
web-runtime/src/module/mod.rs
Normal file
56
web-runtime/src/module/mod.rs
Normal 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;
|
||||
}
|
74
web-runtime/src/module/type_converters.rs
Normal file
74
web-runtime/src/module/type_converters.rs
Normal 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<_>>()
|
||||
}
|
108
web-runtime/src/module/wit_function.rs
Normal file
108
web-runtime/src/module/wit_function.rs
Normal 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(|_| ()),
|
||||
}
|
||||
}
|
||||
}
|
143
web-runtime/src/module/wit_instance.rs
Normal file
143
web-runtime/src/module/wit_instance.rs
Normal 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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user