Skip to content

Instantly share code, notes, and snippets.

@saolsen
Last active December 26, 2023 00:29
Show Gist options
  • Select an option

  • Save saolsen/d273bb1baba5e912e4dc2b187511affa to your computer and use it in GitHub Desktop.

Select an option

Save saolsen/d273bb1baba5e912e4dc2b187511affa to your computer and use it in GitHub Desktop.

Revisions

  1. saolsen revised this gist Dec 20, 2023. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion .Rust_Vals.md
    Original file line number Diff line number Diff line change
    @@ -16,4 +16,7 @@ Requires rust, wasm-pack and deno.
    * https://www.val.town/v/saolsen/example_rust_val

    ## Val that uses it
    * https://www.val.town/v/saolsen/use_example_rust_val
    * https://www.val.town/v/saolsen/use_example_rust_val

    ## Another example that is an http val.
    * https://gist.github.com/saolsen/294683088bae9a8f9a8cf93e2b392729
  2. saolsen revised this gist Dec 20, 2023. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion .Rust_Vals.md
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,8 @@ Requires rust, wasm-pack and deno.
    * `deno run --allow-read --allow-write package.ts`
    * Copy the code in `val.ts` to your val.

    ## Val made from this gist and val that uses it.
    ## Val made from this gist
    * https://www.val.town/v/saolsen/example_rust_val

    ## Val that uses it
    * https://www.val.town/v/saolsen/use_example_rust_val
  3. saolsen revised this gist Dec 20, 2023. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions .Rust_Vals.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,8 @@
    # Make a [Val](https://www.val.town/) with rust.

    Build a https://www.val.town/ val with rust.
    This is an example of how to compile a rust file to wasm and use it as a val.

    Requires rust, wasm-pack and deno.

    ## Usage
  4. saolsen revised this gist Dec 20, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion .Rust_Vals.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Make a val with rust.
    # Make a [Val](https://www.val.town/) with rust.

    Requires rust, wasm-pack and deno.

  5. saolsen revised this gist Dec 20, 2023. 1 changed file with 0 additions and 4 deletions.
    4 changes: 0 additions & 4 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -1,4 +0,0 @@
    .vscode
    target
    pkg
    Cargo.lock
  6. saolsen revised this gist Dec 20, 2023. 3 changed files with 17 additions and 13 deletions.
    4 changes: 4 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    .vscode
    target
    pkg
    Cargo.lock
    16 changes: 7 additions & 9 deletions package.ts
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,12 @@ if (js_file === null) {
    }

    const patched =
    'import * as base64 from "https://deno.land/std/encoding/base64.ts";\n' +
    "" +
    `import * as base64 from "https://deno.land/std/encoding/base64.ts"\n\n` +
    `const bytes = base64.decodeBase64(\n` +
    ` // base64 encoded wasm module\n` +
    ` ${JSON.stringify(encoded)}\n` +
    `);\n\n` +
    js_file
    .replace("let imports = {};", "let imports: any = {};")
    // use global TextDecoder TextEncoder
    @@ -34,14 +39,7 @@ const patched =
    .replace(/\nmodule\.exports\.(.*?)\s+/g, "\nexport const $1 = imports.$1 ")
    .replace(/$/, "export default imports")
    // inline bytes Uint8Array
    .replace(
    /\nconst path.*\nconst bytes.*\n/,
    `
    const bytes = base64.decodeBase64(
    ${JSON.stringify(encoded)}
    );
    `
    );
    .replace(/\nconst path.*\nconst bytes.*\n/, "");

    const encoder = new TextEncoder();
    await Deno.writeFile(`./val.ts`, encoder.encode(patched));
    10 changes: 6 additions & 4 deletions val.ts
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,10 @@
    import * as base64 from "https://deno.land/std/encoding/base64.ts";

    const bytes = base64.decodeBase64(
    // base64 encoded wasm module
    "AGFzbQEAAAABDwNgAn9/AGAAAGACf38BfwI3ARhfX3diaW5kZ2VuX3BsYWNlaG9sZGVyX18aX193YmdfbG9nXzA4ODUwZDZkNGQ5MWY0YzkAAAMDAgECBQMBABEHHAMGbWVtb3J5AgADYWRkAAIJc2F5X2hlbGxvAAEKFQILAEGAgMAAQRoQAAsHACAAIAFqCwsjAQBBgIDAAAsaSGVsbG8gZnJvbSBSdXN0LCBpdCB3b3JrcyEAbwlwcm9kdWNlcnMCCGxhbmd1YWdlAQRSdXN0AAxwcm9jZXNzZWQtYnkDBXJ1c3RjHTEuNzIuMCAoNTY4MGZhMThmIDIwMjMtMDgtMjMpBndhbHJ1cwYwLjIwLjMMd2FzbS1iaW5kZ2VuBjAuMi44OQAsD3RhcmdldF9mZWF0dXJlcwIrD211dGFibGUtZ2xvYmFscysIc2lnbi1leHQ="
    );

    let imports: any = {};
    imports["__wbindgen_placeholder__"] = imports;
    let wasm;
    @@ -45,10 +51,6 @@ export const __wbg_log_08850d6d4d91f4c9 = (imports.__wbg_log_08850d6d4d91f4c9 =
    console.log(getStringFromWasm0(arg0, arg1));
    });

    const bytes = base64.decodeBase64(
    "AGFzbQEAAAABDwNgAn9/AGAAAGACf38BfwI3ARhfX3diaW5kZ2VuX3BsYWNlaG9sZGVyX18aX193YmdfbG9nXzA4ODUwZDZkNGQ5MWY0YzkAAAMDAgECBQMBABEHHAMGbWVtb3J5AgADYWRkAAIJc2F5X2hlbGxvAAEKFQILAEGAgMAAQRoQAAsHACAAIAFqCwsjAQBBgIDAAAsaSGVsbG8gZnJvbSBSdXN0LCBpdCB3b3JrcyEAbwlwcm9kdWNlcnMCCGxhbmd1YWdlAQRSdXN0AAxwcm9jZXNzZWQtYnkDBXJ1c3RjHTEuNzIuMCAoNTY4MGZhMThmIDIwMjMtMDgtMjMpBndhbHJ1cwYwLjIwLjMMd2FzbS1iaW5kZ2VuBjAuMi44OQAsD3RhcmdldF9mZWF0dXJlcwIrD211dGFibGUtZ2xvYmFscysIc2lnbi1leHQ="
    );

    const wasmModule = new WebAssembly.Module(bytes);
    const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
    wasm = wasmInstance.exports;
  7. saolsen renamed this gist Dec 20, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  8. saolsen revised this gist Dec 20, 2023. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions util.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    pub fn set_panic_hook() {
    // When the `console_error_panic_hook` feature is enabled, we can call the
    // `set_panic_hook` function at least once during initialization, and then
    // we will get better error messages if our code ever panics.
    //
    // For more details see
    // https://github.com/rustwasm/console_error_panic_hook#readme
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
    }
  9. saolsen revised this gist Dec 20, 2023. 6 changed files with 123 additions and 48 deletions.
    2 changes: 2 additions & 0 deletions Cargo.toml
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,8 @@ version = "0.1.0"
    edition = "2018"

    [lib]
    name="rust_val"
    path="val.rs"
    crate-type = ["cdylib", "rlib"]

    [features]
    14 changes: 14 additions & 0 deletions _README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    # Make a val with rust.

    Requires rust, wasm-pack and deno.

    ## Usage
    * Put your code in `val.rs`.
    * Build it.
    * `wasm-pack build --target nodejs`
    * `deno run --allow-read --allow-write package.ts`
    * Copy the code in `val.ts` to your val.

    ## Val made from this gist and val that uses it.
    * https://www.val.town/v/saolsen/example_rust_val
    * https://www.val.town/v/saolsen/use_example_rust_val
    45 changes: 0 additions & 45 deletions package.mjs
    Original file line number Diff line number Diff line change
    @@ -1,45 +0,0 @@
    import { readFile, writeFile } from "node:fs/promises";

    const cargoTomlContent = await readFile("./Cargo.toml", "utf8");
    const cargoPackageName = /\[package\]\nname = "(.*?)"/.exec(
    cargoTomlContent
    )[1];
    const name = cargoPackageName.replace(/-/g, "_");

    const content = await readFile(`./dist/pkg/${name}.js`, "utf8");

    const patched = content
    // use global TextDecoder TextEncoder
    .replace("require(`util`)", "globalThis")
    // attach to `imports` instead of module.exports
    .replace("= module.exports", "= imports")
    .replace(/\nmodule\.exports\.(.*?)\s+/g, "\nexport const $1 = imports.$1 ")
    .replace(/$/, "export default imports")
    // inline bytes Uint8Array
    .replace(
    /\nconst path.*\nconst bytes.*\n/,
    `
    var __toBinary = /* @__PURE__ */ (() => {
    var table = new Uint8Array(128);
    for (var i = 0; i < 64; i++)
    table[i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i * 4 - 205] = i;
    return (base64) => {
    var n = base64.length, bytes = new Uint8Array((n - (base64[n - 1] == "=") - (base64[n - 2] == "=")) * 3 / 4 | 0);
    for (var i2 = 0, j = 0; i2 < n; ) {
    var c0 = table[base64.charCodeAt(i2++)], c1 = table[base64.charCodeAt(i2++)];
    var c2 = table[base64.charCodeAt(i2++)], c3 = table[base64.charCodeAt(i2++)];
    bytes[j++] = c0 << 2 | c1 >> 4;
    bytes[j++] = c1 << 4 | c2 >> 2;
    bytes[j++] = c2 << 6 | c3;
    }
    return bytes;
    };
    })();
    const bytes = __toBinary(${JSON.stringify(
    await readFile(`./dist/pkg/${name}_bg.wasm`, "base64")
    )});
    `
    );

    await writeFile(`./dist/${name}.mjs`, patched);
    47 changes: 47 additions & 0 deletions package.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    import * as base64 from "https://deno.land/std@0.207.0/encoding/base64.ts";

    const decoder = new TextDecoder("utf-8");
    const cargo_file = decoder.decode(await Deno.readFile("./Cargo.toml"));
    if (cargo_file === null) {
    throw new Error("Cargo.toml not found");
    }
    const cargo_package = /\[package\]\nname = "(.*?)"/.exec(cargo_file);
    if (cargo_package === null) {
    throw new Error("Cargo.toml is invalid");
    }
    const cargo_package_name = cargo_package[1];
    const name = cargo_package_name.replace(/-/g, "_");

    const bytes = await Deno.readFile(`./pkg/${name}_bg.wasm`);
    if (bytes === null) {
    throw new Error(`pkg/${name}_bg.wasm not found`);
    }
    const encoded = base64.encodeBase64(bytes);

    const js_file = decoder.decode(await Deno.readFile(`./pkg/${name}.js`));
    if (js_file === null) {
    throw new Error(`pkg/${name}.js not found`);
    }

    const patched =
    'import * as base64 from "https://deno.land/std/encoding/base64.ts";\n' +
    js_file
    .replace("let imports = {};", "let imports: any = {};")
    // use global TextDecoder TextEncoder
    .replace("require(`util`)", "globalThis")
    // attach to `imports` instead of module.exports
    .replace("= module.exports", "= imports")
    .replace(/\nmodule\.exports\.(.*?)\s+/g, "\nexport const $1 = imports.$1 ")
    .replace(/$/, "export default imports")
    // inline bytes Uint8Array
    .replace(
    /\nconst path.*\nconst bytes.*\n/,
    `
    const bytes = base64.decodeBase64(
    ${JSON.stringify(encoded)}
    );
    `
    );

    const encoder = new TextEncoder();
    await Deno.writeFile(`./val.ts`, encoder.encode(patched));
    6 changes: 3 additions & 3 deletions val.rs
    Original file line number Diff line number Diff line change
    @@ -1,16 +1,16 @@
    mod util;

    use wasm_bindgen::prelude::*;

    #[wasm_bindgen]
    extern "C" {
    // Use `js_namespace` here to bind `console.log(..)` instead of just
    // `log(..)`
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
    }

    #[wasm_bindgen]
    pub fn say_hello() {
    log("Hello from Rust!");
    log("Hello from Rust, it works!");
    }

    #[wasm_bindgen]
    57 changes: 57 additions & 0 deletions val.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    import * as base64 from "https://deno.land/std/encoding/base64.ts";
    let imports: any = {};
    imports["__wbindgen_placeholder__"] = imports;
    let wasm;
    const { TextDecoder } = globalThis;

    let cachedTextDecoder = new TextDecoder("utf-8", {
    ignoreBOM: true,
    fatal: true,
    });

    cachedTextDecoder.decode();

    let cachedUint8Memory0 = null;

    function getUint8Memory0() {
    if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
    cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
    }
    return cachedUint8Memory0;
    }

    function getStringFromWasm0(ptr, len) {
    ptr = ptr >>> 0;
    return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
    }
    /**
    */
    export const say_hello = (imports.say_hello = function () {
    wasm.say_hello();
    });

    /**
    * @param {number} x
    * @param {number} y
    * @returns {number}
    */
    export const add = (imports.add = function (x, y) {
    const ret = wasm.add(x, y);
    return ret;
    });

    export const __wbg_log_08850d6d4d91f4c9 = (imports.__wbg_log_08850d6d4d91f4c9 =
    function (arg0, arg1) {
    console.log(getStringFromWasm0(arg0, arg1));
    });

    const bytes = base64.decodeBase64(
    "AGFzbQEAAAABDwNgAn9/AGAAAGACf38BfwI3ARhfX3diaW5kZ2VuX3BsYWNlaG9sZGVyX18aX193YmdfbG9nXzA4ODUwZDZkNGQ5MWY0YzkAAAMDAgECBQMBABEHHAMGbWVtb3J5AgADYWRkAAIJc2F5X2hlbGxvAAEKFQILAEGAgMAAQRoQAAsHACAAIAFqCwsjAQBBgIDAAAsaSGVsbG8gZnJvbSBSdXN0LCBpdCB3b3JrcyEAbwlwcm9kdWNlcnMCCGxhbmd1YWdlAQRSdXN0AAxwcm9jZXNzZWQtYnkDBXJ1c3RjHTEuNzIuMCAoNTY4MGZhMThmIDIwMjMtMDgtMjMpBndhbHJ1cwYwLjIwLjMMd2FzbS1iaW5kZ2VuBjAuMi44OQAsD3RhcmdldF9mZWF0dXJlcwIrD211dGFibGUtZ2xvYmFscysIc2lnbi1leHQ="
    );

    const wasmModule = new WebAssembly.Module(bytes);
    const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
    wasm = wasmInstance.exports;
    export const __wasm = (imports.__wasm = wasm);

    export default imports;
  10. saolsen created this gist Dec 20, 2023.
    20 changes: 20 additions & 0 deletions Cargo.toml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    [package]
    name = "rust_val"
    version = "0.1.0"
    edition = "2018"

    [lib]
    crate-type = ["cdylib", "rlib"]

    [features]
    default = ["console_error_panic_hook"]

    [dependencies]
    wasm-bindgen = "0.2.84"
    console_error_panic_hook = { version = "0.1.7", optional = true }

    [dev-dependencies]
    wasm-bindgen-test = "0.3.34"

    [profile.release]
    opt-level = "s"
    45 changes: 45 additions & 0 deletions package.mjs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,45 @@
    import { readFile, writeFile } from "node:fs/promises";

    const cargoTomlContent = await readFile("./Cargo.toml", "utf8");
    const cargoPackageName = /\[package\]\nname = "(.*?)"/.exec(
    cargoTomlContent
    )[1];
    const name = cargoPackageName.replace(/-/g, "_");

    const content = await readFile(`./dist/pkg/${name}.js`, "utf8");

    const patched = content
    // use global TextDecoder TextEncoder
    .replace("require(`util`)", "globalThis")
    // attach to `imports` instead of module.exports
    .replace("= module.exports", "= imports")
    .replace(/\nmodule\.exports\.(.*?)\s+/g, "\nexport const $1 = imports.$1 ")
    .replace(/$/, "export default imports")
    // inline bytes Uint8Array
    .replace(
    /\nconst path.*\nconst bytes.*\n/,
    `
    var __toBinary = /* @__PURE__ */ (() => {
    var table = new Uint8Array(128);
    for (var i = 0; i < 64; i++)
    table[i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i * 4 - 205] = i;
    return (base64) => {
    var n = base64.length, bytes = new Uint8Array((n - (base64[n - 1] == "=") - (base64[n - 2] == "=")) * 3 / 4 | 0);
    for (var i2 = 0, j = 0; i2 < n; ) {
    var c0 = table[base64.charCodeAt(i2++)], c1 = table[base64.charCodeAt(i2++)];
    var c2 = table[base64.charCodeAt(i2++)], c3 = table[base64.charCodeAt(i2++)];
    bytes[j++] = c0 << 2 | c1 >> 4;
    bytes[j++] = c1 << 4 | c2 >> 2;
    bytes[j++] = c2 << 6 | c3;
    }
    return bytes;
    };
    })();
    const bytes = __toBinary(${JSON.stringify(
    await readFile(`./dist/pkg/${name}_bg.wasm`, "base64")
    )});
    `
    );

    await writeFile(`./dist/${name}.mjs`, patched);
    19 changes: 19 additions & 0 deletions val.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    use wasm_bindgen::prelude::*;

    #[wasm_bindgen]
    extern "C" {
    // Use `js_namespace` here to bind `console.log(..)` instead of just
    // `log(..)`
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
    }

    #[wasm_bindgen]
    pub fn say_hello() {
    log("Hello from Rust!");
    }

    #[wasm_bindgen]
    pub fn add(x: i32, y: i32) -> i32 {
    x + y
    }