feat: add a histrical wit-bindgen
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "wit-bindgen-demo"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
crate-type = ['cdylib']
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
wit-bindgen-gen-core = { path = '../gen-core' }
|
||||
wit-bindgen-gen-rust-wasm = { path = '../gen-rust-wasm' }
|
||||
wit-bindgen-gen-wasmtime = { path = '../gen-wasmtime' }
|
||||
wit-bindgen-gen-wasmtime-py = { path = '../gen-wasmtime-py' }
|
||||
wit-bindgen-gen-js = { path = '../gen-js' }
|
||||
wit-bindgen-gen-c = { path = '../gen-c' }
|
||||
wit-bindgen-gen-markdown = { path = '../gen-markdown' }
|
||||
wit-bindgen-gen-spidermonkey = { path = '../gen-spidermonkey' }
|
||||
wit-bindgen-rust = { path = '../rust-wasm' }
|
||||
wasmprinter = "0.2.29"
|
||||
@@ -0,0 +1,2 @@
|
||||
log: func(msg: string)
|
||||
error: func(msg: string)
|
||||
26
__wasm/wit-bindgen-sample/wit-bindgen/crates/wit-bindgen-demo/build.sh
Executable file
26
__wasm/wit-bindgen-sample/wit-bindgen/crates/wit-bindgen-demo/build.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
rm -rf static
|
||||
mkdir static
|
||||
|
||||
cargo build -p wit-bindgen-demo --target wasm32-unknown-unknown --release
|
||||
cp target/wasm32-unknown-unknown/release/wit_bindgen_demo.wasm static/demo.wasm
|
||||
|
||||
cargo run js \
|
||||
--export crates/wit-bindgen-demo/browser.wit \
|
||||
--import crates/wit-bindgen-demo/demo.wit \
|
||||
--out-dir static
|
||||
|
||||
cp crates/wit-bindgen-demo/{index.html,main.ts} static/
|
||||
(cd crates/wit-bindgen-demo && npx tsc ../../static/main.ts --target es6)
|
||||
|
||||
if [ ! -d ace ]; then
|
||||
mkdir ace
|
||||
cd ace
|
||||
curl -L https://github.com/ajaxorg/ace-builds/archive/refs/tags/v1.4.12.tar.gz | tar xzf -
|
||||
cd ..
|
||||
fi
|
||||
|
||||
cp -r ace/ace-builds-1.4.12/src static/ace
|
||||
@@ -0,0 +1,29 @@
|
||||
type files = list<tuple<string, string>>
|
||||
|
||||
variant wasmtime-async {
|
||||
all,
|
||||
none,
|
||||
only(list<string>),
|
||||
}
|
||||
|
||||
enum lang {
|
||||
js,
|
||||
rust,
|
||||
wasmtime,
|
||||
wasmtime-py,
|
||||
c,
|
||||
markdown,
|
||||
spidermonkey,
|
||||
}
|
||||
|
||||
|
||||
resource config {
|
||||
static new: func() -> config
|
||||
|
||||
render: func(lang: lang, wit: string, import: bool) -> expected<files, string>
|
||||
|
||||
set-rust-unchecked: func(unchecked: bool)
|
||||
set-wasmtime-tracing: func(unchecked: bool)
|
||||
set-wasmtime-async: func(val: wasmtime-async)
|
||||
set-wasmtime-custom-error: func(custom: bool)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<style type="text/css" media="screen">
|
||||
body {
|
||||
display: flex;
|
||||
min-height: 800px;
|
||||
}
|
||||
|
||||
.area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.editor{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.options {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.lang-configure {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='area'>
|
||||
<h1>Input <code>*.wit</code></h1>
|
||||
<div class='editor' id='input'></div>
|
||||
<textarea id='input-raw' style='display:none'>
|
||||
record person {
|
||||
name: string,
|
||||
age: u32,
|
||||
}
|
||||
hello: func(who: person) -> string
|
||||
</textarea>
|
||||
</div>
|
||||
<div class='area'>
|
||||
<h1>Generated bindings</h1>
|
||||
|
||||
<div class='options'>
|
||||
<label for="language-select">Language:</label>
|
||||
|
||||
<select name="language" id="language-select">
|
||||
<option value="js">JavaScript</option>
|
||||
<option value="rust">Rust</option>
|
||||
<option value="wasmtime">Wasmtime</option>
|
||||
<option value="wasmtime-py">Wasmtime (Python)</option>
|
||||
<option value="c">C</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
<option value="spidermonkey">SpiderMonkey</option>
|
||||
</select>
|
||||
|
||||
·
|
||||
|
||||
<label for="mode-select">Mode:</label>
|
||||
|
||||
<select name="mode" id="mode-select">
|
||||
<option value="import">import</option>
|
||||
<option value="export">export</option>
|
||||
</select>
|
||||
|
||||
·
|
||||
|
||||
<label for="file-select">File:</label>
|
||||
<select name="file" id="file-select">
|
||||
</select>
|
||||
|
||||
<div id='configure-js' class='lang-configure'>
|
||||
</div>
|
||||
<div id='configure-c' class='lang-configure'>
|
||||
</div>
|
||||
<div id='configure-markdown' class='lang-configure'>
|
||||
</div>
|
||||
<div id='configure-wasmtime-py' class='lang-configure'>
|
||||
</div>
|
||||
<div id='configure-rust' class='lang-configure'>
|
||||
·
|
||||
|
||||
<input type="checkbox" id="rust-unchecked" name="unchecked">
|
||||
<label for="rust-unchecked">Unchecked</label>
|
||||
</div>
|
||||
<div id='configure-wasmtime' class='lang-configure'>
|
||||
·
|
||||
|
||||
<input type="checkbox" id="wasmtime-tracing" name="tracing">
|
||||
<label for="wasmtime-tracing"><code>tracing</code></label>
|
||||
|
||||
·
|
||||
|
||||
<input type="checkbox" id="wasmtime-async" name="async">
|
||||
<label for="wasmtime-async"><code>async</code></label>
|
||||
|
||||
·
|
||||
|
||||
<input type="checkbox" id="wasmtime-custom-error" name="custom-error">
|
||||
<label for="wasmtime-custom-error">custom error</label>
|
||||
</div>
|
||||
<div id='configure-spidermonkey' class='lang-configure'>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='editor' id='output'></div>
|
||||
<div id='html-output'></div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="ace/ace.js"></script>
|
||||
<script src='main.js' type=module></script>
|
||||
</html>
|
||||
@@ -0,0 +1,182 @@
|
||||
import { Demo, Config } from './demo.js';
|
||||
import * as browser from './browser.js';
|
||||
|
||||
class Editor {
|
||||
input: HTMLTextAreaElement;
|
||||
language: HTMLSelectElement;
|
||||
mode: HTMLSelectElement;
|
||||
files: HTMLSelectElement
|
||||
rustUnchecked: HTMLInputElement;
|
||||
wasmtimeTracing: HTMLInputElement;
|
||||
wasmtimeAsync: HTMLInputElement;
|
||||
wasmtimeCustomError: HTMLInputElement;
|
||||
generatedFiles: Record<string, string>;
|
||||
demo: Demo;
|
||||
config: Config | null;
|
||||
rerender: number | null;
|
||||
inputEditor: AceAjax.Editor;
|
||||
outputEditor: AceAjax.Editor;
|
||||
outputHtml: HTMLDivElement;
|
||||
|
||||
constructor() {
|
||||
this.input = document.getElementById('input-raw') as HTMLTextAreaElement;
|
||||
this.language = document.getElementById('language-select') as HTMLSelectElement;
|
||||
this.mode = document.getElementById('mode-select') as HTMLSelectElement;
|
||||
this.files = document.getElementById('file-select') as HTMLSelectElement;
|
||||
this.rustUnchecked = document.getElementById('rust-unchecked') as HTMLInputElement;
|
||||
this.wasmtimeTracing = document.getElementById('wasmtime-tracing') as HTMLInputElement;
|
||||
this.wasmtimeAsync = document.getElementById('wasmtime-async') as HTMLInputElement;
|
||||
this.wasmtimeCustomError = document.getElementById('wasmtime-custom-error') as HTMLInputElement;
|
||||
this.outputHtml = document.getElementById('html-output') as HTMLDivElement;
|
||||
|
||||
this.inputEditor = ace.edit("input");
|
||||
this.outputEditor = ace.edit("output");
|
||||
this.inputEditor.setValue(this.input.value);
|
||||
this.inputEditor.clearSelection();
|
||||
this.outputEditor.setReadOnly(true);
|
||||
this.inputEditor.setOption("useWorker", false);
|
||||
this.outputEditor.setOption("useWorker", false);
|
||||
|
||||
this.generatedFiles = {};
|
||||
this.demo = new Demo();
|
||||
this.config = null;
|
||||
this.rerender = null;
|
||||
}
|
||||
|
||||
async instantiate() {
|
||||
const imports = {};
|
||||
const obj = {
|
||||
log: console.log,
|
||||
error: console.error,
|
||||
};
|
||||
browser.addBrowserToImports(imports, obj, name => this.demo.instance.exports[name]);
|
||||
await this.demo.instantiate(fetch('./demo.wasm'), imports);
|
||||
this.config = Config.new(this.demo);
|
||||
this.installListeners();
|
||||
this.render();
|
||||
}
|
||||
|
||||
installListeners() {
|
||||
this.inputEditor.on('change', () => {
|
||||
this.input.value = this.inputEditor.getValue();
|
||||
if (this.rerender !== null)
|
||||
clearTimeout(this.rerender);
|
||||
this.rerender = setTimeout(() => this.render(), 500);
|
||||
});
|
||||
|
||||
this.language.addEventListener('change', () => this.render());
|
||||
this.mode.addEventListener('change', () => this.render());
|
||||
|
||||
this.rustUnchecked.addEventListener('change', () => {
|
||||
this.config.setRustUnchecked(this.rustUnchecked.checked);
|
||||
this.render();
|
||||
});
|
||||
|
||||
this.wasmtimeTracing.addEventListener('change', () => {
|
||||
this.config.setWasmtimeTracing(this.wasmtimeTracing.checked);
|
||||
this.render();
|
||||
});
|
||||
this.wasmtimeAsync.addEventListener('change', () => {
|
||||
let async_;
|
||||
if (this.wasmtimeAsync.checked)
|
||||
async_ = { tag: 'all' };
|
||||
else
|
||||
async_ = { tag: 'none' };
|
||||
this.config.setWasmtimeAsync(async_);
|
||||
this.render();
|
||||
});
|
||||
this.wasmtimeCustomError.addEventListener('change', () => {
|
||||
this.config.setWasmtimeCustomError(this.wasmtimeCustomError.checked);
|
||||
this.render();
|
||||
});
|
||||
this.files.addEventListener('change', () => this.updateSelectedFile());
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
for (let div of document.querySelectorAll('.lang-configure')) {
|
||||
(div as HTMLDivElement).style.display = 'none';
|
||||
}
|
||||
|
||||
const config = document.getElementById(`configure-${this.language.value}`);
|
||||
config.style.display = 'inline-block';
|
||||
|
||||
const wit = this.inputEditor.getValue();
|
||||
const is_import = this.mode.value === 'import';
|
||||
let lang;
|
||||
switch (this.language.value) {
|
||||
case "js":
|
||||
case "rust":
|
||||
case "wasmtime":
|
||||
case "wasmtime-py":
|
||||
case "c":
|
||||
case "markdown":
|
||||
case "spidermonkey":
|
||||
lang = this.language.value;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
const result = this.config.render(lang, wit, is_import);
|
||||
if (result.tag === 'err') {
|
||||
this.outputEditor.setValue(result.val);
|
||||
this.outputEditor.clearSelection();
|
||||
this.showOutputEditor();
|
||||
return;
|
||||
}
|
||||
this.generatedFiles = {};
|
||||
const selectedFile = this.files.value;
|
||||
this.files.options.length = 0;
|
||||
for (let i = 0; i < result.val.length; i++) {
|
||||
const name = result.val[i][0];
|
||||
const contents = result.val[i][1];
|
||||
this.files.options[i] = new Option(name, name);
|
||||
this.generatedFiles[name] = contents;
|
||||
}
|
||||
if (selectedFile in this.generatedFiles)
|
||||
this.files.value = selectedFile;
|
||||
|
||||
this.updateSelectedFile();
|
||||
}
|
||||
|
||||
showOutputEditor() {
|
||||
this.outputHtml.style.display = 'none';
|
||||
document.getElementById('output').style.display = 'block';
|
||||
}
|
||||
|
||||
showOutputHtml() {
|
||||
this.outputHtml.style.display = 'block';
|
||||
document.getElementById('output').style.display = 'none';
|
||||
}
|
||||
|
||||
updateSelectedFile() {
|
||||
if (this.files.value.endsWith('.html')) {
|
||||
const html = this.generatedFiles[this.files.value];
|
||||
this.outputHtml.innerHTML = html;
|
||||
this.showOutputHtml();
|
||||
return;
|
||||
}
|
||||
|
||||
this.showOutputEditor();
|
||||
this.outputEditor.setValue(this.generatedFiles[this.files.value]);
|
||||
this.outputEditor.clearSelection();
|
||||
if (this.files.value.endsWith('.d.ts'))
|
||||
this.outputEditor.session.setMode("ace/mode/typescript");
|
||||
else if (this.files.value.endsWith('.js'))
|
||||
this.outputEditor.session.setMode("ace/mode/javascript");
|
||||
else if (this.files.value.endsWith('.rs'))
|
||||
this.outputEditor.session.setMode("ace/mode/rust");
|
||||
else if (this.files.value.endsWith('.c'))
|
||||
this.outputEditor.session.setMode("ace/mode/c_cpp");
|
||||
else if (this.files.value.endsWith('.h'))
|
||||
this.outputEditor.session.setMode("ace/mode/c_cpp");
|
||||
else if (this.files.value.endsWith('.md'))
|
||||
this.outputEditor.session.setMode("ace/mode/markdown");
|
||||
else if (this.files.value.endsWith('.py'))
|
||||
this.outputEditor.session.setMode("ace/mode/python");
|
||||
else
|
||||
this.outputEditor.session.setMode(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
(new Editor()).instantiate()
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@types/ace": "^0.0.46",
|
||||
"typescript": "^4.3.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Once;
|
||||
use wit_bindgen_gen_core::wit_parser::Interface;
|
||||
use wit_bindgen_gen_core::Generator;
|
||||
use wit_bindgen_rust::Handle;
|
||||
|
||||
wit_bindgen_rust::export!("demo.wit");
|
||||
wit_bindgen_rust::import!("browser.wit");
|
||||
|
||||
struct Demo;
|
||||
|
||||
impl demo::Demo for Demo {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Config {
|
||||
js: RefCell<wit_bindgen_gen_js::Opts>,
|
||||
c: RefCell<wit_bindgen_gen_c::Opts>,
|
||||
rust: RefCell<wit_bindgen_gen_rust_wasm::Opts>,
|
||||
wasmtime: RefCell<wit_bindgen_gen_wasmtime::Opts>,
|
||||
wasmtime_py: RefCell<wit_bindgen_gen_wasmtime_py::Opts>,
|
||||
markdown: RefCell<wit_bindgen_gen_markdown::Opts>,
|
||||
spidermonkey: RefCell<wit_bindgen_gen_spidermonkey::Opts>,
|
||||
}
|
||||
|
||||
impl demo::Config for Config {
|
||||
fn new() -> Handle<Config> {
|
||||
static INIT: Once = Once::new();
|
||||
INIT.call_once(|| {
|
||||
let prev_hook = std::panic::take_hook();
|
||||
std::panic::set_hook(Box::new(move |info| {
|
||||
browser::error(&info.to_string());
|
||||
prev_hook(info);
|
||||
}));
|
||||
});
|
||||
|
||||
Config::default().into()
|
||||
}
|
||||
|
||||
fn render(
|
||||
&self,
|
||||
lang: demo::Lang,
|
||||
wit: String,
|
||||
import: bool,
|
||||
) -> Result<Vec<(String, String)>, String> {
|
||||
let mut gen: Box<dyn Generator> = match lang {
|
||||
demo::Lang::Rust => Box::new(self.rust.borrow().clone().build()),
|
||||
demo::Lang::Wasmtime => Box::new(self.wasmtime.borrow().clone().build()),
|
||||
demo::Lang::WasmtimePy => Box::new(self.wasmtime_py.borrow().clone().build()),
|
||||
demo::Lang::Js => Box::new(self.js.borrow().clone().build()),
|
||||
demo::Lang::C => Box::new(self.c.borrow().clone().build()),
|
||||
demo::Lang::Markdown => Box::new(self.markdown.borrow().clone().build()),
|
||||
demo::Lang::Spidermonkey => {
|
||||
let mut opts = self.spidermonkey.borrow_mut();
|
||||
opts.import_spidermonkey = true;
|
||||
opts.js = "foo.js".into();
|
||||
let script = "throw new Error('unimplemented');";
|
||||
Box::new(opts.clone().build(script))
|
||||
}
|
||||
};
|
||||
let iface = Interface::parse("input", &wit).map_err(|e| format!("{:?}", e))?;
|
||||
let mut files = Default::default();
|
||||
let (imports, exports) = if import {
|
||||
(vec![iface], vec![])
|
||||
} else {
|
||||
(vec![], vec![iface])
|
||||
};
|
||||
gen.generate_all(&imports, &exports, &mut files);
|
||||
Ok(files
|
||||
.iter()
|
||||
.map(|(name, contents)| {
|
||||
let contents = if contents.starts_with(b"\0asm") {
|
||||
wasmprinter::print_bytes(contents).unwrap()
|
||||
} else {
|
||||
String::from_utf8_lossy(&contents).into()
|
||||
};
|
||||
(name.to_string(), contents)
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn set_rust_unchecked(&self, unchecked: bool) {
|
||||
self.rust.borrow_mut().unchecked = unchecked;
|
||||
}
|
||||
|
||||
fn set_wasmtime_tracing(&self, tracing: bool) {
|
||||
self.wasmtime.borrow_mut().tracing = tracing;
|
||||
}
|
||||
fn set_wasmtime_custom_error(&self, custom_error: bool) {
|
||||
browser::log("custom error");
|
||||
self.wasmtime.borrow_mut().custom_error = custom_error;
|
||||
}
|
||||
fn set_wasmtime_async(&self, async_: demo::WasmtimeAsync) {
|
||||
use wit_bindgen_gen_wasmtime::Async;
|
||||
|
||||
self.wasmtime.borrow_mut().async_ = match async_ {
|
||||
demo::WasmtimeAsync::All => Async::All,
|
||||
demo::WasmtimeAsync::None => Async::None,
|
||||
demo::WasmtimeAsync::Only(list) => Async::Only(list.into_iter().collect()),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user