mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-04-27 16:55:44 +08:00
Add wasm based examples (#1018)
* WIP * Add custom add request * Update package.json * Component model resource example * Update to latest wit-bindgen * WIP * Minor example updates * Update wasm-lsp example * Added some minor comments * Minor renames * Change lsp server to count files * More model resource work * WIP * Make the example work * Update examples to latest * Update sample to latest tooling * Update sample to latest wit2ts tooling * WIP * Carry over https://github.com/microsoft/vscode-docs/pull/7234/files * Code cleanup * Remove dist folder * Remove another dist folder
This commit is contained in:
5
wasm-component-model-resource/.eslintignore
Normal file
5
wasm-component-model-resource/.eslintignore
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules/**
|
||||
out
|
||||
dist
|
||||
src/example.ts
|
||||
bin
|
||||
21
wasm-component-model-resource/.eslintrc.js
Normal file
21
wasm-component-model-resource/.eslintrc.js
Normal file
@ -0,0 +1,21 @@
|
||||
/**@type {import('eslint').Linter.Config} */
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
],
|
||||
rules: {
|
||||
'semi': [2, "always"],
|
||||
'@typescript-eslint/no-unused-vars': 0,
|
||||
'@typescript-eslint/no-explicit-any': 0,
|
||||
'@typescript-eslint/explicit-module-boundary-types': 0,
|
||||
'@typescript-eslint/no-non-null-assertion': 0,
|
||||
'@typescript-eslint/no-namespace': "off"
|
||||
}
|
||||
};
|
||||
2
wasm-component-model-resource/.gitignore
vendored
Normal file
2
wasm-component-model-resource/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
target
|
||||
dist
|
||||
19
wasm-component-model-resource/.vscode/launch.json
vendored
Normal file
19
wasm-component-model-resource/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"name": "Run Example",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceRoot}",
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/out/**/*.js"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"preLaunchTask": "npm: build"
|
||||
}
|
||||
]
|
||||
}
|
||||
313
wasm-component-model-resource/Cargo.lock
generated
Normal file
313
wasm-component-model-resource/Cargo.lock
generated
Normal file
@ -0,0 +1,313 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "calculator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ef1a0fa1e39ac22972c8db23ff89aea700ab96aa87114e1fb55937a631a0c9"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.202.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfd106365a7f5f7aa3c1916a98cbb3ad477f5ff96ddb130285a91c6e7429e67a"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.202.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "094aea3cb90e09f16ee25a4c0e324b3e8c934e7fd838bfa039aef5352f44a917"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.202.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6998515d3cf3f8b980ef7c11b29a9b1017d4cf86b99ae93b546992df9931413"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb4e7653763780be47e38f479e9aa83c768aa6a3b2ed086dc2826fdbbb7e7f5"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b67e11c950041849a10828c7600ea62a4077c01e8af72e8593253575428f91b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b0780cf7046630ed70f689a098cd8d56c5c3b22f2a7379bbdb088879963ff96"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30acbe8fb708c3a830a33c4cb705df82659bf831b492ec6ca1a17a369cfeeafb"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b1b06eae85feaecdf9f2854f7cac124e00d5a6e5014bfb02eb1ecdeb5f265b9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.202.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c836b1fd9932de0431c1758d8be08212071b6bba0151f7bac826dbc4312a2a9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.202.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "744237b488352f4f27bca05a10acb79474415951c450e52ebd0da784c1df2bcc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser",
|
||||
]
|
||||
12
wasm-component-model-resource/Cargo.toml
Normal file
12
wasm-component-model-resource/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "calculator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wit-bindgen = "0.24.0"
|
||||
27
wasm-component-model-resource/README.md
Normal file
27
wasm-component-model-resource/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# WASM Component Model Example
|
||||
|
||||
An example demonstrating how to use the component model to integrate WebAssembly code into VS Code.
|
||||
|
||||
|
||||
## Functionality
|
||||
|
||||
A simple calculator that can perform add, sub, mul and div. The calculator is implemented in Rust and compiled to WebAssembly code and then call from JavaScript.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
To run the sample the following tool chains need to be installed
|
||||
|
||||
- [Rust](https://www.rust-lang.org/): installation instructions can be found [here](https://www.rust-lang.org/tools/install)
|
||||
- [wasm-tools](https://github.com/bytecodealliance/wasm-tools): releases can be found [here](https://github.com/bytecodealliance/wasm-tools/releases). You need at least version >= 1.200 to run the example.
|
||||
|
||||
## Running the Sample in the Desktop
|
||||
|
||||
- Run `npm install` in this folder. This installs all necessary npm modules.
|
||||
- Open VS Code on this folder.
|
||||
- Execute the launch config `Run Example`.
|
||||
|
||||
## Running the Sample in the Web
|
||||
|
||||
As a pre-requisite follow the instructions [here](https://code.visualstudio.com/api/extension-guides/web-extensions#test-your-web-extension-in-vscode.dev) to generate necessary certificate to side load the extension into vscode.dev or insiders.vscode.dev.
|
||||
|
||||
Then compile the extension for the Web by running `npm run esbuild`, start a local extension server using `npm run serve`, open vscode.dev or insiders.vscode.dev in a browser and execute the command `Install Extension from Location`. As a location use `https://localhost:5000`.
|
||||
71
wasm-component-model-resource/bin/esbuild.js
Normal file
71
wasm-component-model-resource/bin/esbuild.js
Normal file
@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
//@ts-check
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
/**
|
||||
* @typedef {import('esbuild').BuildOptions} BuildOptions
|
||||
*/
|
||||
|
||||
/** @type BuildOptions */
|
||||
const sharedWebOptions = {
|
||||
bundle: true,
|
||||
external: ['vscode'],
|
||||
target: 'es2020',
|
||||
platform: 'browser',
|
||||
sourcemap: true,
|
||||
};
|
||||
|
||||
/** @type BuildOptions */
|
||||
const webOptions = {
|
||||
entryPoints: ['src/extension.ts'],
|
||||
outfile: 'dist/web/extension.js',
|
||||
format: 'cjs',
|
||||
...sharedWebOptions,
|
||||
};
|
||||
|
||||
/** @type BuildOptions */
|
||||
const sharedDesktopOptions = {
|
||||
bundle: true,
|
||||
external: ['vscode'],
|
||||
target: 'es2020',
|
||||
platform: 'node',
|
||||
sourcemap: true,
|
||||
};
|
||||
|
||||
/** @type BuildOptions */
|
||||
const desktopOptions = {
|
||||
entryPoints: ['src/extension.ts'],
|
||||
outfile: 'dist/desktop/extension.js',
|
||||
format: 'cjs',
|
||||
...sharedDesktopOptions,
|
||||
};
|
||||
|
||||
function createContexts() {
|
||||
return Promise.all([
|
||||
esbuild.context(webOptions),
|
||||
esbuild.context(desktopOptions),
|
||||
]);
|
||||
}
|
||||
|
||||
createContexts().then(contexts => {
|
||||
if (process.argv[2] === '--watch') {
|
||||
const promises = [];
|
||||
for (const context of contexts) {
|
||||
promises.push(context.watch());
|
||||
}
|
||||
return Promise.all(promises).then(() => { return undefined; });
|
||||
} else {
|
||||
const promises = [];
|
||||
for (const context of contexts) {
|
||||
promises.push(context.rebuild());
|
||||
}
|
||||
Promise.all(promises).then(async () => {
|
||||
for (const context of contexts) {
|
||||
await context.dispose();
|
||||
}
|
||||
}).then(() => { return undefined; }).catch(console.error);
|
||||
}
|
||||
}).catch(console.error);
|
||||
3041
wasm-component-model-resource/package-lock.json
generated
Normal file
3041
wasm-component-model-resource/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
55
wasm-component-model-resource/package.json
Normal file
55
wasm-component-model-resource/package.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "wasm-component-model-resource",
|
||||
"description": "An example implementing a calculator using a resource.",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
||||
},
|
||||
"publisher": "vscode-samples",
|
||||
"categories": [],
|
||||
"keywords": [
|
||||
"WASM",
|
||||
"Component Model"
|
||||
],
|
||||
"engines": {
|
||||
"vscode": "^1.88.0"
|
||||
},
|
||||
"main": "./out/extension",
|
||||
"browser": "./dist/web/extension",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "vscode-samples.wasm-component-model.run",
|
||||
"category": "Samples",
|
||||
"title": "Run Calc Service"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vscode/wasm-component-model": "0.1.0-pre.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "1.88.0",
|
||||
"@types/node": "^18.14.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.6.0",
|
||||
"@typescript-eslint/parser": "^7.6.0",
|
||||
"eslint": "^8.57.0",
|
||||
"typescript": "^5.4.5",
|
||||
"esbuild": "^0.20.2",
|
||||
"serve": "^14.2.1"
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"build": "npm run compile && cargo build --target wasm32-unknown-unknown",
|
||||
"wit-bindgen": "wit-bindgen rust --out-dir ./src ./wit",
|
||||
"compile": "tsc -b",
|
||||
"watch": "tsc -b -w",
|
||||
"lint": "eslint ./src --ext .ts,.tsx",
|
||||
"esbuild": "node ./bin/esbuild.js",
|
||||
"generate:model": "wit2ts --outDir ./src ./wit",
|
||||
"serve": "serve --cors -l 5000 --ssl-cert $HOME/certs/localhost.pem --ssl-key $HOME/certs/localhost-key.pem"
|
||||
}
|
||||
}
|
||||
545
wasm-component-model-resource/src/calculator.rs
Normal file
545
wasm-component-model-resource/src/calculator.rs
Normal file
@ -0,0 +1,545 @@
|
||||
// Generated by `wit-bindgen` 0.24.0. DO NOT EDIT!
|
||||
// Options used:
|
||||
#[allow(dead_code)]
|
||||
pub mod exports {
|
||||
#[allow(dead_code)]
|
||||
pub mod vscode {
|
||||
#[allow(dead_code)]
|
||||
pub mod example {
|
||||
#[allow(dead_code, clippy::all)]
|
||||
pub mod types {
|
||||
#[used]
|
||||
#[doc(hidden)]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports;
|
||||
use super::super::super::super::_rt;
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum Operation {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
}
|
||||
impl ::core::fmt::Debug for Operation {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
match self {
|
||||
Operation::Add => {
|
||||
f.debug_tuple("Operation::Add").finish()
|
||||
}
|
||||
Operation::Sub => {
|
||||
f.debug_tuple("Operation::Sub").finish()
|
||||
}
|
||||
Operation::Mul => {
|
||||
f.debug_tuple("Operation::Mul").finish()
|
||||
}
|
||||
Operation::Div => {
|
||||
f.debug_tuple("Operation::Div").finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Operation{
|
||||
pub(crate) unsafe fn _lift(val: u8) -> Operation{
|
||||
if !cfg!(debug_assertions) {
|
||||
return ::core::mem::transmute(val);
|
||||
}
|
||||
|
||||
match val {
|
||||
0 => Operation::Add,
|
||||
1 => Operation::Sub,
|
||||
2 => Operation::Mul,
|
||||
3 => Operation::Div,
|
||||
|
||||
_ => panic!("invalid enum discriminant"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct Engine{
|
||||
handle: _rt::Resource<Engine>,
|
||||
}
|
||||
|
||||
type _EngineRep<T> = Option<T>;
|
||||
|
||||
impl Engine{
|
||||
/// Creates a new resource from the specified representation.
|
||||
///
|
||||
/// This function will create a new resource handle by moving `val` onto
|
||||
/// the heap and then passing that heap pointer to the component model to
|
||||
/// create a handle. The owned handle is then returned as `Engine`.
|
||||
pub fn new<T: GuestEngine>(val: T) -> Self {
|
||||
Self::type_guard::<T>();
|
||||
let val: _EngineRep<T> = Some(val);
|
||||
let ptr: *mut _EngineRep<T> =
|
||||
_rt::Box::into_raw(_rt::Box::new(val));
|
||||
unsafe {
|
||||
Self::from_handle(T::_resource_new(ptr.cast()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets access to the underlying `T` which represents this resource.
|
||||
pub fn get<T: GuestEngine>(&self) -> &T {
|
||||
let ptr = unsafe { &*self.as_ptr::<T>() };
|
||||
ptr.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Gets mutable access to the underlying `T` which represents this
|
||||
/// resource.
|
||||
pub fn get_mut<T: GuestEngine>(&mut self) -> &mut T {
|
||||
let ptr = unsafe { &mut *self.as_ptr::<T>() };
|
||||
ptr.as_mut().unwrap()
|
||||
}
|
||||
|
||||
/// Consumes this resource and returns the underlying `T`.
|
||||
pub fn into_inner<T: GuestEngine>(self) -> T {
|
||||
let ptr = unsafe { &mut *self.as_ptr::<T>() };
|
||||
ptr.take().unwrap()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn from_handle(handle: u32) -> Self {
|
||||
Self {
|
||||
handle: _rt::Resource::from_handle(handle),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn take_handle(&self) -> u32 {
|
||||
_rt::Resource::take_handle(&self.handle)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn handle(&self) -> u32 {
|
||||
_rt::Resource::handle(&self.handle)
|
||||
}
|
||||
|
||||
// It's theoretically possible to implement the `GuestEngine` trait twice
|
||||
// so guard against using it with two different types here.
|
||||
#[doc(hidden)]
|
||||
fn type_guard<T: 'static>() {
|
||||
use core::any::TypeId;
|
||||
static mut LAST_TYPE: Option<TypeId> = None;
|
||||
unsafe {
|
||||
assert!(!cfg!(target_feature = "threads"));
|
||||
let id = TypeId::of::<T>();
|
||||
match LAST_TYPE {
|
||||
Some(ty) => assert!(ty == id, "cannot use two types with this resource type"),
|
||||
None => LAST_TYPE = Some(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn dtor<T: 'static>(handle: *mut u8) {
|
||||
Self::type_guard::<T>();
|
||||
let _ = _rt::Box::from_raw(handle as *mut _EngineRep<T>);
|
||||
}
|
||||
|
||||
fn as_ptr<T: GuestEngine>(&self) -> *mut _EngineRep<T> {
|
||||
Engine::type_guard::<T>();
|
||||
T::_resource_rep(self.handle()).cast()
|
||||
}
|
||||
}
|
||||
|
||||
/// A borrowed version of [`Engine`] which represents a borrowed value
|
||||
/// with the lifetime `'a`.
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct EngineBorrow<'a> {
|
||||
rep: *mut u8,
|
||||
_marker: core::marker::PhantomData<&'a Engine>,
|
||||
}
|
||||
|
||||
impl<'a> EngineBorrow<'a>{
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn lift(rep: usize) -> Self {
|
||||
Self {
|
||||
rep: rep as *mut u8,
|
||||
_marker: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets access to the underlying `T` in this resource.
|
||||
pub fn get<T: GuestEngine>(&self) -> &T {
|
||||
let ptr = unsafe { &mut *self.as_ptr::<T>() };
|
||||
ptr.as_ref().unwrap()
|
||||
}
|
||||
|
||||
// NB: mutable access is not allowed due to the component model allowing
|
||||
// multiple borrows of the same resource.
|
||||
|
||||
fn as_ptr<T: 'static>(&self) -> *mut _EngineRep<T> {
|
||||
Engine::type_guard::<T>();
|
||||
self.rep.cast()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsafe impl _rt::WasmResource for Engine{
|
||||
#[inline]
|
||||
unsafe fn drop(_handle: u32) {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
unreachable!();
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
#[link(wasm_import_module = "[export]vscode:example/types")]
|
||||
extern "C" {
|
||||
#[link_name = "[resource-drop]engine"]
|
||||
fn drop(_: u32);
|
||||
}
|
||||
|
||||
drop(_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_constructor_engine_cabi<T: GuestEngine>() -> i32 {#[cfg(target_arch="wasm32")]
|
||||
_rt::run_ctors_once();let result0 = Engine::new(T::new());
|
||||
(result0).take_handle() as i32
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_method_engine_push_operand_cabi<T: GuestEngine>(arg0: *mut u8,arg1: i32,) {#[cfg(target_arch="wasm32")]
|
||||
_rt::run_ctors_once();T::push_operand(EngineBorrow::lift(arg0 as u32 as usize).get(), arg1 as u32);
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_method_engine_push_operation_cabi<T: GuestEngine>(arg0: *mut u8,arg1: i32,) {#[cfg(target_arch="wasm32")]
|
||||
_rt::run_ctors_once();T::push_operation(EngineBorrow::lift(arg0 as u32 as usize).get(), Operation::_lift(arg1 as u8));
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_method_engine_execute_cabi<T: GuestEngine>(arg0: *mut u8,) -> i32 {#[cfg(target_arch="wasm32")]
|
||||
_rt::run_ctors_once();let result0 = T::execute(EngineBorrow::lift(arg0 as u32 as usize).get());
|
||||
_rt::as_i32(result0)
|
||||
}
|
||||
pub trait Guest {
|
||||
type Engine: GuestEngine;
|
||||
}
|
||||
pub trait GuestEngine: 'static {
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe fn _resource_new(val: *mut u8) -> u32
|
||||
where Self: Sized
|
||||
{
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = val;
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
#[link(wasm_import_module = "[export]vscode:example/types")]
|
||||
extern "C" {
|
||||
#[link_name = "[resource-new]engine"]
|
||||
fn new(_: *mut u8) -> u32;
|
||||
}
|
||||
new(val)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
fn _resource_rep(handle: u32) -> *mut u8
|
||||
where Self: Sized
|
||||
{
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let _ = handle;
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
#[link(wasm_import_module = "[export]vscode:example/types")]
|
||||
extern "C" {
|
||||
#[link_name = "[resource-rep]engine"]
|
||||
fn rep(_: u32) -> *mut u8;
|
||||
}
|
||||
unsafe {
|
||||
rep(handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn new() -> Self;
|
||||
fn push_operand(&self,operand: u32,);
|
||||
fn push_operation(&self,operation: Operation,);
|
||||
fn execute(&self,) -> u32;
|
||||
}
|
||||
#[doc(hidden)]
|
||||
|
||||
macro_rules! __export_vscode_example_types_cabi{
|
||||
($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = {
|
||||
|
||||
#[export_name = "vscode:example/types#[constructor]engine"]
|
||||
unsafe extern "C" fn export_constructor_engine() -> i32 {
|
||||
$($path_to_types)*::_export_constructor_engine_cabi::<<$ty as $($path_to_types)*::Guest>::Engine>()
|
||||
}
|
||||
#[export_name = "vscode:example/types#[method]engine.push-operand"]
|
||||
unsafe extern "C" fn export_method_engine_push_operand(arg0: *mut u8,arg1: i32,) {
|
||||
$($path_to_types)*::_export_method_engine_push_operand_cabi::<<$ty as $($path_to_types)*::Guest>::Engine>(arg0, arg1)
|
||||
}
|
||||
#[export_name = "vscode:example/types#[method]engine.push-operation"]
|
||||
unsafe extern "C" fn export_method_engine_push_operation(arg0: *mut u8,arg1: i32,) {
|
||||
$($path_to_types)*::_export_method_engine_push_operation_cabi::<<$ty as $($path_to_types)*::Guest>::Engine>(arg0, arg1)
|
||||
}
|
||||
#[export_name = "vscode:example/types#[method]engine.execute"]
|
||||
unsafe extern "C" fn export_method_engine_execute(arg0: *mut u8,) -> i32 {
|
||||
$($path_to_types)*::_export_method_engine_execute_cabi::<<$ty as $($path_to_types)*::Guest>::Engine>(arg0)
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
#[doc(hidden)]
|
||||
#[export_name = "vscode:example/types#[dtor]engine"]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn dtor(rep: *mut u8) {
|
||||
$($path_to_types)*::Engine::dtor::<
|
||||
<$ty as $($path_to_types)*::Guest>::Engine
|
||||
>(rep)
|
||||
}
|
||||
};
|
||||
|
||||
};);
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub(crate) use __export_vscode_example_types_cabi;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
mod _rt {
|
||||
|
||||
|
||||
use core::fmt;
|
||||
use core::marker;
|
||||
use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
|
||||
|
||||
/// A type which represents a component model resource, either imported or
|
||||
/// exported into this component.
|
||||
///
|
||||
/// This is a low-level wrapper which handles the lifetime of the resource
|
||||
/// (namely this has a destructor). The `T` provided defines the component model
|
||||
/// intrinsics that this wrapper uses.
|
||||
///
|
||||
/// One of the chief purposes of this type is to provide `Deref` implementations
|
||||
/// to access the underlying data when it is owned.
|
||||
///
|
||||
/// This type is primarily used in generated code for exported and imported
|
||||
/// resources.
|
||||
#[repr(transparent)]
|
||||
pub struct Resource<T: WasmResource> {
|
||||
// NB: This would ideally be `u32` but it is not. The fact that this has
|
||||
// interior mutability is not exposed in the API of this type except for the
|
||||
// `take_handle` method which is supposed to in theory be private.
|
||||
//
|
||||
// This represents, almost all the time, a valid handle value. When it's
|
||||
// invalid it's stored as `u32::MAX`.
|
||||
handle: AtomicU32,
|
||||
_marker: marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
/// A trait which all wasm resources implement, namely providing the ability to
|
||||
/// drop a resource.
|
||||
///
|
||||
/// This generally is implemented by generated code, not user-facing code.
|
||||
pub unsafe trait WasmResource {
|
||||
/// Invokes the `[resource-drop]...` intrinsic.
|
||||
unsafe fn drop(handle: u32);
|
||||
}
|
||||
|
||||
impl<T: WasmResource> Resource<T> {
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn from_handle(handle: u32) -> Self {
|
||||
debug_assert!(handle != u32::MAX);
|
||||
Self {
|
||||
handle: AtomicU32::new(handle),
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes ownership of the handle owned by `resource`.
|
||||
///
|
||||
/// Note that this ideally would be `into_handle` taking `Resource<T>` by
|
||||
/// ownership. The code generator does not enable that in all situations,
|
||||
/// unfortunately, so this is provided instead.
|
||||
///
|
||||
/// Also note that `take_handle` is in theory only ever called on values
|
||||
/// owned by a generated function. For example a generated function might
|
||||
/// take `Resource<T>` as an argument but then call `take_handle` on a
|
||||
/// reference to that argument. In that sense the dynamic nature of
|
||||
/// `take_handle` should only be exposed internally to generated code, not
|
||||
/// to user code.
|
||||
#[doc(hidden)]
|
||||
pub fn take_handle(resource: &Resource<T>) -> u32 {
|
||||
resource.handle.swap(u32::MAX, Relaxed)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn handle(resource: &Resource<T>) -> u32 {
|
||||
resource.handle.load(Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WasmResource> fmt::Debug for Resource<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Resource")
|
||||
.field("handle", &self.handle)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WasmResource> Drop for Resource<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
match self.handle.load(Relaxed) {
|
||||
// If this handle was "taken" then don't do anything in the
|
||||
// destructor.
|
||||
u32::MAX => {}
|
||||
|
||||
// ... but otherwise do actually destroy it with the imported
|
||||
// component model intrinsic as defined through `T`.
|
||||
other => T::drop(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use alloc_crate::boxed::Box;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn run_ctors_once() {
|
||||
wit_bindgen::rt::run_ctors_once();
|
||||
}
|
||||
|
||||
pub fn as_i32<T: AsI32>(t: T) -> i32 {
|
||||
t.as_i32()
|
||||
}
|
||||
|
||||
pub trait AsI32 {
|
||||
fn as_i32(self) -> i32;
|
||||
}
|
||||
|
||||
impl<'a, T: Copy + AsI32> AsI32 for &'a T {
|
||||
fn as_i32(self) -> i32 {
|
||||
(*self).as_i32()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for i32 {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for u32 {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for i16 {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for u16 {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for i8 {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for u8 {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for char {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl AsI32 for usize {
|
||||
#[inline]
|
||||
fn as_i32(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
}
|
||||
extern crate alloc as alloc_crate;
|
||||
}
|
||||
|
||||
/// Generates `#[no_mangle]` functions to export the specified type as the
|
||||
/// root implementation of all generated traits.
|
||||
///
|
||||
/// For more information see the documentation of `wit_bindgen::generate!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # macro_rules! export{ ($($t:tt)*) => (); }
|
||||
/// # trait Guest {}
|
||||
/// struct MyType;
|
||||
///
|
||||
/// impl Guest for MyType {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// export!(MyType);
|
||||
/// ```
|
||||
#[allow(unused_macros)]
|
||||
#[doc(hidden)]
|
||||
|
||||
macro_rules! __export_calculator_impl {
|
||||
($ty:ident) => (self::export!($ty with_types_in self););
|
||||
($ty:ident with_types_in $($path_to_types_root:tt)*) => (
|
||||
$($path_to_types_root)*::exports::vscode::example::types::__export_vscode_example_types_cabi!($ty with_types_in $($path_to_types_root)*::exports::vscode::example::types);
|
||||
)
|
||||
}
|
||||
#[doc(inline)]
|
||||
pub(crate) use __export_calculator_impl as export;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[link_section = "component-type:wit-bindgen:0.24.0:calculator:encoded world"]
|
||||
#[doc(hidden)]
|
||||
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 419] = *b"\
|
||||
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xa2\x02\x01A\x02\x01\
|
||||
A\x02\x01B\x0d\x01m\x04\x03add\x03sub\x03mul\x03div\x04\0\x09operation\x03\0\0\x04\
|
||||
\0\x06engine\x03\x01\x01i\x02\x01@\0\0\x03\x04\0\x13[constructor]engine\x01\x04\x01\
|
||||
h\x02\x01@\x02\x04self\x05\x07operandy\x01\0\x04\0\x1b[method]engine.push-operan\
|
||||
d\x01\x06\x01@\x02\x04self\x05\x09operation\x01\x01\0\x04\0\x1d[method]engine.pu\
|
||||
sh-operation\x01\x07\x01@\x01\x04self\x05\0y\x04\0\x16[method]engine.execute\x01\
|
||||
\x08\x04\x01\x14vscode:example/types\x05\0\x04\x01\x19vscode:example/calculator\x04\
|
||||
\0\x0b\x10\x01\0\x0acalculator\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0d\
|
||||
wit-component\x070.202.0\x10wit-bindgen-rust\x060.24.0";
|
||||
|
||||
#[inline(never)]
|
||||
#[doc(hidden)]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn __link_custom_section_describing_imports() {
|
||||
wit_bindgen::rt::maybe_link_cabi_realloc();
|
||||
}
|
||||
|
||||
178
wasm-component-model-resource/src/calculator.ts
Normal file
178
wasm-component-model-resource/src/calculator.ts
Normal file
@ -0,0 +1,178 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import * as $wcm from '@vscode/wasm-component-model';
|
||||
import type { u32, own, i32 } from '@vscode/wasm-component-model';
|
||||
|
||||
export namespace Types {
|
||||
export enum Operation {
|
||||
add = 'add',
|
||||
sub = 'sub',
|
||||
mul = 'mul',
|
||||
div = 'div'
|
||||
}
|
||||
|
||||
export namespace Engine {
|
||||
export interface Interface extends $wcm.Resource {
|
||||
pushOperand(operand: u32): void;
|
||||
|
||||
pushOperation(operation: Operation): void;
|
||||
|
||||
execute(): u32;
|
||||
}
|
||||
export type Statics = {
|
||||
};
|
||||
export type Class = Statics & {
|
||||
new(): Interface;
|
||||
};
|
||||
}
|
||||
export type Engine = Engine.Interface;
|
||||
}
|
||||
export type Types = {
|
||||
Engine: Types.Engine.Class;
|
||||
};
|
||||
export namespace calculator {
|
||||
export type Imports = {
|
||||
};
|
||||
export type Exports = {
|
||||
types: Types;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace Types.$ {
|
||||
export const Operation = new $wcm.EnumType<Types.Operation>(['add', 'sub', 'mul', 'div']);
|
||||
export const Engine = new $wcm.ResourceType<Types.Engine>('engine', 'vscode:example/types/engine');
|
||||
export const Engine_Handle = new $wcm.ResourceHandleType('engine');
|
||||
Engine.addDestructor('$drop', new $wcm.DestructorType('[resource-drop]engine', [['inst', Engine]]));
|
||||
Engine.addConstructor('constructor', new $wcm.ConstructorType<Types.Engine.Class['constructor']>('[constructor]engine', [], new $wcm.OwnType(Engine_Handle)));
|
||||
Engine.addMethod('pushOperand', new $wcm.MethodType<Types.Engine.Interface['pushOperand']>('[method]engine.push-operand', [
|
||||
['operand', $wcm.u32],
|
||||
], undefined));
|
||||
Engine.addMethod('pushOperation', new $wcm.MethodType<Types.Engine.Interface['pushOperation']>('[method]engine.push-operation', [
|
||||
['operation', Operation],
|
||||
], undefined));
|
||||
Engine.addMethod('execute', new $wcm.MethodType<Types.Engine.Interface['execute']>('[method]engine.execute', [], $wcm.u32));
|
||||
}
|
||||
export namespace Types._ {
|
||||
export const id = 'vscode:example/types' as const;
|
||||
export const witName = 'types' as const;
|
||||
export namespace Engine {
|
||||
export type WasmInterface = {
|
||||
'[constructor]engine': () => i32;
|
||||
'[method]engine.push-operand': (self: i32, operand: i32) => void;
|
||||
'[method]engine.push-operation': (self: i32, operation_Operation: i32) => void;
|
||||
'[method]engine.execute': (self: i32) => i32;
|
||||
};
|
||||
type ObjectModule = {
|
||||
'constructor'(): own<$wcm.ResourceHandle>;
|
||||
pushOperand(self: Engine, operand: u32): void;
|
||||
pushOperation(self: Engine, operation: Operation): void;
|
||||
execute(self: Engine): u32;
|
||||
};
|
||||
export namespace imports {
|
||||
export type WasmInterface = Engine.WasmInterface & { '[resource-drop]engine': (self: i32) => void };
|
||||
}
|
||||
export namespace exports {
|
||||
export type WasmInterface = Engine.WasmInterface & { '[dtor]engine': (self: i32) => void };
|
||||
class Impl extends $wcm.Resource.Default implements Types.Engine.Interface {
|
||||
private readonly _rep: $wcm.ResourceRepresentation;
|
||||
private readonly _om: ObjectModule;
|
||||
constructor(om: ObjectModule);
|
||||
constructor(handleTag: symbol, handle: $wcm.ResourceHandle, rm: $wcm.ResourceManager, om: ObjectModule);
|
||||
constructor(...args: any[]);
|
||||
constructor(...args: any[]) {
|
||||
if (args[0] === $wcm.ResourceManager.handleTag) {
|
||||
const handle = args[1] as $wcm.ResourceHandle;
|
||||
super(handle);
|
||||
this._rep = (args[2] as $wcm.ResourceManager).getRepresentation(handle);
|
||||
this._om = args[3] as ObjectModule;
|
||||
} else {
|
||||
const rm = args[0] as $wcm.ResourceManager;
|
||||
const om = args[1] as ObjectModule;
|
||||
super(om.constructor());
|
||||
this._rep = rm.getRepresentation(this.$handle());
|
||||
this._om = om;
|
||||
}
|
||||
}
|
||||
public $rep(): $wcm.ResourceRepresentation { return this._rep; }
|
||||
public pushOperand(operand: u32): void {
|
||||
return this._om.pushOperand(this, operand);
|
||||
}
|
||||
public pushOperation(operation: Operation): void {
|
||||
return this._om.pushOperation(this, operation);
|
||||
}
|
||||
public execute(): u32 {
|
||||
return this._om.execute(this);
|
||||
}
|
||||
}
|
||||
export function Class(wasmInterface: WasmInterface, context: $wcm.WasmContext): Types.Engine.Class {
|
||||
const resource = Types.$.Engine;
|
||||
const rm: $wcm.ResourceManager = context.resources.ensure('vscode:example/types/engine');
|
||||
const om: ObjectModule = $wcm.Module.createObjectModule(resource, wasmInterface, context);
|
||||
return class extends Impl {
|
||||
constructor();
|
||||
constructor(handleTag: symbol, handle: $wcm.ResourceHandle);
|
||||
constructor(...args: any[]) {
|
||||
super(...args, rm, om);
|
||||
rm.registerProxy(this);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
export const types: Map<string, $wcm.GenericComponentModelType> = new Map<string, $wcm.GenericComponentModelType>([
|
||||
['Operation', $.Operation],
|
||||
['Engine', $.Engine]
|
||||
]);
|
||||
export const resources: Map<string, { resource: $wcm.ResourceType; factory: $wcm.ClassFactory<any>}> = new Map<string, { resource: $wcm.ResourceType; factory: $wcm.ClassFactory<any>}>([
|
||||
['Engine', { resource: $.Engine, factory: Engine.exports.Class }]
|
||||
]);
|
||||
export type WasmInterface = {
|
||||
};
|
||||
export namespace imports {
|
||||
export type WasmInterface = _.WasmInterface & Engine.imports.WasmInterface;
|
||||
}
|
||||
export namespace exports {
|
||||
export type WasmInterface = _.WasmInterface & Engine.exports.WasmInterface;
|
||||
export namespace imports {
|
||||
export type WasmInterface = {
|
||||
'[resource-new]engine': (rep: i32) => i32;
|
||||
'[resource-rep]engine': (handle: i32) => i32;
|
||||
'[resource-drop]engine': (handle: i32) => void;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
export namespace calculator.$ {
|
||||
}
|
||||
export namespace calculator._ {
|
||||
export const id = 'vscode:example/calculator' as const;
|
||||
export const witName = 'calculator' as const;
|
||||
export type Imports = {
|
||||
'[export]vscode:example/types': Types._.exports.imports.WasmInterface;
|
||||
};
|
||||
export namespace imports {
|
||||
export function create(service: calculator.Imports, context: $wcm.WasmContext): Imports {
|
||||
return $wcm.Imports.create<Imports>(_, service, context);
|
||||
}
|
||||
export function loop(service: calculator.Imports, context: $wcm.WasmContext): calculator.Imports {
|
||||
return $wcm.Imports.loop(_, service, context);
|
||||
}
|
||||
}
|
||||
export type Exports = {
|
||||
'vscode:example/types#[constructor]engine': () => i32;
|
||||
'vscode:example/types#[method]engine.push-operand': (self: i32, operand: i32) => void;
|
||||
'vscode:example/types#[method]engine.push-operation': (self: i32, operation_Operation: i32) => void;
|
||||
'vscode:example/types#[method]engine.execute': (self: i32) => i32;
|
||||
};
|
||||
export namespace exports {
|
||||
export const interfaces: Map<string, $wcm.InterfaceType> = new Map<string, $wcm.InterfaceType>([
|
||||
['Types', Types._]
|
||||
]);
|
||||
export function bind(exports: Exports, context: $wcm.WasmContext): calculator.Exports {
|
||||
return $wcm.Exports.bind<calculator.Exports>(_, exports, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
wasm-component-model-resource/src/extension.ts
Normal file
53
wasm-component-model-resource/src/extension.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as vscode from 'vscode';
|
||||
import { WasmContext, Memory } from '@vscode/wasm-component-model';
|
||||
|
||||
import { calculator, Types } from './calculator';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
// The channel for printing the result.
|
||||
const channel = vscode.window.createOutputChannel('Calculator');
|
||||
context.subscriptions.push(channel);
|
||||
|
||||
// The channel for printing the log.
|
||||
const log = vscode.window.createOutputChannel('Calculator - Log', { log: true });
|
||||
context.subscriptions.push(log);
|
||||
|
||||
// Load the Wasm module
|
||||
const filename = vscode.Uri.joinPath(context.extensionUri, 'target', 'wasm32-unknown-unknown', 'debug', 'calculator.wasm');
|
||||
const bits = await vscode.workspace.fs.readFile(filename);
|
||||
const module = await WebAssembly.compile(bits);
|
||||
|
||||
// The context for the WASM module
|
||||
const wasmContext: WasmContext.Default = new WasmContext.Default();
|
||||
|
||||
// Instantiate the module and create the necessary imports from the service implementation
|
||||
const instance = await WebAssembly.instantiate(module, calculator._.imports.create({}, wasmContext));
|
||||
// Bind the WASM memory to the context
|
||||
wasmContext.initialize(new Memory.Default(instance.exports));
|
||||
|
||||
// Bind the JavaScript Api
|
||||
const api = calculator._.exports.bind(instance.exports as calculator._.Exports, wasmContext);
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('vscode-samples.wasm-component-model.run', () => {
|
||||
channel.show();
|
||||
channel.appendLine('Running calculator example');
|
||||
|
||||
// Create a new calculator engine
|
||||
const calculator = new api.types.Engine();
|
||||
|
||||
// Push some operands and operations
|
||||
calculator.pushOperand(10);
|
||||
calculator.pushOperand(20);
|
||||
calculator.pushOperation(Types.Operation.add);
|
||||
calculator.pushOperand(2);
|
||||
calculator.pushOperation(Types.Operation.mul);
|
||||
|
||||
// Calculate the result
|
||||
const result = calculator.execute();
|
||||
channel.appendLine(`Result: ${result}`);
|
||||
}));
|
||||
}
|
||||
77
wasm-component-model-resource/src/lib.rs
Normal file
77
wasm-component-model-resource/src/lib.rs
Normal file
@ -0,0 +1,77 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
mod calculator;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use crate::calculator::exports::vscode::example::types::{ Guest, GuestEngine, Operation };
|
||||
|
||||
struct EngineImpl {
|
||||
left: Option<u32>,
|
||||
right: Option<u32>,
|
||||
}
|
||||
|
||||
impl EngineImpl {
|
||||
fn new() -> Self {
|
||||
EngineImpl {
|
||||
left: None,
|
||||
right: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn push_operand(&mut self, operand: u32) {
|
||||
if self.left == None {
|
||||
self.left = Some(operand);
|
||||
} else {
|
||||
self.right = Some(operand);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_operation(&mut self, operation: Operation) {
|
||||
let left = self.left.unwrap();
|
||||
let right = self.right.unwrap();
|
||||
self.left = Some(match operation {
|
||||
Operation::Add => left + right,
|
||||
Operation::Sub => left - right,
|
||||
Operation::Mul => left * right,
|
||||
Operation::Div => left / right,
|
||||
});
|
||||
}
|
||||
|
||||
fn execute(&mut self) -> u32 {
|
||||
self.left.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
struct CalcEngine {
|
||||
stack: RefCell<EngineImpl>,
|
||||
}
|
||||
|
||||
impl GuestEngine for CalcEngine {
|
||||
|
||||
fn new() -> Self {
|
||||
CalcEngine {
|
||||
stack: RefCell::new(EngineImpl::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn push_operand(&self, operand: u32) {
|
||||
self.stack.borrow_mut().push_operand(operand);
|
||||
}
|
||||
|
||||
fn push_operation(&self,operation:Operation) {
|
||||
self.stack.borrow_mut().push_operation(operation);
|
||||
}
|
||||
|
||||
fn execute(&self) -> u32 {
|
||||
return self.stack.borrow_mut().execute();
|
||||
}
|
||||
}
|
||||
|
||||
struct Implementation;
|
||||
impl Guest for Implementation {
|
||||
type Engine = CalcEngine;
|
||||
}
|
||||
|
||||
calculator::export!(Implementation with_types_in calculator);
|
||||
26
wasm-component-model-resource/tsconfig.json
Normal file
26
wasm-component-model-resource/tsconfig.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"skipLibCheck": true,
|
||||
"lib": [
|
||||
"es2022",
|
||||
"webworker"
|
||||
],
|
||||
"types": [
|
||||
"vscode"
|
||||
],
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"outDir": "./out",
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false
|
||||
}
|
||||
}
|
||||
22
wasm-component-model-resource/wit/calculator.wit
Normal file
22
wasm-component-model-resource/wit/calculator.wit
Normal file
@ -0,0 +1,22 @@
|
||||
// wit/calculator.wit
|
||||
package vscode:example;
|
||||
|
||||
interface types {
|
||||
|
||||
enum operation {
|
||||
add,
|
||||
sub,
|
||||
mul,
|
||||
div
|
||||
}
|
||||
|
||||
resource engine {
|
||||
constructor();
|
||||
push-operand: func(operand: u32);
|
||||
push-operation: func(operation: operation);
|
||||
execute: func() -> u32;
|
||||
}
|
||||
}
|
||||
world calculator {
|
||||
export types;
|
||||
}
|
||||
3
wasm-component-model/.gitignore
vendored
3
wasm-component-model/.gitignore
vendored
@ -1 +1,2 @@
|
||||
target
|
||||
target
|
||||
dist
|
||||
3813
wasm-component-model/dist/desktop/extension.js
vendored
3813
wasm-component-model/dist/desktop/extension.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
4165
wasm-component-model/dist/web/extension.js
vendored
4165
wasm-component-model/dist/web/extension.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
8
wasm-component-model/package-lock.json
generated
8
wasm-component-model/package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vscode/wasm-component-model": "0.1.0-pre.3"
|
||||
"@vscode/wasm-component-model": "0.1.0-pre.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.14.6",
|
||||
@ -794,9 +794,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vscode/wasm-component-model": {
|
||||
"version": "0.1.0-pre.3",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/wasm-component-model/-/wasm-component-model-0.1.0-pre.3.tgz",
|
||||
"integrity": "sha512-1QgbcblhfBD3crZswJ3JchlwXvVSyYrxNMvVRxEkhjmW9LXYiOXFLT+iyc7yk95LSgYVWDrE5g4CRD2dXmB3sg==",
|
||||
"version": "0.1.0-pre.11",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/wasm-component-model/-/wasm-component-model-0.1.0-pre.11.tgz",
|
||||
"integrity": "sha512-52MPesjJMOgpv4K/Knek5J/szqquVx7Ji2IVfgEXYDUoE80u4aQSkPwnCBSoaIf4fECDTBtjijl4s7zAKq/58w==",
|
||||
"dependencies": {
|
||||
"semver": "^7.6.0",
|
||||
"uuid": "^9.0.1",
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vscode/wasm-component-model": "0.1.0-pre.3"
|
||||
"@vscode/wasm-component-model": "0.1.0-pre.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "1.88.0",
|
||||
@ -48,7 +48,7 @@
|
||||
"watch": "tsc -b -w",
|
||||
"lint": "eslint ./src --ext .ts,.tsx",
|
||||
"esbuild": "node ./bin/esbuild.js",
|
||||
"generate:model": "wit2ts --noMain --outDir ./src ./wit",
|
||||
"generate:model": "wit2ts --outDir ./src ./wit",
|
||||
"serve": "serve --cors -l 5000 --ssl-cert $HOME/certs/localhost.pem --ssl-key $HOME/certs/localhost-key.pem"
|
||||
}
|
||||
}
|
||||
151
wasm-component-model/src/calculator.ts
Normal file
151
wasm-component-model/src/calculator.ts
Normal file
@ -0,0 +1,151 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import * as $wcm from '@vscode/wasm-component-model';
|
||||
import type { u32, i32 } from '@vscode/wasm-component-model';
|
||||
|
||||
export namespace Types {
|
||||
export type Operands = {
|
||||
left: u32;
|
||||
right: u32;
|
||||
};
|
||||
|
||||
export namespace Operation {
|
||||
export const add = 'add' as const;
|
||||
export type Add = { readonly tag: typeof add; readonly value: Operands } & _common;
|
||||
export function Add(value: Operands): Add {
|
||||
return new VariantImpl(add, value) as Add;
|
||||
}
|
||||
|
||||
export const sub = 'sub' as const;
|
||||
export type Sub = { readonly tag: typeof sub; readonly value: Operands } & _common;
|
||||
export function Sub(value: Operands): Sub {
|
||||
return new VariantImpl(sub, value) as Sub;
|
||||
}
|
||||
|
||||
export const mul = 'mul' as const;
|
||||
export type Mul = { readonly tag: typeof mul; readonly value: Operands } & _common;
|
||||
export function Mul(value: Operands): Mul {
|
||||
return new VariantImpl(mul, value) as Mul;
|
||||
}
|
||||
|
||||
export const div = 'div' as const;
|
||||
export type Div = { readonly tag: typeof div; readonly value: Operands } & _common;
|
||||
export function Div(value: Operands): Div {
|
||||
return new VariantImpl(div, value) as Div;
|
||||
}
|
||||
|
||||
export type _tt = typeof add | typeof sub | typeof mul | typeof div;
|
||||
export type _vt = Operands | Operands | Operands | Operands;
|
||||
type _common = Omit<VariantImpl, 'tag' | 'value'>;
|
||||
export function _ctor(t: _tt, v: _vt): Operation {
|
||||
return new VariantImpl(t, v) as Operation;
|
||||
}
|
||||
class VariantImpl {
|
||||
private readonly _tag: _tt;
|
||||
private readonly _value: _vt;
|
||||
constructor(t: _tt, value: _vt) {
|
||||
this._tag = t;
|
||||
this._value = value;
|
||||
}
|
||||
get tag(): _tt {
|
||||
return this._tag;
|
||||
}
|
||||
get value(): _vt {
|
||||
return this._value;
|
||||
}
|
||||
isAdd(): this is Add {
|
||||
return this._tag === Operation.add;
|
||||
}
|
||||
isSub(): this is Sub {
|
||||
return this._tag === Operation.sub;
|
||||
}
|
||||
isMul(): this is Mul {
|
||||
return this._tag === Operation.mul;
|
||||
}
|
||||
isDiv(): this is Div {
|
||||
return this._tag === Operation.div;
|
||||
}
|
||||
}
|
||||
}
|
||||
export type Operation = Operation.Add | Operation.Sub | Operation.Mul | Operation.Div;
|
||||
}
|
||||
export type Types = {
|
||||
};
|
||||
export namespace calculator {
|
||||
export type Operation = Types.Operation;
|
||||
export type Imports = {
|
||||
log: (msg: string) => void;
|
||||
};
|
||||
export type Exports = {
|
||||
calc: (o: Operation) => u32;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace Types.$ {
|
||||
export const Operands = new $wcm.RecordType<Types.Operands>([
|
||||
['left', $wcm.u32],
|
||||
['right', $wcm.u32],
|
||||
]);
|
||||
export const Operation = new $wcm.VariantType<Types.Operation, Types.Operation._tt, Types.Operation._vt>([['add', Operands], ['sub', Operands], ['mul', Operands], ['div', Operands]], Types.Operation._ctor);
|
||||
}
|
||||
export namespace Types._ {
|
||||
export const id = 'vscode:example/types' as const;
|
||||
export const witName = 'types' as const;
|
||||
export const types: Map<string, $wcm.GenericComponentModelType> = new Map<string, $wcm.GenericComponentModelType>([
|
||||
['Operands', $.Operands],
|
||||
['Operation', $.Operation]
|
||||
]);
|
||||
export type WasmInterface = {
|
||||
};
|
||||
}
|
||||
export namespace calculator.$ {
|
||||
export const Operation = Types.$.Operation;
|
||||
export namespace imports {
|
||||
export const log = new $wcm.FunctionType<calculator.Imports['log']>('log',[
|
||||
['msg', $wcm.wstring],
|
||||
], undefined);
|
||||
}
|
||||
export namespace exports {
|
||||
export const calc = new $wcm.FunctionType<calculator.Exports['calc']>('calc',[
|
||||
['o', Operation],
|
||||
], $wcm.u32);
|
||||
}
|
||||
}
|
||||
export namespace calculator._ {
|
||||
export const id = 'vscode:example/calculator' as const;
|
||||
export const witName = 'calculator' as const;
|
||||
export type $Root = {
|
||||
'log': (msg_ptr: i32, msg_len: i32) => void;
|
||||
};
|
||||
export type Imports = {
|
||||
'$root': $Root;
|
||||
};
|
||||
export namespace imports {
|
||||
export const functions: Map<string, $wcm.FunctionType> = new Map([
|
||||
['log', $.imports.log]
|
||||
]);
|
||||
export const interfaces: Map<string, $wcm.InterfaceType> = new Map<string, $wcm.InterfaceType>([
|
||||
['Types', Types._]
|
||||
]);
|
||||
export function create(service: calculator.Imports, context: $wcm.WasmContext): Imports {
|
||||
return $wcm.Imports.create<Imports>(_, service, context);
|
||||
}
|
||||
export function loop(service: calculator.Imports, context: $wcm.WasmContext): calculator.Imports {
|
||||
return $wcm.Imports.loop(_, service, context);
|
||||
}
|
||||
}
|
||||
export type Exports = {
|
||||
'calc': (o_Operation_case: i32, o_Operation_0: i32, o_Operation_1: i32) => i32;
|
||||
};
|
||||
export namespace exports {
|
||||
export const functions: Map<string, $wcm.FunctionType> = new Map([
|
||||
['calc', $.exports.calc]
|
||||
]);
|
||||
export function bind(exports: Exports, context: $wcm.WasmContext): calculator.Exports {
|
||||
return $wcm.Exports.bind<calculator.Exports>(_, exports, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,164 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as $wcm from '@vscode/wasm-component-model';
|
||||
import type { u32, i32 } from '@vscode/wasm-component-model';
|
||||
|
||||
export namespace example {
|
||||
export namespace Types {
|
||||
export type Operands = {
|
||||
left: u32;
|
||||
right: u32;
|
||||
};
|
||||
|
||||
export namespace Operation {
|
||||
export const add = 'add' as const;
|
||||
export type Add = { readonly tag: typeof add; readonly value: Operands } & _common;
|
||||
export function Add(value: Operands): Add {
|
||||
return new VariantImpl(add, value) as Add;
|
||||
}
|
||||
|
||||
export const sub = 'sub' as const;
|
||||
export type Sub = { readonly tag: typeof sub; readonly value: Operands } & _common;
|
||||
export function Sub(value: Operands): Sub {
|
||||
return new VariantImpl(sub, value) as Sub;
|
||||
}
|
||||
|
||||
export const mul = 'mul' as const;
|
||||
export type Mul = { readonly tag: typeof mul; readonly value: Operands } & _common;
|
||||
export function Mul(value: Operands): Mul {
|
||||
return new VariantImpl(mul, value) as Mul;
|
||||
}
|
||||
|
||||
export const div = 'div' as const;
|
||||
export type Div = { readonly tag: typeof div; readonly value: Operands } & _common;
|
||||
export function Div(value: Operands): Div {
|
||||
return new VariantImpl(div, value) as Div;
|
||||
}
|
||||
|
||||
export type _tt = typeof add | typeof sub | typeof mul | typeof div;
|
||||
export type _vt = Operands | Operands | Operands | Operands;
|
||||
type _common = Omit<VariantImpl, 'tag' | 'value'>;
|
||||
export function _ctor(t: _tt, v: _vt): Operation {
|
||||
return new VariantImpl(t, v) as Operation;
|
||||
}
|
||||
class VariantImpl {
|
||||
private readonly _tag: _tt;
|
||||
private readonly _value: _vt;
|
||||
constructor(t: _tt, value: _vt) {
|
||||
this._tag = t;
|
||||
this._value = value;
|
||||
}
|
||||
get tag(): _tt {
|
||||
return this._tag;
|
||||
}
|
||||
get value(): _vt {
|
||||
return this._value;
|
||||
}
|
||||
isAdd(): this is Add {
|
||||
return this._tag === Operation.add;
|
||||
}
|
||||
isSub(): this is Sub {
|
||||
return this._tag === Operation.sub;
|
||||
}
|
||||
isMul(): this is Mul {
|
||||
return this._tag === Operation.mul;
|
||||
}
|
||||
isDiv(): this is Div {
|
||||
return this._tag === Operation.div;
|
||||
}
|
||||
}
|
||||
}
|
||||
export type Operation = Operation.Add | Operation.Sub | Operation.Mul | Operation.Div;
|
||||
}
|
||||
export type Types = {
|
||||
};
|
||||
export namespace calculator {
|
||||
export type Operation = Types.Operation;
|
||||
export type Imports = {
|
||||
log: (msg: string) => void;
|
||||
};
|
||||
export type Exports = {
|
||||
calc: (o: Operation) => u32;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace example {
|
||||
export namespace Types.$ {
|
||||
export const Operands = new $wcm.RecordType<example.Types.Operands>([
|
||||
['left', $wcm.u32],
|
||||
['right', $wcm.u32],
|
||||
]);
|
||||
export const Operation = new $wcm.VariantType<example.Types.Operation, example.Types.Operation._tt, example.Types.Operation._vt>([['add', Operands], ['sub', Operands], ['mul', Operands], ['div', Operands]], example.Types.Operation._ctor);
|
||||
}
|
||||
export namespace Types._ {
|
||||
export const id = 'vscode:example/types' as const;
|
||||
export const witName = 'types' as const;
|
||||
export const types: Map<string, $wcm.GenericComponentModelType> = new Map<string, $wcm.GenericComponentModelType>([
|
||||
['Operands', $.Operands],
|
||||
['Operation', $.Operation]
|
||||
]);
|
||||
}
|
||||
export namespace calculator.$ {
|
||||
export const Operation = Types.$.Operation;
|
||||
export namespace Imports {
|
||||
export const log = new $wcm.FunctionType<calculator.Imports['log']>('log',[
|
||||
['msg', $wcm.wstring],
|
||||
], undefined);
|
||||
}
|
||||
export namespace Exports {
|
||||
export const calc = new $wcm.FunctionType<calculator.Exports['calc']>('calc',[
|
||||
['o', Operation],
|
||||
], $wcm.u32);
|
||||
}
|
||||
}
|
||||
export namespace calculator._ {
|
||||
export const id = 'vscode:example/calculator' as const;
|
||||
export const witName = 'calculator' as const;
|
||||
export type $Root = {
|
||||
'log': (msg_ptr: i32, msg_len: i32) => void;
|
||||
}
|
||||
export namespace Imports {
|
||||
export const functions: Map<string, $wcm.FunctionType> = new Map([
|
||||
['log', $.Imports.log]
|
||||
]);
|
||||
export const interfaces: Map<string, $wcm.InterfaceType> = new Map<string, $wcm.InterfaceType>([
|
||||
['Types', Types._]
|
||||
]);
|
||||
}
|
||||
export type Imports = {
|
||||
'$root': $Root;
|
||||
};
|
||||
export namespace Exports {
|
||||
export const functions: Map<string, $wcm.FunctionType> = new Map([
|
||||
['calc', $.Exports.calc]
|
||||
]);
|
||||
}
|
||||
export type Exports = {
|
||||
'calc': (o_Operation_case: i32, o_Operation_0: i32, o_Operation_1: i32) => i32;
|
||||
};
|
||||
export function createImports(service: calculator.Imports, context: $wcm.WasmContext): Imports {
|
||||
const result: Imports = Object.create(null);
|
||||
result['$root'] = $wcm.Imports.create<$Root>(Imports.functions, undefined, service, context);
|
||||
return result;
|
||||
}
|
||||
export function bindExports(exports: Exports, context: $wcm.WasmContext): calculator.Exports {
|
||||
const result: calculator.Exports = Object.create(null);
|
||||
Object.assign(result, $wcm.Exports.bind(Exports.functions, undefined, exports, context));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace example._ {
|
||||
export const id = 'vscode:example' as const;
|
||||
export const witName = 'example' as const;
|
||||
export const interfaces: Map<string, $wcm.InterfaceType> = new Map<string, $wcm.InterfaceType>([
|
||||
['Types', Types._]
|
||||
]);
|
||||
export const worlds: Map<string, $wcm.WorldType> = new Map<string, $wcm.WorldType>([
|
||||
['calculator', calculator._]
|
||||
]);
|
||||
}
|
||||
@ -5,9 +5,8 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { WasmContext, Memory } from '@vscode/wasm-component-model';
|
||||
|
||||
import { example } from './example';
|
||||
import calculator = example.calculator;
|
||||
import Types = example.Types;
|
||||
// Import the code generated by wit2ts
|
||||
import { Types, calculator } from './calculator';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
// The channel for printing the result.
|
||||
@ -28,25 +27,32 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
||||
log: (msg: string) => {
|
||||
log.info(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The context for the WASM module
|
||||
const wasmContext: WasmContext.Default = new WasmContext.Default();
|
||||
|
||||
// Instantiate the module and create the necessary imports from the service implementation
|
||||
const instance = await WebAssembly.instantiate(module, calculator._.createImports(service, wasmContext));
|
||||
// Create the bindings to import the log function into the WASM module
|
||||
const imports = calculator._.imports.create(service, wasmContext);
|
||||
// Instantiate the module
|
||||
const instance = await WebAssembly.instantiate(module, imports);
|
||||
|
||||
// Bind the WASM memory to the context
|
||||
wasmContext.initialize(new Memory.Default(instance.exports));
|
||||
|
||||
// Bind the JavaScript Api
|
||||
const api = calculator._.bindExports(instance.exports as calculator._.Exports, wasmContext);
|
||||
// Bind the TypeScript Api
|
||||
const api = calculator._.exports.bind(instance.exports as calculator._.Exports, wasmContext);
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand('vscode-samples.wasm-component-model.run', () => {
|
||||
channel.show();
|
||||
channel.appendLine('Running calculator example');
|
||||
channel.appendLine(`Add ${api.calc(Types.Operation.Add({ left: 1, right: 2}))}`);
|
||||
channel.appendLine(`Sub ${api.calc(Types.Operation.Sub({ left: 10, right: 8 }))}`);
|
||||
channel.appendLine(`Mul ${api.calc(Types.Operation.Mul({ left: 3, right: 7 }))}`);
|
||||
channel.appendLine(`Div ${api.calc(Types.Operation.Div({ left: 10, right: 2 }))}`);
|
||||
const add = Types.Operation.Add({ left: 1, right: 2});
|
||||
channel.appendLine(`Add ${api.calc(add)}`);
|
||||
const sub = Types.Operation.Sub({ left: 10, right: 8 });
|
||||
channel.appendLine(`Sub ${api.calc(sub)}`);
|
||||
const mul = Types.Operation.Mul({ left: 3, right: 7 });
|
||||
channel.appendLine(`Mul ${api.calc(mul)}`);
|
||||
const div = Types.Operation.Div({ left: 10, right: 2 });
|
||||
channel.appendLine(`Div ${api.calc(div)}`);
|
||||
}));
|
||||
}
|
||||
@ -5,11 +5,11 @@ wit_bindgen::generate!({
|
||||
world: "calculator",
|
||||
});
|
||||
|
||||
struct MyType;
|
||||
struct Calculator;
|
||||
|
||||
impl Guest for MyType {
|
||||
impl Guest for Calculator {
|
||||
|
||||
fn calc(op: Operation) -> u32 {
|
||||
fn calc(op: Operation) -> u32 {
|
||||
log(&format!("Starting calculation: {:?}", op));
|
||||
let result = match op {
|
||||
Operation::Add(operands) => operands.left + operands.right,
|
||||
@ -18,8 +18,9 @@ impl Guest for MyType {
|
||||
Operation::Div(operands) => operands.left / operands.right,
|
||||
};
|
||||
log(&format!("Finished calculation: {:?}", op));
|
||||
return result;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
export!(MyType);
|
||||
// Export the Calculator to the extension code.
|
||||
export!(Calculator);
|
||||
20
wasm-language-server/client/package-lock.json
generated
20
wasm-language-server/client/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "client",
|
||||
"version": "1.0.0",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "client",
|
||||
"version": "1.0.0",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vscode/wasm-wasi-lsp": "0.1.0-pre.1"
|
||||
"@vscode/wasm-wasi-lsp": "0.1.0-pre.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.14.6",
|
||||
@ -52,15 +52,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/wasm-wasi-lsp": {
|
||||
"version": "0.1.0-pre.1",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/wasm-wasi-lsp/-/wasm-wasi-lsp-0.1.0-pre.1.tgz",
|
||||
"integrity": "sha512-xB6Jjo7v1JnJsxH18/d1GyhXqi3wqLe20cyvfQQp2XOKzapgGJC+CGL+Hc5w3BubOKwwcbHe6mtaMEKgArrv5A==",
|
||||
"version": "0.1.0-pre.3",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/wasm-wasi-lsp/-/wasm-wasi-lsp-0.1.0-pre.3.tgz",
|
||||
"integrity": "sha512-3qgroKPvPKNcXd8Nl7DQINqSQtAoQ/6dix/X3b2fgdgJyBkISz/gNK5HfLBBC06lFCZlwP5gpaj1nx64No2y3A==",
|
||||
"engines": {
|
||||
"node": ">=18.18.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vscode/wasm-wasi": "0.13.0-pre.1",
|
||||
"vscode-languageclient": "10.0.0-next.3"
|
||||
"vscode-languageclient": "10.0.0-next.5"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
@ -260,9 +260,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageclient": {
|
||||
"version": "10.0.0-next.3",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-10.0.0-next.3.tgz",
|
||||
"integrity": "sha512-jJhPdZaiELpPRnCUt8kQcF2HJuvzLgeW4HOGc6dp8Je+p08ndueVT4fpSsbly6KiEHr/Ri73tNz0CSfsOye6MA==",
|
||||
"version": "10.0.0-next.5",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-10.0.0-next.5.tgz",
|
||||
"integrity": "sha512-JIf1WE7fvV0RElFM062bAummI433vcxuFwqoYAp+1zTVhta/jznxkTz1zs3Hbj2tiDfclf0TZ0qCxflAP1mY2Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"minimatch": "^9.0.3",
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"description": "The language client",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"version": "0.1.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode-extension-samples"
|
||||
@ -22,7 +22,7 @@
|
||||
"main": "./out/extension",
|
||||
"browser": "./dist/web/extension",
|
||||
"dependencies": {
|
||||
"@vscode/wasm-wasi-lsp": "0.1.0-pre.1"
|
||||
"@vscode/wasm-wasi-lsp": "0.1.0-pre.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "1.88.0",
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import { ExtensionContext, Uri, window, workspace } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node';
|
||||
import { ExtensionContext, Uri, window, workspace, commands } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions, RequestType } from 'vscode-languageclient/node';
|
||||
import { Wasm, ProcessOptions } from '@vscode/wasm-wasi';
|
||||
import { createStdioOptions, startServer } from '@vscode/wasm-wasi-lsp';
|
||||
|
||||
@ -46,6 +46,17 @@ export async function activate(context: ExtensionContext) {
|
||||
} catch (error) {
|
||||
client.error(`Start failed`, error, 'force');
|
||||
}
|
||||
|
||||
type CountFileParams = { folder: string };
|
||||
const CountFilesRequest = new RequestType<CountFileParams, number, void>('wasm-language-server/countFilesInFolder');
|
||||
context.subscriptions.push(commands.registerCommand('vscode-samples.wasm-language-server.countFiles', async () => {
|
||||
// We assume we do have a folder.
|
||||
const folder = workspace.workspaceFolders![0].uri;
|
||||
// We need to convert the folder URI to a URI that maps to the mounted WASI file system. This is something
|
||||
// @vscode/wasm-wasi-lsp does for us.
|
||||
const result = await client.sendRequest(CountFilesRequest, { folder: client.code2ProtocolConverter.asUri(folder!) });
|
||||
window.showInformationMessage(`The workspace contains ${result} files.`);
|
||||
}));
|
||||
}
|
||||
|
||||
export function deactivate() {
|
||||
|
||||
@ -27,6 +27,15 @@
|
||||
"extensionDependencies": [
|
||||
"ms-vscode.wasm-wasi-core"
|
||||
],
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "vscode-samples.wasm-language-server.countFiles",
|
||||
"category": "Samples",
|
||||
"title": "Count Files"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
51
wasm-language-server/server/Cargo.lock
generated
51
wasm-language-server/server/Cargo.lock
generated
@ -109,6 +109,15 @@ version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
@ -159,6 +168,7 @@ dependencies = [
|
||||
"lsp-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -219,3 +229,44 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
@ -8,5 +8,6 @@ edition = "2021"
|
||||
[dependencies]
|
||||
lsp-server = "0.7.6"
|
||||
lsp-types = "0.95.1"
|
||||
walkdir = "2"
|
||||
serde = "1.0.189"
|
||||
serde_json = "1.0.107"
|
||||
@ -4,13 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
use std::error::Error;
|
||||
|
||||
use lsp_types::OneOf;
|
||||
use lsp_types::{
|
||||
request::GotoDefinition, GotoDefinitionResponse, InitializeParams, ServerCapabilities,
|
||||
Location
|
||||
request::GotoDefinition, GotoDefinitionResponse, InitializeParams,
|
||||
ServerCapabilities, Location, OneOf
|
||||
};
|
||||
|
||||
use lsp_server::{Connection, ExtractError, Message, Request, RequestId, Response};
|
||||
use lsp_server::{ Connection, ExtractError, Message, RequestId, Response };
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
// Note that we must have our logging only write out to stderr.
|
||||
@ -35,10 +33,7 @@ fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main_loop(
|
||||
connection: Connection,
|
||||
params: serde_json::Value,
|
||||
) -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
fn main_loop(connection: Connection, params: serde_json::Value) -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
let _params: InitializeParams = serde_json::from_value(params).unwrap();
|
||||
for msg in &connection.receiver {
|
||||
match msg {
|
||||
@ -61,7 +56,6 @@ fn main_loop(
|
||||
Err(err @ ExtractError::JsonError { .. }) => panic!("{err:?}"),
|
||||
Err(ExtractError::MethodMismatch(req)) => req,
|
||||
};
|
||||
// ...
|
||||
}
|
||||
Message::Response(resp) => {
|
||||
eprintln!("got response: {resp:?}");
|
||||
@ -74,10 +68,10 @@ fn main_loop(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cast<R>(req: Request) -> Result<(RequestId, R::Params), ExtractError<Request>>
|
||||
fn cast<R>(req: lsp_server::Request) -> Result<(RequestId, R::Params), ExtractError<lsp_server::Request>>
|
||||
where
|
||||
R: lsp_types::request::Request,
|
||||
R::Params: serde::de::DeserializeOwned,
|
||||
{
|
||||
req.extract(R::METHOD)
|
||||
}
|
||||
}
|
||||
1
wasm-language-server/testbed/workspace/test.txt
Normal file
1
wasm-language-server/testbed/workspace/test.txt
Normal file
@ -0,0 +1 @@
|
||||
Some text.
|
||||
Reference in New Issue
Block a user