From 05ebf862fd4e7d73187b2f2a56192b6e69b1dc47 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 17 Jul 2022 19:41:12 +0800 Subject: [PATCH] feat: patch js-wasm --- __wasm/js-wasm/helloworld/js-wasm/.gitignore | 6 + __wasm/js-wasm/helloworld/js-wasm/CNAME | 1 + .../js-wasm/helloworld/js-wasm/LICENSE-APACHE | 201 +++ __wasm/js-wasm/helloworld/js-wasm/LICENSE-MIT | 8 + __wasm/js-wasm/helloworld/js-wasm/Makefile | 11 + __wasm/js-wasm/helloworld/js-wasm/README.md | 100 ++ .../js-wasm/assemblyscript/js-wasm.ts | 52 + .../js-wasm/assemblyscript/web_console.ts | 65 + .../js-wasm/assemblyscript/web_dom.ts | 12 + .../js-wasm/bindings/web_canvas.yaml | 37 + .../js-wasm/bindings/web_console.yaml | 25 + .../helloworld/js-wasm/bindings/web_dom.yaml | 8 + .../js-wasm/crates/callback/Cargo.toml | 14 + .../js-wasm/crates/callback/README.md | 20 + .../js-wasm/crates/callback/src/lib.rs | 791 ++++++++++ .../crates/cargo-webassembly/Cargo.toml | 19 + .../crates/cargo-webassembly/README.md | 78 + .../crates/cargo-webassembly/src/cli.yaml | 29 + .../crates/cargo-webassembly/src/main.rs | 213 +++ .../src/template/Project.toml | 18 + .../cargo-webassembly/src/template/index.html | 11 + .../cargo-webassembly/src/template/js-wasm.js | 304 ++++ .../cargo-webassembly/src/template/lib.rs | 6 + .../js-wasm/crates/class_names/Cargo.toml | 9 + .../js-wasm/crates/class_names/README.md | 46 + .../js-wasm/crates/class_names/src/lib.rs | 75 + .../js-wasm/crates/cstring/Cargo.toml | 16 + .../js-wasm/crates/cstring/README.md | 15 + .../js-wasm/crates/cstring/cstring.js | 22 + .../js-wasm/crates/cstring/src/cstr_core.rs | 1377 +++++++++++++++++ .../js-wasm/crates/cstring/src/lib.rs | 24 + .../js-wasm/crates/html_color/Cargo.toml | 12 + .../js-wasm/crates/html_color/src/lib.rs | 150 ++ .../js-wasm/crates/js-bindgen/Cargo.toml | 19 + .../js-wasm/crates/js-bindgen/README.md | 162 ++ .../js-wasm/crates/js-bindgen/src/main.rs | 96 ++ .../src/templates/assemblyscript/module.ts | 77 + .../js-bindgen/src/templates/c/header.h | 61 + .../js-bindgen/src/templates/rust/module.rs | 68 + .../helloworld/js-wasm/crates/js/Cargo.toml | 17 + .../helloworld/js-wasm/crates/js/README.md | 20 + .../helloworld/js-wasm/crates/js/src/lib.rs | 447 ++++++ .../helloworld/js-wasm/crates/web/Cargo.toml | 24 + .../helloworld/js-wasm/crates/web/README.md | 70 + .../helloworld/js-wasm/crates/web/src/lib.rs | 12 + .../js-wasm/crates/web_canvas/Cargo.toml | 14 + .../js-wasm/crates/web_canvas/README.md | 20 + .../js-wasm/crates/web_canvas/src/lib.rs | 71 + .../js-wasm/crates/web_common/Cargo.toml | 14 + .../js-wasm/crates/web_common/README.md | 20 + .../js-wasm/crates/web_common/src/lib.rs | 222 +++ .../js-wasm/crates/web_console/Cargo.toml | 14 + .../js-wasm/crates/web_console/README.md | 20 + .../js-wasm/crates/web_console/src/lib.rs | 55 + .../js-wasm/crates/web_dom/Cargo.toml | 15 + .../js-wasm/crates/web_dom/README.md | 20 + .../js-wasm/crates/web_dom/src/lib.rs | 221 +++ .../crates/web_local_storage/Cargo.toml | 14 + .../crates/web_local_storage/README.md | 20 + .../crates/web_local_storage/src/lib.rs | 53 + .../js-wasm/crates/web_random/Cargo.toml | 14 + .../js-wasm/crates/web_random/README.md | 20 + .../js-wasm/crates/web_random/src/lib.rs | 9 + .../js-wasm/crates/web_timer/Cargo.toml | 14 + .../js-wasm/crates/web_timer/README.md | 20 + .../js-wasm/crates/web_timer/src/lib.rs | 79 + .../js-wasm/crates/webcomponent/Cargo.toml | 24 + .../js-wasm/crates/webcomponent/README.md | 168 ++ .../examples/helloworld/Cargo.toml | 16 + .../webcomponent/examples/helloworld/Makefile | 7 + .../examples/helloworld/example.wasm | Bin 0 -> 35915 bytes .../examples/helloworld/index.html | 8 + .../examples/helloworld/src/lib.rs | 17 + .../examples/loudbutton/Cargo.toml | 17 + .../webcomponent/examples/loudbutton/Makefile | 7 + .../examples/loudbutton/example.wasm | Bin 0 -> 43601 bytes .../examples/loudbutton/index.html | 8 + .../examples/loudbutton/src/lib.rs | 27 + .../examples/observable_attributes/Cargo.toml | 17 + .../examples/observable_attributes/Makefile | 7 + .../observable_attributes/example.wasm | Bin 0 -> 44388 bytes .../examples/observable_attributes/index.html | 8 + .../examples/observable_attributes/src/lib.rs | 39 + .../examples/shadowdom/Cargo.toml | 17 + .../webcomponent/examples/shadowdom/Makefile | 7 + .../examples/shadowdom/example.wasm | Bin 0 -> 43287 bytes .../examples/shadowdom/index.html | 8 + .../examples/shadowdom/src/lib.rs | 19 + .../webcomponent/examples/todo/Cargo.toml | 20 + .../webcomponent/examples/todo/Makefile | 7 + .../webcomponent/examples/todo/example.wasm | Bin 0 -> 51009 bytes .../webcomponent/examples/todo/index.html | 22 + .../webcomponent/examples/todo/src/lib.rs | 118 ++ .../examples/todo/src/todo-item.html | 1 + .../examples/todo/src/todo-list.html | 7 + .../js-wasm/crates/webcomponent/src/lib.rs | 147 ++ .../helloworld/js-wasm/electron/Cargo.toml | 16 + .../helloworld/js-wasm/electron/Makefile | 27 + .../helloworld/js-wasm/electron/README.md | 68 + .../helloworld/js-wasm/electron/index.html | 17 + .../helloworld/js-wasm/electron/index.js | 33 + .../electron/resources/webassembly.svg | 35 + .../helloworld/js-wasm/electron/src/lib.rs | 37 + .../helloworld/js-wasm/headers/js-wasm.h | 63 + .../helloworld/js-wasm/headers/web_canvas.h | 1 + .../helloworld/js-wasm/headers/web_console.h | 65 + .../helloworld/js-wasm/headers/web_dom.h | 12 + __wasm/js-wasm/helloworld/js-wasm/js-wasm.js | 244 +++ __wasm/js-wasm/helloworld/js-wasm/js-wasm.ts | 368 +++++ .../helloworld/js-wasm/package-lock.json | 36 + .../js-wasm/helloworld/js-wasm/package.json | 33 + .../js-wasm/helloworld/js-wasm/tsconfig.json | 74 + 112 files changed, 7669 insertions(+) create mode 100644 __wasm/js-wasm/helloworld/js-wasm/.gitignore create mode 100644 __wasm/js-wasm/helloworld/js-wasm/CNAME create mode 100644 __wasm/js-wasm/helloworld/js-wasm/LICENSE-APACHE create mode 100644 __wasm/js-wasm/helloworld/js-wasm/LICENSE-MIT create mode 100644 __wasm/js-wasm/helloworld/js-wasm/Makefile create mode 100644 __wasm/js-wasm/helloworld/js-wasm/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/assemblyscript/js-wasm.ts create mode 100644 __wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_console.ts create mode 100644 __wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_dom.ts create mode 100644 __wasm/js-wasm/helloworld/js-wasm/bindings/web_canvas.yaml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/bindings/web_console.yaml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/bindings/web_dom.yaml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/callback/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/callback/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/callback/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/cli.yaml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/main.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/Project.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/js-wasm.js create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/class_names/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/class_names/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/class_names/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cstring/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cstring/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cstring/cstring.js create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/cstr_core.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/html_color/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/html_color/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/main.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/assemblyscript/module.ts create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/c/header.h create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/rust/module.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/js/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_common/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_common/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_common/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_console/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_console/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_console/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_dom/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_dom/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_dom/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_random/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_random/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_random/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_timer/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_timer/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/web_timer/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Makefile create mode 100755 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/example.wasm create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Makefile create mode 100755 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/example.wasm create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Makefile create mode 100755 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/example.wasm create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Makefile create mode 100755 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/example.wasm create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Makefile create mode 100755 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/example.wasm create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-item.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-list.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/Cargo.toml create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/Makefile create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/README.md create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/index.html create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/index.js create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/resources/webassembly.svg create mode 100644 __wasm/js-wasm/helloworld/js-wasm/electron/src/lib.rs create mode 100644 __wasm/js-wasm/helloworld/js-wasm/headers/js-wasm.h create mode 100644 __wasm/js-wasm/helloworld/js-wasm/headers/web_canvas.h create mode 100644 __wasm/js-wasm/helloworld/js-wasm/headers/web_console.h create mode 100644 __wasm/js-wasm/helloworld/js-wasm/headers/web_dom.h create mode 100644 __wasm/js-wasm/helloworld/js-wasm/js-wasm.js create mode 100644 __wasm/js-wasm/helloworld/js-wasm/js-wasm.ts create mode 100644 __wasm/js-wasm/helloworld/js-wasm/package-lock.json create mode 100644 __wasm/js-wasm/helloworld/js-wasm/package.json create mode 100644 __wasm/js-wasm/helloworld/js-wasm/tsconfig.json diff --git a/__wasm/js-wasm/helloworld/js-wasm/.gitignore b/__wasm/js-wasm/helloworld/js-wasm/.gitignore new file mode 100644 index 0000000..b3822c8 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/.gitignore @@ -0,0 +1,6 @@ +.vscode +target +Cargo.lock +tmp +dist +node_modules diff --git a/__wasm/js-wasm/helloworld/js-wasm/CNAME b/__wasm/js-wasm/helloworld/js-wasm/CNAME new file mode 100644 index 0000000..4936e1e --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/CNAME @@ -0,0 +1 @@ +wasm.js.org \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/LICENSE-APACHE b/__wasm/js-wasm/helloworld/js-wasm/LICENSE-APACHE new file mode 100644 index 0000000..c8e86dd --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) 2019 Richard Anaya + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/LICENSE-MIT b/__wasm/js-wasm/helloworld/js-wasm/LICENSE-MIT new file mode 100644 index 0000000..ebdd1dd --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/LICENSE-MIT @@ -0,0 +1,8 @@ + +Copyright 2020 Richard Anaya + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/Makefile b/__wasm/js-wasm/helloworld/js-wasm/Makefile new file mode 100644 index 0000000..5d3ebad --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/Makefile @@ -0,0 +1,11 @@ +build: + npm run build +build-rs: + cd crates/js-bindgen/ && cargo run -- --language c ../../bindings/web_console.yaml > ../../headers/web_console.h + cd crates/js-bindgen/ && cargo run -- --language c ../../bindings/web_canvas.yaml > ../../headers/web_canvas.h + cd crates/js-bindgen/ && cargo run -- --language c ../../bindings/web_dom.yaml > ../../headers/web_dom.h + cd crates/js-bindgen/ && cargo run -- --language rust ../../bindings/web_console.yaml > ../../crates/web_console/src/lib.rs + cd crates/js-bindgen/ && cargo run -- --language assemblyscript ../../bindings/web_console.yaml > ../../assemblyscript/web_console.ts + cd crates/js-bindgen/ && cargo run -- --language assemblyscript ../../bindings/web_dom.yaml > ../../assemblyscript/web_dom.ts +serve: build + python3 -m http.server \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/README.md b/__wasm/js-wasm/helloworld/js-wasm/README.md new file mode 100644 index 0000000..49e02f4 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/README.md @@ -0,0 +1,100 @@ +# js-wasm +docs.rs docs + +*JavaScript and WebAssembly should be a joy to use together.* + +This project aims to provide a simple, easy to learn, technology-agnostic way bridge the Rust and Javascript using an extremely minimal setup with out-of-box cargo compilation tools. + +See a [demo](https://richardanaya.github.io/js-wasm/examples/snake/index.html) of it working! + +# How It Works? +```bash +cargo new helloworld --lib +cd helloworld +cargo add js +vim src/lib.rs +``` +```rust +use js::*; + +#[no_mangle] +pub fn main() { + // let's dynamically create a javascript function we can invoke to write logs + let fn_log = js!("function(strPtr,strLen){ + console.log(this.readUtf8FromMemory(strPtr,strLen)); + }"); + let msg = "Hello World!"; + fn_log.invoke_2(msg.as_ptr() as u32, msg.len() as u32); +} +``` + +```bash +vim index.html +``` +```html + + + + + + + + Open my console. + + +``` +```bash +vim Cargo.toml +``` +```toml +# add these lines for WebAssembly to end of Cargo.toml + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true +``` +```bash +cargo build --target wasm32-unknown-unknown --release +cp target/wasm32-unknown-unknown/release/helloworld.wasm . +python3 -m http.server + +# open http://localhost:8000 in browser +# right click, inspect, look at message in console +``` + +Full example is [here](https://github.com/richardanaya/js-wasm/tree/master/examples/helloworld). + + +# details +In your JS function context `this` contains several functions handle most issues you'll encounter. It's probably easiest to look at examples to figure out how they are used. + +| Name | Description | +| ------------- | ------------- | +| `readUtf8FromMemory(start,length)` | Extract utf-8 text from your program's memory. | +| `readUtf16FromMemory(start,length)` | Extract utf-16 text from your program's memory. | +| `writeUtf8ToMemory(str)` | Write utf-8 to a memory location you are sure it should go. | +| `readUint8ArrayFromMemory(start)` | Read a list of uint8 from a pointer to a location of a number of elements, followed by a pointer to bytes in memory. | +| `storeObject(object)` | Store an object in your context for later reference, get a handle you can give to WebAssembly. | +| `getObject(handle)` | Retreive and object from your context with a handle. | +| `releaseObject(handle)` | Release a stored object so it's memory can be freed. | +| `createCallback(callbackHandle)` | Creates a callback function that will pass its arguments to the associated WebAssembly function represented by the handle. | +| `module` | Get access to your program so you can call methods on it. | + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `js-wasm` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/js-wasm.ts b/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/js-wasm.ts new file mode 100644 index 0000000..2582bcd --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/js-wasm.ts @@ -0,0 +1,52 @@ + + +@external("env", "js_register_function") +export declare function js_register_function(codePtr: f64, codeLen: f64, utfByeLen: f64): f64 +@external("env", "js_invoke_function") +export declare function js_invoke_function(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64, g: f64, h: f64, i: f64, j: f64): f64 +@external("env", "js_release") +export declare function js_release(ref: f64): void + +export function js_invoke_function_0(fn: f64): void { + js_invoke_function(fn,0,0,0,0,0,0,0,0,0,0); +} + +export function js_invoke_function_1(fn: f64, a: f64): void { + js_invoke_function(fn,a,0,0,0,0,0,0,0,0,0); +} + +export function js_invoke_function_2(fn: f64, a: f64, b: f64): void { + js_invoke_function(fn,a,b,0,0,0,0,0,0,0,0); +} + +export function js_invoke_function_3(fn: f64, a: f64, b: f64, c: f64): void { + js_invoke_function(fn,a,b,c,0,0,0,0,0,0,0); +} + +export function js_invoke_function_4(fn: f64, a: f64, b: f64, c: f64, d: f64): void { + js_invoke_function(fn,a,b,c,d,0,0,0,0,0,0); +} + +export function js_invoke_function_5(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64): void { + js_invoke_function(fn,a,b,c,d,e,0,0,0,0,0); +} + +export function js_invoke_function_6(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64): void { + js_invoke_function(fn,a,b,c,d,e,f,0,0,0,0); +} + +export function js_invoke_function_7(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64, g: f64): void { + js_invoke_function(fn,a,b,c,d,e,f,g,0,0,0); +} + +export function js_invoke_function_8(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64, g: f64, h: f64): void { + js_invoke_function(fn,a,b,c,d,e,f,g,h,0,0); +} + +export function js_invoke_function_9(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64, g: f64, h: f64, i: f64): void { + js_invoke_function(fn,a,b,c,d,e,f,g,h,i,0); +} + +export function js_invoke_function_10(fn: f64, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64, g: f64, h: f64, i: f64, j: f64): void { + js_invoke_function(fn,a,b,c,d,e,f,g,h,i,j); +} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_console.ts b/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_console.ts new file mode 100644 index 0000000..2eaef3e --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_console.ts @@ -0,0 +1,65 @@ +import * as jswasm from "./js-wasm" +let console_clear_fn:f64 = 0; +export function console_clear() : void { + if( console_clear_fn === 0) { + const code = `function(){ console.clear(); }`; + console_clear_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_0(console_clear_fn); +} + +let console_log_fn:f64 = 0; +export function console_log(msg: string) : void { + const a0: f64 = changetype(msg); + const a1: f64 = msg.length*2; + if( console_log_fn === 0) { + const code = `function(msgPtr,msgLen){ console.log(this.readUtf16FromMemory(msgPtr,msgLen)); }`; + console_log_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_2(console_log_fn, a0, a1); +} + +let console_warning_fn:f64 = 0; +export function console_warning(msg: string) : void { + const a0: f64 = changetype(msg); + const a1: f64 = msg.length*2; + if( console_warning_fn === 0) { + const code = `function(msgPtr,msgLen){ console.warn(this.readUtf16FromMemory(msgPtr,msgLen)); }`; + console_warning_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_2(console_warning_fn, a0, a1); +} + +let console_error_fn:f64 = 0; +export function console_error(msg: string) : void { + const a0: f64 = changetype(msg); + const a1: f64 = msg.length*2; + if( console_error_fn === 0) { + const code = `function(msgPtr,msgLen){ console.error(this.readUtf16FromMemory(msgPtr,msgLen)); }`; + console_error_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_2(console_error_fn, a0, a1); +} + +let console_time_fn:f64 = 0; +export function console_time(msg: string) : void { + const a0: f64 = changetype(msg); + const a1: f64 = msg.length*2; + if( console_time_fn === 0) { + const code = `function(msgPtr,msgLen){ console.time(this.readUtf16FromMemory(msgPtr,msgLen)); }`; + console_time_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_2(console_time_fn, a0, a1); +} + +let console_time_end_fn:f64 = 0; +export function console_time_end(msg: string) : void { + const a0: f64 = changetype(msg); + const a1: f64 = msg.length*2; + if( console_time_end_fn === 0) { + const code = `function(msgPtr,msgLen){ console.timeEnd(this.readUtf16FromMemory(msgPtr,msgLen)); }`; + console_time_end_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_2(console_time_end_fn, a0, a1); +} + diff --git a/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_dom.ts b/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_dom.ts new file mode 100644 index 0000000..bf155e8 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/assemblyscript/web_dom.ts @@ -0,0 +1,12 @@ +import * as jswasm from "./js-wasm" +let document_get_element_by_id_fn:f64 = 0; +export function document_get_element_by_id(id: string) : f64 { + const a0: f64 = changetype(id); + const a1: f64 = id.length*2; + if( document_get_element_by_id_fn === 0) { + const code = `function(idPtr,idLen){ return this.storeObject(document.getElementById(this.readUtf16FromMemory(idPtr,idLen))); }`; + document_get_element_by_id_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + return jswasm.js_invoke_function_2(document_get_element_by_id_fn, a0, a1); +} + diff --git a/__wasm/js-wasm/helloworld/js-wasm/bindings/web_canvas.yaml b/__wasm/js-wasm/helloworld/js-wasm/bindings/web_canvas.yaml new file mode 100644 index 0000000..7b508e3 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/bindings/web_canvas.yaml @@ -0,0 +1,37 @@ +--- +- namespace: canvas + class: CanvasElement + parameter_self: el + method: + - name: getContext + parameters: + - name: contextType + parameter_type: string + +- namespace: canvas + class: CanvasContext + parameter_self: ctx + properties: + - name: fillStyle + property_type: string + methods: + - name: fillRect + parameters: + - name: x + parameter_type: f64 + - name: "y" + parameter_type: f64 + - name: height + parameter_type: f64 + - name: width + parameter_type: f64 + - name: clearRect + parameters: + - name: x + parameter_type: f64 + - name: "y" + parameter_type: f64 + - name: height + parameter_type: f64 + - name: width + parameter_type: f64 \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/bindings/web_console.yaml b/__wasm/js-wasm/helloworld/js-wasm/bindings/web_console.yaml new file mode 100644 index 0000000..5ac52bd --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/bindings/web_console.yaml @@ -0,0 +1,25 @@ +--- +- namespace: console + functions: + - name: clear + - name: log + parameters: + - name: msg + parameter_type: string + - name: warn + friendly_name: warning + parameters: + - name: msg + parameter_type: string + - name: error + parameters: + - name: msg + parameter_type: string + - name: time + parameters: + - name: msg + parameter_type: string + - name: timeEnd + parameters: + - name: msg + parameter_type: string diff --git a/__wasm/js-wasm/helloworld/js-wasm/bindings/web_dom.yaml b/__wasm/js-wasm/helloworld/js-wasm/bindings/web_dom.yaml new file mode 100644 index 0000000..6bab7c3 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/bindings/web_dom.yaml @@ -0,0 +1,8 @@ +--- +- namespace: document + functions: + - name: getElementById + parameters: + - name: id + parameter_type: string + output: object diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/callback/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/callback/Cargo.toml new file mode 100644 index 0000000..5913ecc --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/callback/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "callback" +version = "0.5.4" +authors = ["Richard Anaya"] +edition = "2021" +description = "A library for handling callbacks in WebAssembly" +license = "MIT OR Apache-2.0" +categories = ["wasm", "no-std"] +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" +rust-version="1.62" + +[dependencies] +spin = "0" diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/callback/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/callback/README.md new file mode 100644 index 0000000..c6a85e1 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/callback/README.md @@ -0,0 +1,20 @@ +# callback + +A library for handling callbacks in WebAssembly. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'callback' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/callback/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/callback/src/lib.rs new file mode 100644 index 0000000..2575e91 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/callback/src/lib.rs @@ -0,0 +1,791 @@ +#![no_std] +#![allow(clippy::type_complexity)] +#![allow(clippy::too_many_arguments)] +extern crate alloc; +use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, Waker}, +}; +use spin::{Mutex, MutexGuard}; + +pub enum CallbackHandler { + Callback0(Box), + Callback1(Box), + Callback2(Box), + Callback3(Box), + Callback4(Box), + Callback5(Box), + Callback6(Box), + Callback7(Box), + Callback8(Box), + Callback9(Box), + Callback10(Box), +} + +type CallbackHandle = f64; + +pub struct CallbackManager { + cur_id: CallbackHandle, + pub keys: Vec, + pub handlers: Vec>>, +} + +fn get_callbacks() -> MutexGuard<'static, CallbackManager> { + static SINGLETON: Mutex = { + Mutex::new(CallbackManager { + cur_id: 0.0, + keys: Vec::new(), + handlers: Vec::new(), + }) + }; + SINGLETON.lock() +} + +pub fn get_callback(id: CallbackHandle) -> Option>> { + let cbs = get_callbacks(); + let index = cbs.keys.iter().position(|&r| r == id); + if let Some(i) = index { + let handler_ref = cbs.handlers.get(i).unwrap().clone(); + core::mem::drop(cbs); + Some(handler_ref) + } else { + None + } +} + +pub fn remove_callback(id: CallbackHandle) { + let mut cbs = get_callbacks(); + let index = cbs.keys.iter().position(|&r| r == id); + if let Some(i) = index { + cbs.keys.remove(i); + cbs.handlers.remove(i); + } +} + +fn create_callback(cb: CallbackHandler) -> f64 { + let mut h = get_callbacks(); + h.cur_id += 1.0; + let id = h.cur_id; + h.keys.push(id); + h.handlers.push(Arc::new(Mutex::new(cb))); + id +} + +pub fn create_callback_0(cb: impl FnMut() + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback0(Box::new(cb))) +} + +pub fn create_callback_1(cb: impl FnMut(f64) + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback1(Box::new(cb))) +} + +pub fn create_callback_2(cb: impl FnMut(f64, f64) + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback2(Box::new(cb))) +} + +pub fn create_callback_3(cb: impl FnMut(f64, f64, f64) + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback3(Box::new(cb))) +} + +pub fn create_callback_4(cb: impl FnMut(f64, f64, f64, f64) + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback4(Box::new(cb))) +} + +pub fn create_callback_5(cb: impl FnMut(f64, f64, f64, f64, f64) + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback5(Box::new(cb))) +} + +pub fn create_callback_6(cb: impl FnMut(f64, f64, f64, f64, f64, f64) + Send + 'static) -> f64 { + create_callback(CallbackHandler::Callback6(Box::new(cb))) +} + +pub fn create_callback_7( + cb: impl FnMut(f64, f64, f64, f64, f64, f64, f64) + Send + 'static, +) -> f64 { + create_callback(CallbackHandler::Callback7(Box::new(cb))) +} + +pub fn create_callback_8( + cb: impl FnMut(f64, f64, f64, f64, f64, f64, f64, f64) + Send + 'static, +) -> f64 { + create_callback(CallbackHandler::Callback8(Box::new(cb))) +} + +pub fn create_callback_9( + cb: impl FnMut(f64, f64, f64, f64, f64, f64, f64, f64, f64) + Send + 'static, +) -> f64 { + create_callback(CallbackHandler::Callback9(Box::new(cb))) +} + +pub fn create_callback_10( + cb: impl FnMut(f64, f64, f64, f64, f64, f64, f64, f64, f64, f64) + Send + 'static, +) -> f64 { + create_callback(CallbackHandler::Callback10(Box::new(cb))) +} + +pub struct CallbackFuture { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState { + completed: bool, + waker: Option, + result: Option, +} + +impl Future for CallbackFuture { + type Output = Option; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture { + pub fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState { + completed: false, + waker: None, + result: None, + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback1(Box::new(move |v: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = Some(v); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }))); + (CallbackFuture { shared_state }, id as f64) + } +} + +struct CallbackFuture0 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState0 { + completed: bool, + waker: Option, + result: (), +} + +impl Future for CallbackFuture0 { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(()) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture0 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState0 { + completed: false, + waker: None, + result: (), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback0(Box::new(move || { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }))); + (CallbackFuture0 { shared_state }, id) + } +} + +pub fn create_callback_future_0() -> (impl Future, f64) { + CallbackFuture0::new() +} + +struct CallbackFuture1 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState1 { + completed: bool, + waker: Option, + result: f64, +} + +impl Future for CallbackFuture1 { + type Output = f64; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture1 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState1 { + completed: false, + waker: None, + result: 0.0, + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback1(Box::new(move |v: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = v; + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }))); + (CallbackFuture1 { shared_state }, id) + } +} + +pub fn create_callback_future_1() -> (impl Future, f64) { + CallbackFuture1::new() +} + +struct CallbackFuture2 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState2 { + completed: bool, + waker: Option, + result: (f64, f64), +} + +impl Future for CallbackFuture2 { + type Output = (f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture2 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState2 { + completed: false, + waker: None, + result: (0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback2(Box::new( + move |a1: f64, a2: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture2 { shared_state }, id) + } +} + +pub fn create_callback_future_2() -> (impl Future, f64) { + CallbackFuture2::new() +} + +struct CallbackFuture3 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState3 { + completed: bool, + waker: Option, + result: (f64, f64, f64), +} + +impl Future for CallbackFuture3 { + type Output = (f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture3 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState3 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback3(Box::new( + move |a1: f64, a2: f64, a3: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture3 { shared_state }, id) + } +} + +pub fn create_callback_future_3() -> (impl Future, f64) { + CallbackFuture3::new() +} + +struct CallbackFuture4 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState4 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64), +} + +impl Future for CallbackFuture4 { + type Output = (f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture4 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState4 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback4(Box::new( + move |a1: f64, a2: f64, a3: f64, a4: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture4 { shared_state }, id) + } +} + +pub fn create_callback_future_4() -> (impl Future, f64) { + CallbackFuture4::new() +} + +struct CallbackFuture5 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState5 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64, f64), +} + +impl Future for CallbackFuture5 { + type Output = (f64, f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture5 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState5 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback5(Box::new( + move |a1: f64, a2: f64, a3: f64, a4: f64, a5: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4, a5); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture5 { shared_state }, id) + } +} + +pub fn create_callback_future_5() -> (impl Future, f64) { + CallbackFuture5::new() +} + +struct CallbackFuture6 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState6 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64, f64, f64), +} + +impl Future for CallbackFuture6 { + type Output = (f64, f64, f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture6 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState6 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback6(Box::new( + move |a1: f64, a2: f64, a3: f64, a4: f64, a5: f64, a6: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4, a5, a6); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture6 { shared_state }, id) + } +} + +pub fn create_callback_future_6() -> (impl Future, f64) { + CallbackFuture6::new() +} + +struct CallbackFuture7 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState7 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64, f64, f64, f64), +} + +impl Future for CallbackFuture7 { + type Output = (f64, f64, f64, f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture7 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState7 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback7(Box::new( + move |a1: f64, a2: f64, a3: f64, a4: f64, a5: f64, a6: f64, a7: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4, a5, a6, a7); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture7 { shared_state }, id) + } +} + +pub fn create_callback_future_7() -> (impl Future, f64) { + CallbackFuture7::new() +} + +struct CallbackFuture8 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState8 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64, f64, f64, f64, f64), +} + +impl Future for CallbackFuture8 { + type Output = (f64, f64, f64, f64, f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture8 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState8 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback8(Box::new( + move |a1: f64, a2: f64, a3: f64, a4: f64, a5: f64, a6: f64, a7: f64, a8: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4, a5, a6, a7, a8); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture8 { shared_state }, id) + } +} + +pub fn create_callback_future_8() -> (impl Future, f64) { + CallbackFuture8::new() +} + +struct CallbackFuture9 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState9 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64, f64, f64, f64, f64, f64), +} + +impl Future for CallbackFuture9 { + type Output = (f64, f64, f64, f64, f64, f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture9 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState9 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback9(Box::new( + move |a1: f64, + a2: f64, + a3: f64, + a4: f64, + a5: f64, + a6: f64, + a7: f64, + a8: f64, + a9: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4, a5, a6, a7, a8, a9); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture9 { shared_state }, id) + } +} + +pub fn create_callback_future_9() -> (impl Future, f64) { + CallbackFuture9::new() +} + +struct CallbackFuture10 { + shared_state: Arc>, +} + +/// Shared state between the future and the waiting thread +struct SharedState10 { + completed: bool, + waker: Option, + result: (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64), +} + +impl Future for CallbackFuture10 { + type Output = (f64, f64, f64, f64, f64, f64, f64, f64, f64, f64); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut shared_state = self.shared_state.lock(); + if shared_state.completed { + Poll::Ready(shared_state.result) + } else { + shared_state.waker = Some(cx.waker().clone()); + Poll::Pending + } + } +} + +impl CallbackFuture10 { + fn new() -> (Self, f64) { + let shared_state = Arc::new(Mutex::new(SharedState10 { + completed: false, + waker: None, + result: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), + })); + + let thread_shared_state = shared_state.clone(); + let id = create_callback(CallbackHandler::Callback10(Box::new( + move |a1: f64, + a2: f64, + a3: f64, + a4: f64, + a5: f64, + a6: f64, + a7: f64, + a8: f64, + a9: f64, + a10: f64| { + let mut shared_state = thread_shared_state.lock(); + shared_state.completed = true; + shared_state.result = (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + if let Some(waker) = shared_state.waker.take() { + core::mem::drop(shared_state); + waker.wake() + } + }, + ))); + (CallbackFuture10 { shared_state }, id) + } +} + +pub fn create_callback_future_10() -> (impl Future, f64) { + CallbackFuture10::new() +} + +#[no_mangle] +fn handle_callback( + id: f64, + a1: f64, + a2: f64, + a3: f64, + a4: f64, + a5: f64, + a6: f64, + a7: f64, + a8: f64, + a9: f64, + a10: f64, +) { + let h = get_callback(id); + let handler_ref = h.unwrap(); + let mut handler = handler_ref.lock(); + match &mut *handler { + CallbackHandler::Callback0(c) => c(), + CallbackHandler::Callback1(c) => c(a1), + CallbackHandler::Callback2(c) => c(a1, a2), + CallbackHandler::Callback3(c) => c(a1, a2, a3), + CallbackHandler::Callback4(c) => c(a1, a2, a3, a4), + CallbackHandler::Callback5(c) => c(a1, a2, a3, a4, a5), + CallbackHandler::Callback6(c) => c(a1, a2, a3, a4, a5, a6), + CallbackHandler::Callback7(c) => c(a1, a2, a3, a4, a5, a6, a7), + CallbackHandler::Callback8(c) => c(a1, a2, a3, a4, a5, a6, a7, a8), + CallbackHandler::Callback9(c) => c(a1, a2, a3, a4, a5, a6, a7, a8, a9), + CallbackHandler::Callback10(c) => c(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10), + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/Cargo.toml new file mode 100644 index 0000000..de1815e --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "cargo-webassembly" +version = "0.0.18" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "A cargo utility for working on WebAssembly" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +url= "2.2.0" +webbrowser = "0.5.5" +clap = { version = "2.33.3", features = ["yaml"] } +colored = "2.0.0" +tide = "0.15.0" +async-std = { version = "1.7.0", features = ["attributes"] } diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/README.md new file mode 100644 index 0000000..7376b98 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/README.md @@ -0,0 +1,78 @@ +# cargo-webassembly + +This cargo extension is for developing front end applications in WebAssembly. Use it's subcommands to generate Rust projects ready to develop WebAssembly immediately, and use the tool to run a local dev server to see it while you work. + +This project is currently **beta**, but totally functional! Next steps include: + +* cleaning up the code to use less `unwrap` +* use a better open url library (the current one has some weird behavior). +* support project file watching and recompiling + +

+ +

+ +First make sure you [install Rust](https://rustup.rs/) and have the `wasm32` toolchain installed: + +``` +rustup target add wasm32-unknown-unknown +``` + +Install with the following command: + +``` +cargo install cargo-webassembly +``` + +# Create a new project + +``` +cargo webassembly new my_project +``` + +This will initialize a Rust WebAssembly project completely setup to run in the browser. + +# Run your project + +Go into your projects root directory (e.g. `cd my_project`) + +``` +cargo webassembly run +``` + +This will compile and start a server by default on port `8080`, you can change the port with the `-p` option. + +This server is setup for single-page apps where all non-static file routes redirect to the root `index.html`. + +# Building your project + +``` +cargo webassembly build +``` + +This command will just compile your WebAssembly and place everything you need for your web app in the `dist` folder. + +# Next steps + +Check out more ways to interact with the browser using the [`web`](https://docs.rs/web/) package! + +Here's some cool examples: + +* [snake](https://wasm.js.org/examples/snake/) + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `cargo-webassembly` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/cli.yaml b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/cli.yaml new file mode 100644 index 0000000..5871a8d --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/cli.yaml @@ -0,0 +1,29 @@ +name: cargo-webassembly +version: "0.0.12" +author: Richard Anaya +about: A tool for working with WebAssembly Rust projects +subcommands: + - webassembly: + args: + - version: + short: V + multiple: true + help: Displays the version + about: A collection of subcommands for working with WebAssembly + subcommands: + - new: + about: creates new WebAssembly project + args: + - INPUT: + help: Sets the name of the project directory to use + required: true + - init: + about: creates new WebAssembly project in current directory + - build: + about: controls testing features + - run: + about: controls testing features + args: + - port: + help: Sets the port to be used when running + default_value: "8080" \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/main.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/main.rs new file mode 100644 index 0000000..0694f41 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/main.rs @@ -0,0 +1,213 @@ +#[macro_use] +extern crate clap; +use clap::App; +extern crate url; +use colored::*; +use std::env; +use std::fs::create_dir; +use std::path::PathBuf; + +pub fn from_extension(extension: impl AsRef) -> Option { + match extension.as_ref() { + "html" => Some(tide::http::mime::HTML), + "js" | "mjs" | "jsonp" => Some(tide::http::mime::JAVASCRIPT), + "json" => Some(tide::http::mime::JSON), + "css" => Some(tide::http::mime::CSS), + "svg" => Some(tide::http::mime::SVG), + "xml" => Some(tide::http::mime::XML), + "png" => Some(tide::http::mime::PNG), + "jpg" | "jpeg" => Some(tide::http::mime::JPEG), + "wasm" => Some(tide::http::mime::WASM), + "ico" => Some(tide::http::mime::ICO), + _ => None, + } +} + +#[async_std::main] +async fn main() -> tide::Result<()> { + let yaml = load_yaml!("cli.yaml"); + let mut app = App::from_yaml(yaml); + let matches = app.clone().get_matches(); + + let mut dir = env::current_dir().unwrap(); + + if let Some(matches) = matches.subcommand_matches("webassembly") { + if let Some(matches) = matches.subcommand_matches("new") { + dir = dir.join(matches.value_of("INPUT").unwrap()); + create_project_in_dir(&dir) + } else if let Some(_) = matches.subcommand_matches("init") { + create_project_in_dir(&dir) + } else if let Some(_) = matches.subcommand_matches("build") { + build_project_in_dir(&dir) + } else if let Some(matches) = matches.subcommand_matches("run") { + build_project_in_dir(&dir); + let name = dir.file_name().unwrap().to_str().unwrap(); + let server_dir = dir.join("dist"); + let mut app = tide::new(); + let server_dir2 = server_dir.clone(); + app.at("/").get(move |_req: tide::Request<()>| { + let index = server_dir.join("index.html"); + async move { + tide::Result::Ok( + tide::Response::builder(200) + .body(std::fs::read(index).unwrap()) + .content_type(tide::http::mime::HTML) + .build(), + ) + } + }); + app.at("/*").get(move |req: tide::Request<()>| { + let server_dir3 = server_dir2.clone(); + async move { + let index = server_dir3.join("index.html"); + let p = server_dir3.to_str().unwrap(); + let p2 = req.url().path(); + let s = format!("{}{}", p, p2).to_string(); + let p3 = std::path::Path::new(&s); + if p3.exists() { + tide::Result::Ok( + tide::Response::builder(200) + .body(std::fs::read(p3).unwrap()) + .content_type( + from_extension(p3.extension().unwrap().to_str().unwrap()) + .unwrap(), + ) + .build(), + ) + } else { + tide::Result::Ok( + tide::Response::builder(200) + .body(std::fs::read(index).unwrap()) + .content_type(tide::http::mime::HTML) + .build(), + ) + } + } + }); + let port = matches.value_of("port").unwrap().parse::().unwrap(); + let addr = format!("{}{}", "http://127.0.0.1:", port); + let addr2 = addr.clone(); + async_std::task::spawn(async move { webbrowser::open(&addr2) }); + println!( + " {} webassembly `{}` package on port {}", + "Running".green().bold(), + name, + addr + ); + app.listen(addr).await?; + } else { + if matches.is_present("version") { + println!("{}", env!("CARGO_PKG_VERSION")) + } else { + app.print_long_help().unwrap(); + } + } + } + Ok(()) +} + +fn create_project_in_dir(dir: &PathBuf) { + let name = dir.file_name().unwrap().to_str().unwrap(); + if !dir.exists() { + create_dir(dir).unwrap(); + } + create_dir(dir.join("src")).unwrap(); + create_dir(dir.join("dist")).unwrap(); + std::fs::write( + dir.join("Cargo.toml"), + include_str!("template/Project.toml").replace("PROJECT", name), + ) + .expect("Failed to write"); + std::fs::write( + dir.join("src/lib.rs"), + include_str!("template/lib.rs").replace("PROJECT", name), + ) + .expect("Failed to write"); + std::fs::write( + dir.join("dist/index.html"), + include_str!("template/index.html").replace("PROJECT", name), + ) + .expect("Failed to write"); + std::fs::write( + dir.join("dist/js-wasm.js"), + include_str!("template/js-wasm.js").replace("PROJECT", name), + ) + .expect("Failed to write"); + println!( + " {} webassembly `{}` package", + "Created".green().bold(), + name + ); +} + +fn build_project_in_dir(dir: &PathBuf) { + use std::io::{self, Write}; + use std::process::Command; + + if !dir.join("Cargo.toml").exists() { + println!("must execute this command in project root"); + return; + } + + let name = dir.file_name().unwrap().to_str().unwrap(); + println!( + " {} webassembly `{}` package", + "Pre-compile check".green().bold(), + name + ); + let mut target_check = Command::new("cargo"); + target_check + .arg("check") + .arg("--target") + .arg("wasm32-unknown-unknown"); + let command_output = target_check + .output() + .expect("Build pre-check failed! (check that wasm32 build target is installed)"); + io::stdout().write_all(&command_output.stdout).unwrap(); + io::stderr().write_all(&command_output.stderr).unwrap(); + println!( + " Pre-compile check exit code status: {}", + command_output.status + ); + + let name = dir.file_name().unwrap().to_str().unwrap(); + println!( + " {} webassembly `{}` package", + "Compiling".green().bold(), + name + ); + + println!( + " {} webassembly `{}` package", + "Compiling".green().bold(), + name + ); + let mut echo_hello = Command::new("cargo"); + echo_hello + .arg("build") + .arg("--target") + .arg("wasm32-unknown-unknown") + .arg("--release"); + let compile_command_output = echo_hello.output().expect("Could not compile to wasm"); + + io::stdout() + .write_all(&compile_command_output.stdout) + .unwrap(); + io::stderr() + .write_all(&compile_command_output.stderr) + .unwrap(); + println!( + " Compilation exit code status: {}", + compile_command_output.status + ); + + std::fs::copy( + dir.join(format!( + "target/wasm32-unknown-unknown/release/{}.wasm", + name.replace("-", "_") + )), + dir.join(format!("dist/{}.wasm", name)), + ) + .expect("Could not copy built file! (check that wasm32 build target is installed)"); + println!(" {} webassembly target", "Finished".green().bold()); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/Project.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/Project.toml new file mode 100644 index 0000000..240d11b --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/Project.toml @@ -0,0 +1,18 @@ +[package] +name = "PROJECT" +version = "0.0.0" +authors = [""] +edition = "2018" +description = "" +categories = ["wasm"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +web = "0" + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/index.html b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/index.html new file mode 100644 index 0000000..8e4ea0d --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/index.html @@ -0,0 +1,11 @@ + + + + PROJECT + + + + + + + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/js-wasm.js b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/js-wasm.js new file mode 100644 index 0000000..e57f02d --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/js-wasm.js @@ -0,0 +1,304 @@ +class Index { + constructor(index, generation) { + this.index = index; + this.generation = generation; + } + + toNum() { + return Number(BigInt(this.generation) << BigInt(32) | BigInt(this.index)); + } +} + +Index.fromNum = function (n) { + let i = Number(((BigInt(n) & BigInt(0xffffffff00000000)) >> BigInt(32)) & BigInt(0xffffffff)); + let g = n & 0xffffffff; + return new Index(g, i); +}; + +class GenerationalArena { + constructor() { + this.items = []; + this.generation = 0; + this.free_list_head = null; + this.length = 0; + } + + insert(v) { + // lets use the first free entry if we have one + if (this.free_list_head !== null) { + let i = this.free_list_head; + this.free_list_head = this.items[i].next_free; + this.items[i] = { + generation: this.generation, + value: v + }; + this.length += 1; + return new Index(i, this.generation); + } + + this.items.push({ + generation: this.generation, + value: v + }); + let idx = new Index(this.items.length - 1, this.generation); + this.length += 1; + return idx; + } + + contains(idx) { + return this.get(idx) !== undefined; + } + + get(i) { + let e = this.items[i.index]; + if (e && e.generation === i.generation) { + return e.value; + } + return undefined; + } + + remove(idx) { + if (idx.index >= this.items.length) { + return undefined; + } + + let e = this.items[idx.index]; + if (e.generation !== undefined && e.generation == idx.generation) { + this.generation += 1; + this.items[idx.index] = { + next_free: this.free_list_head + }; + this.free_list_head = idx.index; + this.length -= 1; + return e.value; + } + return undefined; + } + + *[Symbol.iterator]() { + for (var i = 0; i < this.items.length; i++) { + let x = this.items[i]; + if (x.generation !== undefined) { + yield { index: new Index(i, x.generation), value: x.value }; + } + } + } + + indices() { + let i = { items: this.items }; + i[Symbol.iterator] = function* iter() { + for (var i = 0; i < this.items.length; i++) { + let x = this.items[i]; + if (x.generation !== undefined) { + yield new Index(i, x.generation); + } + } + }; + return i; + } + + values() { + let i = { items: this.items }; + i[Symbol.iterator] = function* iter() { + for (var i = 0; i < this.items.length; i++) { + let x = this.items[i]; + if (x.generation !== undefined) { + yield x.value; + } + } + }; + return i; + } +} + +window.JsWasm = { + createEnvironment() { + let arena = new GenerationalArena(); + arena.insert(undefined); + arena.insert(null); + arena.insert(self); + arena.insert(typeof document != "undefined" ? document : null); + arena.insert(typeof document != "undefined" ? document.body : null); + let context = { + functions: [ + function () { + debugger; + } + ], + objects: arena, + utf8dec: new TextDecoder("utf-8"), + utf8enc: new TextEncoder("utf-8"), + utf16dec: new TextDecoder("utf-16"), + utf16enc: new TextEncoder("utf-16"), + toCallbackArg: function (arg) { + if (typeof arg === "object") { + return context.storeObject(arg); + } + return arg; + }, + createCallback: function (cb) { + let fnHandleCallback = this.module.instance.exports.handle_callback; + return function () { + const arg = arguments; + fnHandleCallback( + cb, + context.toCallbackArg(arg[0]), + context.toCallbackArg(arg[1]), + context.toCallbackArg(arg[2]), + context.toCallbackArg(arg[3]), + context.toCallbackArg(arg[4]), + context.toCallbackArg(arg[5]), + context.toCallbackArg(arg[6]), + context.toCallbackArg(arg[7]), + context.toCallbackArg(arg[8]), + context.toCallbackArg(arg[9]) + ); + }; + }, + readCStringFromMemory: function (start) { + const data = new Uint8Array(this.module.instance.exports.memory.buffer); + const str = []; + let i = start; + while (data[i] !== 0) { + str.push(data[i]); + i++; + } + return this.utf8dec.decode(new Uint8Array(str)); + }, + writeCStringToMemory(str) { + const bytes = this.utf8enc.encode(str + String.fromCharCode(0)); + const len = bytes.length; + const start = this.module.instance.exports.malloc(len); + const memory = new Uint8Array( + this.module.instance.exports.memory.buffer + ); + memory.set(bytes, start); + return start; + }, + readUtf8FromMemory: function (start, len) { + const memory = new Uint8Array( + this.module.instance.exports.memory.buffer + ); + const text = this.utf8dec.decode(memory.subarray(start, start + len)); + return text; + }, + writeUtf8ToMemory: function (str) { + const bytes = utf8enc.encode(str); + const len = bytes.length; + const start = this.module.instance.exports.malloc(len); + const memory = new Uint8Array( + this.module.instance.exports.memory.buffer + ); + memory.set(bytes, start); + return start; + }, + readUtf16FromMemory: function (start, len) { + const memory = new Uint8Array( + this.module.instance.exports.memory.buffer + ); + const text = this.utf16dec.decode(memory.subarray(start, start + len)); + return text; + }, + writeUtf16ToMemory: function (str) { + const bytes = utf16enc.encode(str); + const len = bytes.length; + const start = this.module.instance.exports.malloc(len); + const memory = new Uint8Array( + this.module.instance.exports.memory.buffer + ); + memory.set(bytes, start); + return start; + }, + readUint8ArrayFromMemory(start) { + const data32 = new Uint32Array( + this.module.instance.exports.memory.buffer + ); + const ptr = data32[start / 4]; + const length = data32[ptr / 4]; + let b = mem.slice(ptr + 4, ptr + 4 + length); + return new Uint8Array(b); + }, + storeObject: function (obj) { + const index = this.objects.insert(obj); + return index.toNum(); + }, + getObject: function (handle) { + return this.objects.get(Index.fromNum(handle)); + }, + releaseObject: function (handle) { + this.objects.remove(Index.fromNum(handle)); + } + }; + return { + context, + abort() { + throw new Error("WebAssembly module aborted"); + }, + js_release(obj) { + context.releaseObject(obj); + }, + js_register_function(start, len, utfByteLen) { + let functionBody; + if (utfByteLen === 16) { + functionBody = context.readUtf16FromMemory(start, len); + } else { + functionBody = context.readUtf8FromMemory(start, len); + } + let id = context.functions.length; + context.functions.push( + Function(`"use strict";return(${functionBody})`)() + ); + return id; + }, + js_invoke_function(funcHandle, a, b, c, d, e, f, g, h, i, j) { + return context.functions[funcHandle].call( + context, + a, + b, + c, + d, + e, + f, + g, + h, + i, + j + ); + } + }; + }, + + async load_and_run_wasm(wasmURL) { + const env = JsWasm.createEnvironment(); + const response = await fetch(wasmURL); + const bytes = await response.arrayBuffer(); + const module = await WebAssembly.instantiate(bytes, { + env + }); + env.context.module = module; + module.instance.exports.main(); + } +}; + +document.addEventListener("DOMContentLoaded", function () { + const wasmScripts = document.querySelectorAll( + "script[type='application/wasm']" + ); + for (let i = 0; i < wasmScripts.length; i++) { + const src = wasmScripts[i].src; + if (src) { + JsWasm.load_and_run_wasm(src); + } else { + console.error("Script tag must have 'src' property."); + } + } +}); + +if (window.WasmScriptComponents) { + window.WasmScriptComponents["js-wasm"] = function (e) { + return { + ...e, + ...JsWasm.createEnvironment() + }; + }; +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/lib.rs new file mode 100644 index 0000000..880558e --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cargo-webassembly/src/template/lib.rs @@ -0,0 +1,6 @@ +use web::*; + +#[no_mangle] +pub fn main() { + set_inner_html(DOM_BODY,"Hello World!"); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/Cargo.toml new file mode 100644 index 0000000..9076dfa --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "class_names" +version = "0.0.2" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "A macro library for elegantly joining class names for web frameworks" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/README.md new file mode 100644 index 0000000..33fa72c --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/README.md @@ -0,0 +1,46 @@ +# class_names + +docs.rs docs + +```toml +[dependencies] +class_names="0" +``` + +# How to use + +This library includes a macro for easily expressing a list of CSS class names (some which may be optional). The macro takes in a mixed list of `&str`,`String`,`Option<&str>`, or `Option` and calculates a final list of class names for the HTML `class` attribute. Here's some examples + +1. use strings +```rust +class_names!("big-button", "red".to_string()) // "big-button red" +``` +2. accepts optionals +```rust +class_names!("big-button", if btn_red { Some("red") } else { None } ) +``` +3. a concise way of writing an optional +```rust +class_names!("big-button", btn_inactive.then(|| "inactive")) +``` +4. one day from future features in [Rust nightly](https://doc.rust-lang.org/std/primitive.bool.html#method.then_some) you'll be able to write like this +```rust +class_names!("big-button", btn_inactive.then_some("inactive")) +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `class_names` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/src/lib.rs new file mode 100644 index 0000000..c0ea4a6 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/class_names/src/lib.rs @@ -0,0 +1,75 @@ +#![no_std] +use core::cell::RefCell; +extern crate alloc; +use alloc::string::String; +use alloc::vec::Vec; + +pub trait AddClassList<'a> { + fn insert_into_list(&'a self, list: &'a ClassList<'a>); +} + +impl<'a> AddClassList<'a> for &str { + fn insert_into_list(&'a self, list: &'a ClassList<'a>) { + list.classes.borrow_mut().push(self); + } +} + +impl<'a> AddClassList<'a> for Option<&str> { + fn insert_into_list(&'a self, list: &'a ClassList<'a>) { + match self { + Some(t) => list.classes.borrow_mut().push(t), + None => (), + }; + } +} + +impl<'a> AddClassList<'a> for Option { + fn insert_into_list(&'a self, list: &'a ClassList<'a>) { + match self { + Some(t) => list.classes.borrow_mut().push(&t), + None => (), + }; + } +} + +impl<'a> AddClassList<'a> for String { + fn insert_into_list(&'a self, list: &'a ClassList<'a>) { + list.classes.borrow_mut().push(&self); + } +} + +pub struct ClassList<'a> { + classes: RefCell>, +} + +impl<'a> ClassList<'a> { + pub fn new() -> ClassList<'a> { + ClassList { + classes: RefCell::new(Vec::new()), + } + } + pub fn add(&'a self, item: &'a T) + where + T: AddClassList<'a>, + { + (&item).insert_into_list(self); + } + pub fn to_string(&self) -> String { + self.classes.borrow_mut().join(" ") + } +} + +#[macro_export] +macro_rules! class_names { + // `()` indicates that the macro takes no argument. + ($($element:expr),*) => { + { + let class_list = ClassList::new(); + $( + let e = $element; + class_list.add(&e); + )* + class_list.to_string() + } + }; +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/Cargo.toml new file mode 100644 index 0000000..1bf7fde --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "cstring" +version = "0.1.1" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "A super simple cstring library for WebAssembly" +categories = ["wasm", "no-std"] + +[dependencies] +cty = "0.2.1" +memchr = { version = "2.3.4", default-features = false } + +[features] +default = ["alloc"] +alloc = [] diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/README.md new file mode 100644 index 0000000..fa0c570 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/README.md @@ -0,0 +1,15 @@ +# cstring +A super simple library for c strings in web assembly + +```toml +[dependencies] +cstring = "0.0.4" +``` + +# javascript + +I've also included a very useful es6 module for interacting with strings in web assembly memory + +```javascript +import { extractCString, insertString } from "https://cdn.jsdelivr.net/gh/richardanaya/cstring/cstring.js"; +``` diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/cstring.js b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/cstring.js new file mode 100644 index 0000000..89dfd50 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/cstring.js @@ -0,0 +1,22 @@ +const utf8dec = new TextDecoder("utf-8"); +const utf8enc = new TextEncoder("utf-8"); + +export function extractCString(mem, ptr) { + const memory = new Uint8Array(mem); + const str = []; + let i = ptr; + while (memory[i] !== 0) { + str.push(memory[i]); + i++; + } + return utf8dec.decode(new Uint8Array(str)); +} + +export function insertString(getMemory, malloc, str) { + const bytes = utf8enc.encode(str); + const len = bytes.length; + const start = malloc(len); + const memory = new Uint8Array(getMemory()); + memory.set(bytes, start); + return [start, len]; +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/cstr_core.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/cstr_core.rs new file mode 100644 index 0000000..5b212b4 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/cstr_core.rs @@ -0,0 +1,1377 @@ +// This code comes from the unupdated project https://github.com/Amanieu/cstr_core + +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "alloc")] +extern crate alloc; +extern crate cty; +extern crate memchr; + +#[cfg(feature = "alloc")] +use alloc::borrow::{Borrow, Cow, ToOwned}; +#[cfg(feature = "alloc")] +use alloc::boxed::Box; +#[cfg(feature = "alloc")] +use alloc::rc::Rc; +#[cfg(feature = "alloc")] +use alloc::string::String; +#[cfg(feature = "alloc")] +use alloc::sync::Arc; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +#[cfg(feature = "alloc")] +use core::{mem, ops, ptr}; + +use core::cmp::Ordering; +use core::fmt::{self, Write}; +use core::slice; +use core::str::{self, Utf8Error}; + +/// Re-export c_char +pub use cty::c_char; + +#[inline] +unsafe fn strlen(p: *const c_char) -> usize { + let mut n = 0; + while *p.offset(n as isize) != 0 { + n += 1; + } + n +} + +mod ascii { + use core::ops::Range; + + /// An iterator over the escaped version of a byte. + /// + /// This `struct` is created by the [`escape_default`] function. See its + /// documentation for more. + /// + /// [`escape_default`]: fn.escape_default.html + pub struct EscapeDefault { + range: Range, + data: [u8; 4], + } + + /// Returns an iterator that produces an escaped version of a `u8`. + /// + /// The default is chosen with a bias toward producing literals that are + /// legal in a variety of languages, including C++11 and similar C-family + /// languages. The exact rules are: + /// + /// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. + /// - Single-quote, double-quote and backslash chars are backslash-escaped. + /// - Any other chars in the range [0x20,0x7e] are not escaped. + /// - Any other chars are given hex escapes of the form '\xNN'. + /// - Unicode escapes are never generated by this function. + /// + /// # Examples + /// + /// ``` + /// use std::ascii; + /// + /// let escaped = ascii::escape_default(b'0').next().unwrap(); + /// assert_eq!(b'0', escaped); + /// + /// let mut escaped = ascii::escape_default(b'\t'); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b't', escaped.next().unwrap()); + /// + /// let mut escaped = ascii::escape_default(b'\r'); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b'r', escaped.next().unwrap()); + /// + /// let mut escaped = ascii::escape_default(b'\n'); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b'n', escaped.next().unwrap()); + /// + /// let mut escaped = ascii::escape_default(b'\''); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b'\'', escaped.next().unwrap()); + /// + /// let mut escaped = ascii::escape_default(b'"'); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b'"', escaped.next().unwrap()); + /// + /// let mut escaped = ascii::escape_default(b'\\'); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// + /// let mut escaped = ascii::escape_default(b'\x9d'); + /// + /// assert_eq!(b'\\', escaped.next().unwrap()); + /// assert_eq!(b'x', escaped.next().unwrap()); + /// assert_eq!(b'9', escaped.next().unwrap()); + /// assert_eq!(b'd', escaped.next().unwrap()); + /// ``` + pub fn escape_default(c: u8) -> EscapeDefault { + let (data, len) = match c { + b'\t' => ([b'\\', b't', 0, 0], 2), + b'\r' => ([b'\\', b'r', 0, 0], 2), + b'\n' => ([b'\\', b'n', 0, 0], 2), + b'\\' => ([b'\\', b'\\', 0, 0], 2), + b'\'' => ([b'\\', b'\'', 0, 0], 2), + b'"' => ([b'\\', b'"', 0, 0], 2), + b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1), + _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), + }; + + return EscapeDefault { + range: (0..len), + data: data, + }; + + fn hexify(b: u8) -> u8 { + match b { + 0..=9 => b'0' + b, + _ => b'a' + b - 10, + } + } + } + + impl Iterator for EscapeDefault { + type Item = u8; + fn next(&mut self) -> Option { + self.range.next().map(|i| self.data[i]) + } + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } + } + impl DoubleEndedIterator for EscapeDefault { + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.data[i]) + } + } + impl ExactSizeIterator for EscapeDefault {} +} + +/// A type representing an owned C-compatible string. +/// +/// This type serves the primary purpose of being able to safely generate a +/// C-compatible string from a Rust byte slice or vector. An instance of this +/// type is a static guarantee that the underlying bytes contain no interior 0 +/// bytes and the final byte is 0. +/// +/// A `CString` is created from either a byte slice or a byte vector. A [`u8`] +/// slice can be obtained with the `as_bytes` method. Slices produced from a +/// `CString` do *not* contain the trailing nul terminator unless otherwise +/// specified. +/// +/// [`u8`]: ../primitive.u8.html +/// +/// # Examples +/// +/// ```ignore (extern-declaration) +/// # fn main() { +/// use cstr_core::CString; +/// use cstr_core::c_char; +/// +/// extern { +/// fn my_printer(s: *const c_char); +/// } +/// +/// let c_to_print = CString::new("Hello, world!").unwrap(); +/// unsafe { +/// my_printer(c_to_print.as_ptr()); +/// } +/// # } +/// ``` +/// +/// # Safety +/// +/// `CString` is intended for working with traditional C-style strings +/// (a sequence of non-null bytes terminated by a single null byte); the +/// primary use case for these kinds of strings is interoperating with C-like +/// code. Often you will need to transfer ownership to/from that external +/// code. It is strongly recommended that you thoroughly read through the +/// documentation of `CString` before use, as improper ownership management +/// of `CString` instances can lead to invalid memory accesses, memory leaks, +/// and other memory errors. + +#[cfg(feature = "alloc")] +#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] +pub struct CString { + // Invariant 1: the slice ends with a zero byte and has a length of at least one. + // Invariant 2: the slice contains only one zero byte. + // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. + inner: Box<[u8]>, +} + +/// Representation of a borrowed C string. +/// +/// This dynamically sized type is only safely constructed via a borrowed +/// version of an instance of `CString`. This type can be constructed from a raw +/// C string as well and represents a C string borrowed from another location. +/// +/// Note that this structure is **not** `repr(C)` and is not recommended to be +/// placed in the signatures of FFI functions. Instead safe wrappers of FFI +/// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe +/// interface to other consumers. +/// +/// [`from_ptr`]: #method.from_ptr +/// +/// # Examples +/// +/// Inspecting a foreign C string: +/// +/// ```ignore (extern-declaration) +/// use cstr_core::CStr; +/// use cstr_core::c_char; +/// +/// extern { fn my_string() -> *const c_char; } +/// +/// unsafe { +/// let slice = CStr::from_ptr(my_string()); +/// println!("string length: {}", slice.to_bytes().len()); +/// } +/// ``` +/// +/// Passing a Rust-originating C string: +/// +/// ```ignore (extern-declaration) +/// use cstr_core::{CString, CStr}; +/// use cstr_core::c_char; +/// +/// fn work(data: &CStr) { +/// extern { fn work_with(data: *const c_char); } +/// +/// unsafe { work_with(data.as_ptr()) } +/// } +/// +/// let s = CString::new("data data data data").unwrap(); +/// work(&s); +/// ``` +/// +/// Converting a foreign C string into a Rust [`String`]: +/// +/// [`String`]: ../string/struct.String.html +/// +/// ```ignore (extern-declaration) +/// use cstr_core::CStr; +/// use cstr_core::c_char; +/// +/// extern { fn my_string() -> *const c_char; } +/// +/// fn my_string_safe() -> String { +/// unsafe { +/// CStr::from_ptr(my_string()).to_string_lossy().into_owned() +/// } +/// } +/// +/// println!("string: {}", my_string_safe()); +/// ``` +#[derive(Hash)] +pub struct CStr { + // FIXME: this should not be represented with a DST slice but rather with + // just a raw `c_char` along with some form of marker to make + // this an unsized type. Essentially `sizeof(&CStr)` should be the + // same as `sizeof(&c_char)` but `CStr` should be an unsized type. + inner: [c_char], +} + +/// An error returned from [`CString::new`] to indicate that a nul byte was found +/// in the vector provided. +/// +/// [`CString::new`]: struct.CString.html#method.new +/// +/// # Examples +/// +/// ``` +/// use cstr_core::{CString, NulError}; +/// +/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err(); +/// ``` +#[cfg(feature = "alloc")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct NulError(usize, Vec); + +/// An error returned from [`CStr::from_bytes_with_nul`] to indicate that a nul +/// byte was found too early in the slice provided or one wasn't found at all. +/// +/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul +/// +/// # Examples +/// +/// ``` +/// use cstr_core::{CStr, FromBytesWithNulError}; +/// +/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err(); +/// ``` +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FromBytesWithNulError { + kind: FromBytesWithNulErrorKind, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum FromBytesWithNulErrorKind { + InteriorNul(usize), + NotNulTerminated, +} + +impl FromBytesWithNulError { + fn interior_nul(pos: usize) -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::InteriorNul(pos), + } + } + fn not_nul_terminated() -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::NotNulTerminated, + } + } +} + +/// An error returned from [`CString::into_string`] to indicate that a UTF-8 error +/// was encountered during the conversion. +/// +/// [`CString::into_string`]: struct.CString.html#method.into_string +#[cfg(feature = "alloc")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct IntoStringError { + inner: CString, + error: Utf8Error, +} + +#[cfg(feature = "alloc")] +impl CString { + /// Creates a new C-compatible string from a container of bytes. + /// + /// This method will consume the provided data and use the underlying bytes + /// to construct a new string, ensuring that there is a trailing 0 byte. + /// + /// # Examples + /// + /// ```ignore (extern-declaration) + /// use cstr_core::CString; + /// use cstr_core::c_char; + /// + /// extern { fn puts(s: *const c_char); } + /// + /// let to_print = CString::new("Hello!").unwrap(); + /// unsafe { + /// puts(to_print.as_ptr()); + /// } + /// ``` + /// + /// # Errors + /// + /// This function will return an error if the bytes yielded contain an + /// internal 0 byte. The error returned will contain the bytes as well as + /// the position of the nul byte. + pub fn new>>(t: T) -> Result { + Self::_new(t.into()) + } + + fn _new(bytes: Vec) -> Result { + match memchr::memchr(0, &bytes) { + Some(i) => Err(NulError(i, bytes)), + None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + } + } + + /// Creates a C-compatible string from a byte vector without checking for + /// interior 0 bytes. + /// + /// This method is equivalent to [`new`] except that no runtime assertion + /// is made that `v` contains no 0 bytes, and it requires an actual + /// byte vector, not anything that can be converted to one with Into. + /// + /// [`new`]: #method.new + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let raw = b"foo".to_vec(); + /// unsafe { + /// let c_string = CString::from_vec_unchecked(raw); + /// } + /// ``` + pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.reserve_exact(1); + v.push(0); + CString { + inner: v.into_boxed_slice(), + } + } + + /// Retakes ownership of a `CString` that was transferred to C. + /// + /// Additionally, the length of the string will be recalculated from the pointer. + /// + /// # Safety + /// + /// This should only ever be called with a pointer that was earlier + /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take + /// ownership of a string that was allocated by foreign code) is likely to lead + /// to undefined behavior or allocator corruption. + /// + /// [`into_raw`]: #method.into_raw + /// + /// # Examples + /// + /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake + /// ownership with `from_raw`: + /// + /// ```ignore (extern-declaration) + /// use cstr_core::CString; + /// use cstr_core::c_char; + /// + /// extern { + /// fn some_extern_function(s: *mut c_char); + /// } + /// + /// let c_string = CString::new("Hello!").unwrap(); + /// let raw = c_string.into_raw(); + /// unsafe { + /// some_extern_function(raw); + /// let c_string = CString::from_raw(raw); + /// } + /// ``` + pub unsafe fn from_raw(ptr: *mut c_char) -> CString { + let len = strlen(ptr) + 1; // Including the NUL byte + let slice = slice::from_raw_parts_mut(ptr, len as usize); + CString { + inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]), + } + } + + /// Transfers ownership of the string to a C caller. + /// + /// The pointer must be returned to Rust and reconstituted using + /// [`from_raw`] to be properly deallocated. Specifically, one + /// should *not* use the standard C `free` function to deallocate + /// this string. + /// + /// Failure to call [`from_raw`] will lead to a memory leak. + /// + /// [`from_raw`]: #method.from_raw + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// + /// let ptr = c_string.into_raw(); + /// + /// unsafe { + /// assert_eq!(b'f', *ptr as u8); + /// assert_eq!(b'o', *ptr.offset(1) as u8); + /// assert_eq!(b'o', *ptr.offset(2) as u8); + /// assert_eq!(b'\0', *ptr.offset(3) as u8); + /// + /// // retake pointer to free memory + /// let _ = CString::from_raw(ptr); + /// } + /// ``` + #[inline] + pub fn into_raw(self) -> *mut c_char { + Box::into_raw(self.into_inner()) as *mut c_char + } + + /// Converts the `CString` into a [`String`] if it contains valid Unicode data. + /// + /// On failure, ownership of the original `CString` is returned. + /// + /// [`String`]: ../string/struct.String.html + pub fn into_string(self) -> Result { + String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError { + error: e.utf8_error(), + inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, + }) + } + + /// Returns the underlying byte buffer. + /// + /// The returned buffer does **not** contain the trailing nul separator and + /// it is guaranteed to not have any interior nul bytes. + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.into_bytes(); + /// assert_eq!(bytes, vec![b'f', b'o', b'o']); + /// ``` + pub fn into_bytes(self) -> Vec { + let mut vec = self.into_inner().into_vec(); + let _nul = vec.pop(); + debug_assert_eq!(_nul, Some(0u8)); + vec + } + + /// Equivalent to the [`into_bytes`] function except that the returned vector + /// includes the trailing nul byte. + /// + /// [`into_bytes`]: #method.into_bytes + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.into_bytes_with_nul(); + /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); + /// ``` + pub fn into_bytes_with_nul(self) -> Vec { + self.into_inner().into_vec() + } + + /// Returns the contents of this `CString` as a slice of bytes. + /// + /// The returned slice does **not** contain the trailing nul separator and + /// it is guaranteed to not have any interior nul bytes. + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.as_bytes(); + /// assert_eq!(bytes, &[b'f', b'o', b'o']); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.inner[..self.inner.len() - 1] + } + + /// Equivalent to the [`as_bytes`] function except that the returned slice + /// includes the trailing nul byte. + /// + /// [`as_bytes`]: #method.as_bytes + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.as_bytes_with_nul(); + /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); + /// ``` + #[inline] + pub fn as_bytes_with_nul(&self) -> &[u8] { + &self.inner + } + + /// Extracts a [`CStr`] slice containing the entire string. + /// + /// [`CStr`]: struct.CStr.html + /// + /// # Examples + /// + /// ``` + /// use cstr_core::{CString, CStr}; + /// + /// let c_string = CString::new(b"foo".to_vec()).unwrap(); + /// let c_str = c_string.as_c_str(); + /// assert_eq!(c_str, CStr::from_bytes_with_nul(b"foo\0").unwrap()); + /// ``` + #[inline] + pub fn as_c_str(&self) -> &CStr { + &*self + } + + /// Converts this `CString` into a boxed [`CStr`]. + /// + /// [`CStr`]: struct.CStr.html + /// + /// # Examples + /// + /// ``` + /// use cstr_core::{CString, CStr}; + /// + /// let c_string = CString::new(b"foo".to_vec()).unwrap(); + /// let boxed = c_string.into_boxed_c_str(); + /// assert_eq!(&*boxed, CStr::from_bytes_with_nul(b"foo\0").unwrap()); + /// ``` + pub fn into_boxed_c_str(self) -> Box { + unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) } + } + + // Bypass "move out of struct which implements [`Drop`] trait" restriction. + /// + /// [`Drop`]: ../ops/trait.Drop.html + fn into_inner(self) -> Box<[u8]> { + unsafe { + let result = ptr::read(&self.inner); + mem::forget(self); + result + } + } +} + +// Turns this `CString` into an empty string to prevent +// memory unsafe code from working by accident. Inline +// to prevent LLVM from optimizing it away in debug builds. +#[cfg(feature = "alloc")] +impl Drop for CString { + #[inline] + fn drop(&mut self) { + unsafe { + *self.inner.get_unchecked_mut(0) = 0; + } + } +} + +#[cfg(feature = "alloc")] +impl ops::Deref for CString { + type Target = CStr; + + #[inline] + fn deref(&self) -> &CStr { + unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } + } +} + +#[cfg(feature = "alloc")] +impl fmt::Debug for CString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(feature = "alloc")] +impl From for Vec { + #[inline] + fn from(s: CString) -> Vec { + s.into_bytes() + } +} + +impl fmt::Debug for CStr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"")?; + for byte in self + .to_bytes() + .iter() + .flat_map(|&b| ascii::escape_default(b)) + { + f.write_char(byte as char)?; + } + write!(f, "\"") + } +} + +impl<'a> Default for &'a CStr { + fn default() -> &'a CStr { + const SLICE: &'static [c_char] = &[0]; + unsafe { CStr::from_ptr(SLICE.as_ptr()) } + } +} + +#[cfg(feature = "alloc")] +impl Default for CString { + /// Creates an empty `CString`. + fn default() -> CString { + let a: &CStr = Default::default(); + a.to_owned() + } +} + +#[cfg(feature = "alloc")] +impl Borrow for CString { + #[inline] + fn borrow(&self) -> &CStr { + self + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a CStr> for Box { + fn from(s: &'a CStr) -> Box { + let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } + } +} + +#[cfg(feature = "alloc")] +impl From> for CString { + #[inline] + fn from(s: Box) -> CString { + s.into_c_string() + } +} + +#[cfg(feature = "alloc")] +impl From for Box { + #[inline] + fn from(s: CString) -> Box { + s.into_boxed_c_str() + } +} + +#[cfg(feature = "alloc")] +impl From for Arc { + #[inline] + fn from(s: CString) -> Arc { + let arc: Arc<[u8]> = Arc::from(s.into_inner()); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a CStr> for Arc { + #[inline] + fn from(s: &CStr) -> Arc { + let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } + } +} + +#[cfg(feature = "alloc")] +impl From for Rc { + #[inline] + fn from(s: CString) -> Rc { + let rc: Rc<[u8]> = Rc::from(s.into_inner()); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a CStr> for Rc { + #[inline] + fn from(s: &CStr) -> Rc { + let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } + } +} + +#[cfg(feature = "alloc")] +impl Default for Box { + fn default() -> Box { + let boxed: Box<[u8]> = Box::from([0]); + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } + } +} + +#[cfg(feature = "alloc")] +impl NulError { + /// Returns the position of the nul byte in the slice that was provided to + /// [`CString::new`]. + /// + /// [`CString::new`]: struct.CString.html#method.new + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let nul_error = CString::new("foo\0bar").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 3); + /// + /// let nul_error = CString::new("foo bar\0").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 7); + /// ``` + pub fn nul_position(&self) -> usize { + self.0 + } + + /// Consumes this error, returning the underlying vector of bytes which + /// generated the error in the first place. + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let nul_error = CString::new("foo\0bar").unwrap_err(); + /// assert_eq!(nul_error.into_vec(), b"foo\0bar"); + /// ``` + pub fn into_vec(self) -> Vec { + self.1 + } +} + +#[cfg(feature = "alloc")] +impl fmt::Display for NulError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nul byte found in provided data at position: {}", self.0) + } +} + +impl fmt::Display for FromBytesWithNulError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.kind { + FromBytesWithNulErrorKind::InteriorNul(..) => { + f.write_str("data provided contains an interior nul byte")? + } + FromBytesWithNulErrorKind::NotNulTerminated => { + f.write_str("data provided is not nul terminated")? + } + } + if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { + write!(f, " at byte pos {}", pos)?; + } + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl IntoStringError { + /// Consumes this error, returning original [`CString`] which generated the + /// error. + /// + /// [`CString`]: struct.CString.html + pub fn into_cstring(self) -> CString { + self.inner + } + + /// Access the underlying UTF-8 error that was the cause of this error. + pub fn utf8_error(&self) -> Utf8Error { + self.error + } +} + +#[cfg(feature = "alloc")] +impl fmt::Display for IntoStringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "C string contained non-utf8 bytes") + } +} + +impl CStr { + /// Casts a raw C string to a safe C string wrapper. + /// + /// This function will cast the provided `ptr` to the `CStr` wrapper which + /// allows inspection and interoperation of non-owned C strings. This method + /// is unsafe for a number of reasons: + /// + /// * There is no guarantee to the validity of `ptr`. + /// * The returned lifetime is not guaranteed to be the actual lifetime of + /// `ptr`. + /// * There is no guarantee that the memory pointed to by `ptr` contains a + /// valid nul terminator byte at the end of the string. + /// * It is not guaranteed that the memory pointed by `ptr` won't change + /// before the `CStr` has been destroyed. + /// + /// > **Note**: This operation is intended to be a 0-cost cast but it is + /// > currently implemented with an up-front calculation of the length of + /// > the string. This is not guaranteed to always be the case. + /// + /// # Examples + /// + /// ```ignore (extern-declaration) + /// # fn main() { + /// use cstr_core::CStr; + /// use cstr_core::c_char; + /// + /// extern { + /// fn my_string() -> *const c_char; + /// } + /// + /// unsafe { + /// let slice = CStr::from_ptr(my_string()); + /// println!("string returned: {}", slice.to_str().unwrap()); + /// } + /// # } + /// ``` + pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { + let len = strlen(ptr); + let ptr = ptr as *const u8; + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) + } + + /// Creates a C string wrapper from a byte slice. + /// + /// This function will cast the provided `bytes` to a `CStr` wrapper after + /// ensuring that it is null terminated and does not contain any interior + /// nul bytes. + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CStr; + /// + /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); + /// assert!(cstr.is_ok()); + /// ``` + /// + /// Creating a `CStr` without a trailing nul byte is an error: + /// + /// ``` + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"hello"); + /// assert!(c_str.is_err()); + /// ``` + /// + /// Creating a `CStr` with an interior nul byte is an error: + /// + /// ``` + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0"); + /// assert!(c_str.is_err()); + /// ``` + pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { + let nul_pos = memchr::memchr(0, bytes); + if let Some(nul_pos) = nul_pos { + if nul_pos + 1 != bytes.len() { + return Err(FromBytesWithNulError::interior_nul(nul_pos)); + } + Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) + } else { + Err(FromBytesWithNulError::not_nul_terminated()) + } + } + + /// Unsafely creates a C string wrapper from a byte slice. + /// + /// This function will cast the provided `bytes` to a `CStr` wrapper without + /// performing any sanity checks. The provided slice must be null terminated + /// and not contain any interior nul bytes. + /// + /// # Examples + /// + /// ``` + /// use cstr_core::{CStr, CString}; + /// + /// unsafe { + /// let cstring = CString::new("hello").unwrap(); + /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); + /// assert_eq!(cstr, &*cstring); + /// } + /// ``` + #[inline] + pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + &*(bytes as *const [u8] as *const CStr) + } + + /// Returns the inner pointer to this C string. + /// + /// The returned pointer will be valid for as long as `self` is and points + /// to a contiguous region of memory terminated with a 0 byte to represent + /// the end of the string. + /// + /// **WARNING** + /// + /// It is your responsibility to make sure that the underlying memory is not + /// freed too early. For example, the following code will cause undefined + /// behavior when `ptr` is used inside the `unsafe` block: + /// + /// ```no_run + /// use cstr_core::{CString}; + /// + /// let ptr = CString::new("Hello").unwrap().as_ptr(); + /// unsafe { + /// // `ptr` is dangling + /// *ptr; + /// } + /// ``` + /// + /// This happens because the pointer returned by `as_ptr` does not carry any + /// lifetime information and the string is deallocated immediately after + /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated. + /// To fix the problem, bind the string to a local variable: + /// + /// ```no_run + /// use cstr_core::{CString}; + /// + /// let hello = CString::new("Hello").unwrap(); + /// let ptr = hello.as_ptr(); + /// unsafe { + /// // `ptr` is valid because `hello` is in scope + /// *ptr; + /// } + /// ``` + #[inline] + pub fn as_ptr(&self) -> *const c_char { + self.inner.as_ptr() + } + + /// Converts this C string to a byte slice. + /// + /// This function will calculate the length of this string (which normally + /// requires a linear amount of work to be done) and then return the + /// resulting slice of `u8` elements. + /// + /// The returned slice will **not** contain the trailing nul that this C + /// string has. + /// + /// > **Note**: This method is currently implemented as a constant-time + /// > cast, but it is planned to alter its definition in the future to + /// > perform the length calculation whenever this method is called. + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap(); + /// assert_eq!(c_str.to_bytes(), b"foo"); + /// ``` + #[inline] + pub fn to_bytes(&self) -> &[u8] { + let bytes = self.to_bytes_with_nul(); + &bytes[..bytes.len() - 1] + } + + /// Converts this C string to a byte slice containing the trailing 0 byte. + /// + /// This function is the equivalent of [`to_bytes`] except that it will retain + /// the trailing nul instead of chopping it off. + /// + /// > **Note**: This method is currently implemented as a 0-cost cast, but + /// > it is planned to alter its definition in the future to perform the + /// > length calculation whenever this method is called. + /// + /// [`to_bytes`]: #method.to_bytes + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap(); + /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0"); + /// ``` + #[inline] + pub fn to_bytes_with_nul(&self) -> &[u8] { + unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } + } + + /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. + /// + /// This function will calculate the length of this string and check for + /// UTF-8 validity, and then return the [`&str`] if it's valid. + /// + /// > **Note**: This method is currently implemented to check for validity + /// > after a constant-time cast, but it is planned to alter its definition + /// > in the future to perform the length calculation in addition to the + /// > UTF-8 check whenever this method is called. + /// + /// [`&str`]: ../primitive.str.html + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap(); + /// assert_eq!(c_str.to_str(), Ok("foo")); + /// ``` + pub fn to_str(&self) -> Result<&str, Utf8Error> { + // NB: When CStr is changed to perform the length check in .to_bytes() + // instead of in from_ptr(), it may be worth considering if this should + // be rewritten to do the UTF-8 check inline with the length calculation + // instead of doing it afterwards. + str::from_utf8(self.to_bytes()) + } + + /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. + /// + /// This function will calculate the length of this string (which normally + /// requires a linear amount of work to be done) and then return the + /// resulting slice as a [`Cow`]`<`[`str`]`>`, replacing any invalid UTF-8 sequences + /// with `U+FFFD REPLACEMENT CHARACTER`. + /// + /// > **Note**: This method is currently implemented to check for validity + /// > after a constant-time cast, but it is planned to alter its definition + /// > in the future to perform the length calculation in addition to the + /// > UTF-8 check whenever this method is called. + /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`str`]: ../primitive.str.html + /// + /// # Examples + /// + /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8: + /// + /// ``` + /// use std::borrow::Cow; + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0").unwrap(); + /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World")); + /// ``` + /// + /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8: + /// + /// ``` + /// use std::borrow::Cow; + /// use cstr_core::CStr; + /// + /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0").unwrap(); + /// assert_eq!( + /// c_str.to_string_lossy(), + /// Cow::Owned(String::from("Hello �World")) as Cow + /// ); + /// ``` + #[cfg(feature = "alloc")] + pub fn to_string_lossy(&self) -> Cow { + String::from_utf8_lossy(self.to_bytes()) + } + + /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`CString`]: struct.CString.html + /// + /// # Examples + /// + /// ``` + /// use cstr_core::CString; + /// + /// let c_string = CString::new(b"foo".to_vec()).unwrap(); + /// let boxed = c_string.into_boxed_c_str(); + /// assert_eq!(boxed.into_c_string(), CString::new("foo").unwrap()); + /// ``` + #[cfg(feature = "alloc")] + pub fn into_c_string(self: Box) -> CString { + let raw = Box::into_raw(self) as *mut [u8]; + CString { + inner: unsafe { Box::from_raw(raw) }, + } + } +} + +impl PartialEq for CStr { + fn eq(&self, other: &CStr) -> bool { + self.to_bytes().eq(other.to_bytes()) + } +} +impl Eq for CStr {} +impl PartialOrd for CStr { + fn partial_cmp(&self, other: &CStr) -> Option { + self.to_bytes().partial_cmp(&other.to_bytes()) + } +} +impl Ord for CStr { + fn cmp(&self, other: &CStr) -> Ordering { + self.to_bytes().cmp(&other.to_bytes()) + } +} + +#[cfg(feature = "alloc")] +impl ToOwned for CStr { + type Owned = CString; + + fn to_owned(&self) -> CString { + CString { + inner: self.to_bytes_with_nul().into(), + } + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a CStr> for CString { + fn from(s: &'a CStr) -> CString { + s.to_owned() + } +} + +#[cfg(feature = "alloc")] +impl ops::Index for CString { + type Output = CStr; + + #[inline] + fn index(&self, _index: ops::RangeFull) -> &CStr { + self + } +} + +impl AsRef for CStr { + #[inline] + fn as_ref(&self) -> &CStr { + self + } +} + +#[cfg(feature = "alloc")] +impl AsRef for CString { + #[inline] + fn as_ref(&self) -> &CStr { + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::borrow::Cow::{Borrowed, Owned}; + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + #[test] + fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); + assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); + } + } + + #[test] + fn simple() { + let s = CString::new("1234").unwrap(); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); + } + + #[test] + fn build_with_zero1() { + assert!(CString::new(&b"\0"[..]).is_err()); + } + #[test] + fn build_with_zero2() { + assert!(CString::new(vec![0]).is_err()); + } + + #[test] + fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } + } + + #[test] + fn formatted() { + let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); + assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); + } + + #[test] + fn borrowed() { + unsafe { + let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); + assert_eq!(s.to_bytes(), b"12"); + assert_eq!(s.to_bytes_with_nul(), b"12\0"); + } + } + + #[test] + fn to_str() { + let data = b"123\xE2\x80\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); + } + let data = b"123\xE2\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert!(CStr::from_ptr(ptr).to_str().is_err()); + assert_eq!( + CStr::from_ptr(ptr).to_string_lossy(), + Owned::(format!("123\u{FFFD}")) + ); + } + } + + #[test] + fn to_owned() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + + let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; + assert_eq!(owned.as_bytes_with_nul(), data); + } + + #[test] + fn equal_hash() { + let data = b"123\xE2\xFA\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; + + let mut s = DefaultHasher::new(); + cstr.hash(&mut s); + let cstr_hash = s.finish(); + let mut s = DefaultHasher::new(); + CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); + let cstring_hash = s.finish(); + + assert_eq!(cstr_hash, cstring_hash); + } + + #[test] + fn from_bytes_with_nul() { + let data = b"123\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); + + unsafe { + let cstr = CStr::from_bytes_with_nul(data); + let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); + assert_eq!(cstr, Ok(cstr_unchecked)); + } + } + + #[test] + fn from_bytes_with_nul_unterminated() { + let data = b"123"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); + } + + #[test] + fn from_bytes_with_nul_interior() { + let data = b"1\023\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); + } + + #[test] + fn into_boxed() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let boxed: Box = Box::from(cstr); + let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); + assert_eq!(cstr, &*boxed); + assert_eq!(&*boxed, &*cstring); + assert_eq!(&*cstring, cstr); + } + + #[test] + fn boxed_default() { + let boxed = >::default(); + assert_eq!(boxed.to_bytes_with_nul(), &[0]); + } + + #[test] + fn into_rc() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let rc: Rc = Rc::from(cstr); + let arc: Arc = Arc::from(cstr); + + assert_eq!(&*rc, cstr); + assert_eq!(&*arc, cstr); + + let rc2: Rc = Rc::from(cstr.to_owned()); + let arc2: Arc = Arc::from(cstr.to_owned()); + + assert_eq!(&*rc2, cstr); + assert_eq!(&*arc2, cstr); + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/lib.rs new file mode 100644 index 0000000..e8f61fe --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/cstring/src/lib.rs @@ -0,0 +1,24 @@ +#![no_std] +mod cstr_core; +extern crate alloc; +use crate::alloc::borrow::ToOwned; +use alloc::string::String; +use core::convert::TryInto; + +pub fn from_str(s: &str) -> usize { + cstr_core::CString::new(s).unwrap().into_raw() as usize +} + +pub fn try_into_string(start: impl TryInto) -> Result { + if let Ok(pos) = start.try_into() { + let s: &cstr_core::CStr = + unsafe { cstr_core::CStr::from_ptr(pos as *const cstr_core::c_char) }; + if let Ok(s) = s.to_str() { + Ok(s.to_owned()) + } else { + Err("error creating cstring") + } + } else { + Err("could not decypher cstring starting point") + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/html_color/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/html_color/Cargo.toml new file mode 100644 index 0000000..b280e56 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/html_color/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "html_color" +version = "0.0.0" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "A library of web colors" +repository = "https://github.com/richardanaya/js-wasm" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/html_color/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/html_color/src/lib.rs new file mode 100644 index 0000000..6d3ba45 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/html_color/src/lib.rs @@ -0,0 +1,150 @@ +#![no_std] + +pub const ALICEBLUE: &'static str = "aliceblue"; +pub const ANTIQUEWHITE: &'static str = "antiquewhite"; +pub const AQUA: &'static str = "aqua"; +pub const AQUAMARINE: &'static str = "aquamarine"; +pub const AZURE: &'static str = "azure"; +pub const BEIGE: &'static str = "beige"; +pub const BISQUE: &'static str = "bisque"; +pub const BLACK: &'static str = "black"; +pub const BLANCHEDALMOND: &'static str = "blanchedalmond"; +pub const BLUE: &'static str = "blue"; +pub const BLUEVIOLET: &'static str = "blueviolet"; +pub const BROWN: &'static str = "brown"; +pub const BURLYWOOD: &'static str = "burlywood"; +pub const CADETBLUE: &'static str = "cadetblue"; +pub const CHARTREUSE: &'static str = "chartreuse"; +pub const CHOCOLATE: &'static str = "chocolate"; +pub const CORAL: &'static str = "coral"; +pub const CORNFLOWERBLUE: &'static str = "cornflowerblue"; +pub const CORNSILK: &'static str = "cornsilk"; +pub const CRIMSON: &'static str = "crimson"; +pub const CYAN: &'static str = "cyan"; +pub const DARKBLUE: &'static str = "darkblue"; +pub const DARKCYAN: &'static str = "darkcyan"; +pub const DARKGOLDENROD: &'static str = "darkgoldenrod"; +pub const DARKGRAY: &'static str = "darkgray"; +pub const DARKGREEN: &'static str = "darkgreen"; +pub const DARKGREY: &'static str = "darkgrey"; +pub const DARKKHAKI: &'static str = "darkkhaki"; +pub const DARKMAGENTA: &'static str = "darkmagenta"; +pub const DARKOLIVEGREEN: &'static str = "darkolivegreen"; +pub const DARKORANGE: &'static str = "darkorange"; +pub const DARKORCHID: &'static str = "darkorchid"; +pub const DARKRED: &'static str = "darkred"; +pub const DARKSALMON: &'static str = "darksalmon"; +pub const DARKSEAGREEN: &'static str = "darkseagreen"; +pub const DARKSLATEBLUE: &'static str = "darkslateblue"; +pub const DARKSLATEGRAY: &'static str = "darkslategray"; +pub const DARKSLATEGREY: &'static str = "darkslategrey"; +pub const DARKTURQUOISE: &'static str = "darkturquoise"; +pub const DARKVIOLET: &'static str = "darkviolet"; +pub const DEEPPINK: &'static str = "deeppink"; +pub const DEEPSKYBLUE: &'static str = "deepskyblue"; +pub const DIMGRAY: &'static str = "dimgray"; +pub const DIMGREY: &'static str = "dimgrey"; +pub const DODGERBLUE: &'static str = "dodgerblue"; +pub const FIREBRICK: &'static str = "firebrick"; +pub const FLORALWHITE: &'static str = "floralwhite"; +pub const FORESTGREEN: &'static str = "forestgreen"; +pub const FUCHSIA: &'static str = "fuchsia"; +pub const GAINSBORO: &'static str = "gainsboro"; +pub const GHOSTWHITE: &'static str = "ghostwhite"; +pub const GOLDENROD: &'static str = "goldenrod"; +pub const GOLD: &'static str = "gold"; +pub const GRAY: &'static str = "gray"; +pub const GREEN: &'static str = "green"; +pub const GREENYELLOW: &'static str = "greenyellow"; +pub const GREY: &'static str = "grey"; +pub const HONEYDEW: &'static str = "honeydew"; +pub const HOTPINK: &'static str = "hotpink"; +pub const INDIANRED: &'static str = "indianred"; +pub const INDIGO: &'static str = "indigo"; +pub const IVORY: &'static str = "ivory"; +pub const KHAKI: &'static str = "khaki"; +pub const LAVENDERBLUSH: &'static str = "lavenderblush"; +pub const LAVENDER: &'static str = "lavender"; +pub const LAWNGREEN: &'static str = "lawngreen"; +pub const LEMONCHIFFON: &'static str = "lemonchiffon"; +pub const LIGHTBLUE: &'static str = "lightblue"; +pub const LIGHTCORAL: &'static str = "lightcoral"; +pub const LIGHTCYAN: &'static str = "lightcyan"; +pub const LIGHTGOLDENRODYELLOW: &'static str = "lightgoldenrodyellow"; +pub const LIGHTGRAY: &'static str = "lightgray"; +pub const LIGHTGREEN: &'static str = "lightgreen"; +pub const LIGHTGREY: &'static str = "lightgrey"; +pub const LIGHTPINK: &'static str = "lightpink"; +pub const LIGHTSALMON: &'static str = "lightsalmon"; +pub const LIGHTSEAGREEN: &'static str = "lightseagreen"; +pub const LIGHTSKYBLUE: &'static str = "lightskyblue"; +pub const LIGHTSLATEGRAY: &'static str = "lightslategray"; +pub const LIGHTSLATEGREY: &'static str = "lightslategrey"; +pub const LIGHTSTEELBLUE: &'static str = "lightsteelblue"; +pub const LIGHTYELLOW: &'static str = "lightyellow"; +pub const LIME: &'static str = "lime"; +pub const LIMEGREEN: &'static str = "limegreen"; +pub const LINEN: &'static str = "linen"; +pub const MAGENTA: &'static str = "magenta"; +pub const MAROON: &'static str = "maroon"; +pub const MEDIUMAQUAMARINE: &'static str = "mediumaquamarine"; +pub const MEDIUMBLUE: &'static str = "mediumblue"; +pub const MEDIUMORCHID: &'static str = "mediumorchid"; +pub const MEDIUMPURPLE: &'static str = "mediumpurple"; +pub const MEDIUMSEAGREEN: &'static str = "mediumseagreen"; +pub const MEDIUMSLATEBLUE: &'static str = "mediumslateblue"; +pub const MEDIUMSPRINGGREEN: &'static str = "mediumspringgreen"; +pub const MEDIUMTURQUOISE: &'static str = "mediumturquoise"; +pub const MEDIUMVIOLETRED: &'static str = "mediumvioletred"; +pub const MIDNIGHTBLUE: &'static str = "midnightblue"; +pub const MINTCREAM: &'static str = "mintcream"; +pub const MISTYROSE: &'static str = "mistyrose"; +pub const MOCCASIN: &'static str = "moccasin"; +pub const NAVAJOWHITE: &'static str = "navajowhite"; +pub const NAVY: &'static str = "navy"; +pub const OLDLACE: &'static str = "oldlace"; +pub const OLIVE: &'static str = "olive"; +pub const OLIVEDRAB: &'static str = "olivedrab"; +pub const ORANGE: &'static str = "orange"; +pub const ORANGERED: &'static str = "orangered"; +pub const ORCHID: &'static str = "orchid"; +pub const PALEGOLDENROD: &'static str = "palegoldenrod"; +pub const PALEGREEN: &'static str = "palegreen"; +pub const PALETURQUOISE: &'static str = "paleturquoise"; +pub const PALEVIOLETRED: &'static str = "palevioletred"; +pub const PAPAYAWHIP: &'static str = "papayawhip"; +pub const PEACHPUFF: &'static str = "peachpuff"; +pub const PERU: &'static str = "peru"; +pub const PINK: &'static str = "pink"; +pub const PLUM: &'static str = "plum"; +pub const POWDERBLUE: &'static str = "powderblue"; +pub const PURPLE: &'static str = "purple"; +pub const REBECCAPURPLE: &'static str = "rebeccapurple"; +pub const RED: &'static str = "red"; +pub const ROSYBROWN: &'static str = "rosybrown"; +pub const ROYALBLUE: &'static str = "royalblue"; +pub const SADDLEBROWN: &'static str = "saddlebrown"; +pub const SALMON: &'static str = "salmon"; +pub const SANDYBROWN: &'static str = "sandybrown"; +pub const SEAGREEN: &'static str = "seagreen"; +pub const SEASHELL: &'static str = "seashell"; +pub const SIENNA: &'static str = "sienna"; +pub const SILVER: &'static str = "silver"; +pub const SKYBLUE: &'static str = "skyblue"; +pub const SLATEBLUE: &'static str = "slateblue"; +pub const SLATEGRAY: &'static str = "slategray"; +pub const SLATEGREY: &'static str = "slategrey"; +pub const SNOW: &'static str = "snow"; +pub const SPRINGGREEN: &'static str = "springgreen"; +pub const STEELBLUE: &'static str = "steelblue"; +pub const TAN: &'static str = "tan"; +pub const TEAL: &'static str = "teal"; +pub const THISTLE: &'static str = "thistle"; +pub const TOMATO: &'static str = "tomato"; +pub const TURQUOISE: &'static str = "turquoise"; +pub const VIOLET: &'static str = "violet"; +pub const WHEAT: &'static str = "wheat"; +pub const WHITE: &'static str = "white"; +pub const WHITESMOKE: &'static str = "whitesmoke"; +pub const YELLOW: &'static str = "yellow"; +pub const YELLOWGREEN: &'static str = "yellowgreen"; diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/Cargo.toml new file mode 100644 index 0000000..7d17e02 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "js-bindgen" +version = "0.0.6" +authors = ["Richard Anaya"] +edition = "2018" +description = "Generate bindings that call JavaScript from WebAssembly" +license = "MIT OR Apache-2.0" +categories = ["wasm"] +repository = "https://github.com/richardanaya/js-wasm" +readme="README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tera = "1" +serde = { version = "1.0", features = ["derive"] } +Inflector = "0.11.4" +serde_yaml = "0" +clap="2" diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/README.md new file mode 100644 index 0000000..bff97f3 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/README.md @@ -0,0 +1,162 @@ +# js-bindgen + +

+ +

+ +**The project is very ALPHA right now, but it is generating some very basic bindings for Rust and C right now** + +Generate WebAssembly bindings to JavaSCript via [`js-wasm`](https://wasm.js.org) for various languages: + +* Rust +* C +* AssemblyScript + +``` +cargo install js-bindgen +``` + +# Getting Started + +This project is able to take JavaScript API descriptions in yaml like the one below: + +```yaml +Bindings to web console +---- +- namespace: console + functions: + - name: clear + - name: log + parameters: + - name: msg + parameter_type: string + - name: warn + friendly_name: warning + parameters: + - name: msg + parameter_type: string + - name: error + parameters: + - name: msg + parameter_type: string + - name: time + parameters: + - name: msg + parameter_type: string + - name: timeEnd + parameters: + - name: msg + parameter_type: string + +``` + +And turn them into code. + +# Rust + +``` +js-bindgen --lang rust console.yaml +``` + +```rust +#![no_std] + +pub mod console { + use js::*; + + pub fn clear(){ + let func = js!(r###"function(){ + console.clear(); + }"###); + func.invoke_0(); + } + + pub fn log(msg: &str){ + let a0 = msg.as_ptr() as u32; + let a1 = msg.len() as u32; + let func = js!(r###"function(msgPtr,msgLen){ + console.log(this.readUtf8FromMemory(msgPtr,msgLen)); + }"###); + func.invoke_2(a0, a1); + } + +... +``` + +# C + +``` +js-bindgen --lang c console.yaml +``` + +```C +#include "js-wasm.h" + +void console_clear(){ + static int fn; + char *fn_code = "function(){ console.clear(); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_0(fn); +} + +void console_log(char * msg){ + static int fn; + unsigned int a0 = (unsigned int)msg; + unsigned int a1 = js_strlen(msg); + char *fn_code = "function(msgPtr,msgLen){ console.log(this.readUtf8FromMemory(msgPtr,msgLen)); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_2(fn, a0, a1); +} + +... +``` + +# AssemblyScript + +``` +js-bindgen --lang assemblyscript console.yaml +``` + +```ts +import * as jswasm from "./js-wasm" + +let console_clear_fn:f64 = 0; +export function console_clear() : void { + if( console_clear_fn === 0) { + const code = `function(){ console.clear(); }`; + console_clear_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_0(console_clear_fn); +} + +let console_log_fn:f64 = 0; +export function console_log(msg: string) : void { + const a0: f64 = changetype(msg); + const a1: f64 = msg.length*2; + if( console_log_fn === 0) { + const code = `function(msgPtr,msgLen){ console.log(this.readUtf16FromMemory(msgPtr,msgLen)); }`; + console_log_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + jswasm.js_invoke_function_2(console_log_fn, a0, a1); +} + +... +``` + +# Custom Code + +Sometimes you may want to create a binding to code that doesn't exist and still have the power to generate libraries for many targets + +```yaml +- namespace: unicorn + functions: + makeUnicorns: + code: | + function() { + console.log("🦄🦄🦄") + } +``` diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/main.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/main.rs new file mode 100644 index 0000000..a46ab4e --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/main.rs @@ -0,0 +1,96 @@ +use inflector::Inflector; +use serde::*; +use tera::*; +use clap::{Arg, App }; + +fn main() { + let matches = App::new("js-bindgen") + .version("0.0") + .author("Richard Anaya ") + .about("Creates js-wasm bindings for various languages") + .arg(Arg::with_name("lang") + .short("l") + .long("language") + .help("Sets a custom config file") + .takes_value(true) + .required(true)) + .arg(Arg::with_name("INPUT") + .help("Sets the input file to use") + .required(true) + .index(1)) + .get_matches(); + + + let mut tera = Tera::default(); + tera.add_raw_template("rust/module.rs", include_str!("templates/rust/module.rs")) + .unwrap(); + + tera.add_raw_template("c/header.h", include_str!("templates/c/header.h")) + .unwrap(); + + tera.add_raw_template("assemblyscript/module.ts", include_str!("templates/assemblyscript/module.ts")) + .unwrap(); + + let file = matches.value_of("INPUT").unwrap(); + let text = std::fs::read_to_string(file).unwrap(); + + let mut bindings: Vec = serde_yaml::from_str(&text).unwrap(); + + for n in bindings.iter_mut() { + if let Some(fs) = &mut n.functions { + for f in fs.iter_mut() { + if f.friendly_name.is_none() { + f.friendly_name = Some(f.name.to_snake_case()) + } + if let Some(ps) = &mut f.parameters { + for p in ps.iter_mut() { + if p.friendly_name.is_none() { + p.friendly_name = Some(p.name.to_snake_case()) + } + } + } else { + f.parameters = Some(vec![]); + } + } + } else { + n.functions = Some(vec![]); + } + } + + let mut context = Context::new(); + context.insert("bindings", &bindings); + + if let Some(l) = matches.value_of("lang") { + let r = if l == "rust" { + tera.render("rust/module.rs", &context).unwrap() + } else if l == "assemblyscript" { + tera.render("assemblyscript/module.ts", &context).unwrap() + } else { + tera.render("c/header.h", &context).unwrap() + }; + println!("{}", r); + } +} + +#[derive(Serialize, Deserialize)] +struct JSParameter { + name: String, + friendly_name: Option, + parameter_type: String, +} + +#[derive(Serialize, Deserialize)] +struct JSFunction { + name: String, + friendly_name: Option, + parameters: Option>, + output: Option, + code: Option +} + +#[derive(Serialize, Deserialize)] +struct Binding { + namespace: Option, + class: Option, + functions: Option>, +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/assemblyscript/module.ts b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/assemblyscript/module.ts new file mode 100644 index 0000000..2d2c32a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/assemblyscript/module.ts @@ -0,0 +1,77 @@ +import * as jswasm from "./js-wasm" + +{%- for binding in bindings %} + +{%- for function in binding.functions %} +let {{binding.namespace}}_{% if function.friendly_name -%} +{{function.friendly_name}} +{%- else -%} +{{function.name}} +{%- endif -%}_fn:f64 = 0; +export function {{binding.namespace}}_{% if function.friendly_name -%} + {{function.friendly_name}} + {%- else -%} + {{function.name}} + {%- endif -%}( + {%- for param in function.parameters -%}{{param.friendly_name}}: {% if param.parameter_type == "string" -%} + string + {%- else -%} + f64 + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){% if function.output %} : f64{% else %} : void{% endif %} { + {% set_global i = 0 %} + {%- for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + const a{{i}}: f64 = changetype({{param.friendly_name}}); + {% set_global i = i + 1 -%} + const a{{i}}: f64 = {{param.friendly_name}}.length*2; + {% else %} + const a{{i}}: f64 = {{param.friendly_name}}; + {% endif -%} + {% set_global i = i + 1 %} + {%- endfor -%} + if( {{binding.namespace}}_{% if function.friendly_name -%} + {{function.friendly_name}} + {%- else -%} + {{function.name}} + {%- endif -%}_fn === 0) { + const code = `function({% for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + {{param.name}}Ptr,{{param.name}}Len + {%- else -%} + {{param.name}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){ {% if function.output -%}return {% endif %}{% if function.output == "object" %} this.storeObject({% endif %}{{binding.namespace}}.{{function.name}}({% for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + this.readUtf16FromMemory({{param.name}}Ptr,{{param.name}}Len) + {%- elif param.parameter_type == "object" -%}this.getObject({{param.name}}) + {%- else -%}{{param.name}} + {%- endif -%}{%- if not loop.last -%}, {% endif -%}{%- endfor -%}){% if function.output == "object" %}){% endif %}; }`; + {{binding.namespace}}_{% if function.friendly_name -%} + {{function.friendly_name}} + {%- else -%} + {{function.name}} + {%- endif -%}_fn = jswasm.js_register_function(changetype(code),code.length*2, 16); + } + {% if function.output -%}return {% endif %}jswasm.js_invoke_function_{{i}}({{binding.namespace}}_{% if function.friendly_name -%} + {{function.friendly_name}} + {%- else -%} + {{function.name}} + {%- endif -%}_fn{% if function.parameters | length > 0 %}, {% endif %}{% set i = 0 -%} + {%- for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + a{{i}}, {% set i = i + 1 -%} + a{{i}} + {%- else -%} + a{{i}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}); +} +{% endfor %} +{%- endfor -%} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/c/header.h b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/c/header.h new file mode 100644 index 0000000..b6f6123 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/c/header.h @@ -0,0 +1,61 @@ +#include "js-wasm.h" + +{%- for binding in bindings %} +{%- for function in binding.functions %} + +{% if function.output -%}double{% else %}void{% endif %} {{binding.namespace}}_{% if function.friendly_name -%} +{{function.friendly_name}} +{%- else -%} +{{function.name}} +{%- endif -%}( + {%- for param in function.parameters -%} {% if param.parameter_type == "string" -%} + char * + {%- else -%} + double + {%- endif %} {{param.friendly_name}} + {%- if not loop.last -%} + , {% endif %} + {%- endfor -%}){ + static int fn; + {% set_global i = 0 %} + {%- for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + unsigned int a{{i}} = (unsigned int){{param.friendly_name}}; + {% set_global i = i + 1 -%} + unsigned int a{{i}} = js_strlen({{param.friendly_name}}); + {% else %} + double a{{i}} = {{param.friendly_name}}; + {% endif -%} + {% set_global i = i + 1 %} + {%- endfor -%} + char *fn_code = "function({% for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + {{param.name}}Ptr,{{param.name}}Len + {%- else -%} + {{param.name}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){ {% if function.output -%}return {% endif %}{% if function.output == "object" %} this.storeObject({% endif %}{{binding.namespace}}.{{function.name}}({% for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + this.readUtf8FromMemory({{param.name}}Ptr,{{param.name}}Len) + {%- elif param.parameter_type == "object" -%}this.getObject({{param.name}}) + {%- else -%}{{param.name}} + {%- endif -%}{%- if not loop.last -%}, {% endif -%}{%- endfor -%}){% if function.output == "object" %}){% endif %}; }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + {% if function.output -%}return {% endif %}js_invoke_function_{{i}}(fn{% if function.parameters | length > 0 %}, {% endif %}{% set i = 0 -%} + {%- for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + a{{i}}, {% set i = i + 1 -%} + a{{i}} + {%- else -%} + a{{i}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}); +} +{%- endfor %} +{%- endfor -%} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/rust/module.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/rust/module.rs new file mode 100644 index 0000000..b68e99b --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js-bindgen/src/templates/rust/module.rs @@ -0,0 +1,68 @@ +#![no_std] + +use js::*; + +{%- for binding in bindings %} + +{%- for function in binding.functions %} + +pub fn {{binding.namespace}}_{% if function.friendly_name -%} + {{function.friendly_name}} + {%- else -%} + {{function.name}} + {%- endif -%}( + {%- for param in function.parameters -%}{{param.friendly_name}}: {% if param.parameter_type == "string" -%} + &str + {%- else -%} + impl Into + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){% if function.output %} -> f64{% endif %} { + {% set_global i = 0 %} + {%- for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + let a{{i}} = {{param.friendly_name}}.as_ptr() as u32; + {% set_global i = i + 1 -%} + let a{{i}} = {{param.friendly_name}}.len() as u32; + {% else -%} + let a{{i}} = {{param.friendly_name}}.into(); + {% endif -%} + {% set_global i = i + 1 %} + {%- endfor -%} + let func = js!(r###"function({% for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + {{param.name}}Ptr,{{param.name}}Len + {%- else -%} + {{param.name}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){ + {% if function.output -%}return {% endif %}{% if function.output == "object" %} this.storeObject({% endif %}{{binding.namespace}}.{{function.name}}({% for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + this.readUtf8FromMemory({{param.name}}Ptr,{{param.name}}Len) + {%- elif param.parameter_type == "object" -%} + this.getObject({{param.name}}) + {%- else -%} + {{param.name}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){% if function.output == "object" %}){% endif %}; + }"###); + func.invoke_{{i}}( + {%- set i = 0 -%} + {%- for param in function.parameters -%} + {%- if param.parameter_type == "string" -%} + a{{i}}, {% set i = i + 1 -%} + a{{i}} + {%- else -%} + a{{i}} + {%- endif -%} + {%- if not loop.last -%} + , {% endif -%} + {%- endfor -%}){%- if not function.output -%};{%- endif %} +} +{%- endfor %} +{%- endfor -%} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/js/Cargo.toml new file mode 100644 index 0000000..18386e1 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "js" +version = "0.4.3" +authors = ["Richard Anaya"] +edition = "2021" +description = "Call JavaScript from WebAssembly" +license = "MIT OR Apache-2.0" +categories = ["wasm", "no-std"] +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" +rust-version="1.62" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +callback= {path="../callback",version="0.5"} +spin = "0.9.4" diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/js/README.md new file mode 100644 index 0000000..19b5efa --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js/README.md @@ -0,0 +1,20 @@ +# js-rs + +A library for creating and invoking JavaScript functions from Rust. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'js' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/js/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/js/src/lib.rs new file mode 100644 index 0000000..ed259d2 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/js/src/lib.rs @@ -0,0 +1,447 @@ +#![no_std] +#![allow(clippy::too_many_arguments)] +extern crate alloc; +use alloc::string::String; +use alloc::vec::Vec; +pub use callback::*; +use spin::Mutex; + +pub const JS_NULL: f64 = 0.0; +pub const JS_UNDEFINED: f64 = 1.0; +pub const DOM_SELF: f64 = 2.0; +pub const DOM_WINDOW: f64 = 2.0; +pub const DOM_DOCUMENT: f64 = 3.0; +pub const DOM_BODY: f64 = 4.0; + +extern "C" { + fn js_register_function(start: f64, len: f64) -> f64; + fn js_release(obj: f64); + fn js_invoke_function( + fn_handle: f64, + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, + f: f64, + g: f64, + h: f64, + i: f64, + j: f64, + ) -> f64; +} + +#[derive(Copy, Clone)] +pub struct JSFunction { + pub fn_handle: f64, +} + +impl From for JSFunction { + fn from(f: f64) -> Self { + JSFunction { fn_handle: f } + } +} + +impl From<&JSFunction> for f64 { + fn from(f: &JSFunction) -> Self { + f.fn_handle + } +} + +impl JSFunction { + pub fn invoke_0(&self) -> f64 +where { + unsafe { + js_invoke_function( + self.fn_handle, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_1(&self, a: A) -> f64 + where + A: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_2(&self, a: A, b: B) -> f64 + where + A: Into, + B: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_3(&self, a: A, b: B, c: C) -> f64 + where + A: Into, + B: Into, + C: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_4(&self, a: A, b: B, c: C, d: D) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_5(&self, a: A, b: B, c: C, d: D, e: E) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + E: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + e.into(), + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_6(&self, a: A, b: B, c: C, d: D, e: E, f: F) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + E: Into, + F: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + e.into(), + f.into(), + 0.0, + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_7(&self, a: A, b: B, c: C, d: D, e: E, f: F, g: G) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + E: Into, + F: Into, + G: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + e.into(), + f.into(), + g.into(), + 0.0, + 0.0, + 0.0, + ) + } + } + + pub fn invoke_8( + &self, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + ) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + E: Into, + F: Into, + G: Into, + H: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + e.into(), + f.into(), + g.into(), + h.into(), + 0.0, + 0.0, + ) + } + } + + pub fn invoke_9( + &self, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + ) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + E: Into, + F: Into, + G: Into, + H: Into, + I: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + e.into(), + f.into(), + g.into(), + h.into(), + i.into(), + 0.0, + ) + } + } + + pub fn invoke_10( + &self, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + ) -> f64 + where + A: Into, + B: Into, + C: Into, + D: Into, + E: Into, + F: Into, + G: Into, + H: Into, + I: Into, + J: Into, + { + unsafe { + js_invoke_function( + self.fn_handle, + a.into(), + b.into(), + c.into(), + d.into(), + e.into(), + f.into(), + g.into(), + h.into(), + i.into(), + j.into(), + ) + } + } +} + +pub fn register_function(code: &str) -> JSFunction { + let start = code.as_ptr(); + let len = code.len(); + unsafe { + JSFunction { + fn_handle: js_register_function(start as usize as f64, len as f64), + } + } +} + +pub struct JSObject { + pub handle: f64, +} + +impl From<&JSObject> for f64 { + fn from(f: &JSObject) -> Self { + f.handle + } +} + +impl From for JSObject { + fn from(n: f64) -> Self { + JSObject { handle: n } + } +} + +impl Drop for JSObject { + fn drop(&mut self) { + unsafe { + js_release(self.handle); + } + } +} + +static ALLOCATIONS: Mutex>>> = Mutex::new(Vec::new()); + +pub fn extract_string_from_memory(allocation_id: usize) -> String { + let allocations = ALLOCATIONS.lock(); + let allocation = allocations.get(allocation_id).unwrap(); + let vec = allocation.as_ref().unwrap(); + String::from_utf8(vec.clone()).unwrap() +} + +#[no_mangle] +pub fn create_allocation(size: usize) -> usize { + let mut buf = Vec::with_capacity(size as usize); + buf.resize(size, 0); + let mut allocations = ALLOCATIONS.lock(); + let i = allocations.len(); + allocations.push(Some(buf)); + i +} + +#[no_mangle] +pub fn allocation_ptr(allocation_id: i32) -> *const u8 { + let allocations = ALLOCATIONS.lock(); + let allocation = allocations.get(allocation_id as usize).unwrap(); + let vec = allocation.as_ref().unwrap(); + vec.as_ptr() +} + +#[no_mangle] +pub fn allocation_len(allocation_id: i32) -> f64 { + let allocations = ALLOCATIONS.lock(); + let allocation = allocations.get(allocation_id as usize).unwrap(); + let vec = allocation.as_ref().unwrap(); + vec.len() as f64 +} + +pub fn clear_allocation(allocation_id: usize) { + let mut allocations = ALLOCATIONS.lock(); + allocations[allocation_id] = None; +} + +#[macro_export] +macro_rules! js { + ($e:expr) => {{ + static mut FN: Option = None; + unsafe { + if FN.is_none() { + FN = Some(js::register_function($e).fn_handle); + } + JSFunction { + fn_handle: FN.unwrap(), + } + } + }}; +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web/Cargo.toml new file mode 100644 index 0000000..b741403 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "web" +version = "0.1.16" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "A library for interacting with the web browser" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +web_common={path="../../crates/web_common",version="0"} +web-dom={path="../../crates/web_dom",version="0"} +web_console={path="../../crates/web_console",version="0"} +web_random={path="../../crates/web_random",version="0"} +web_timer={path="../../crates/web_timer",version="0"} +web_canvas={path="../../crates/web_canvas",version="0"} +html_color={path="../../crates/html_color",version="0"} +js = {path="../js",version="0"} +class_names= "0" +spin = "0.9.0" +web_local_storage={path="../../crates/web_local_storage",version="0"} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web/README.md new file mode 100644 index 0000000..20dbac2 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web/README.md @@ -0,0 +1,70 @@ +# web-rs + +docs.rs docs + +A Rust library full of useful functions from various microlibraries for interacting with the web browser using [`js-wasm`](../../). + +

+ +

+ +```toml +[dependencies] +web = "0.1" +``` + +```rust +use web::*; + +#[no_mangle] +pub fn main() { + set_interval(|| { + log(&format!("⏰ {}", random())); + }, 1000); +} +``` +```html + + + + + + + ... + + +``` +```make +# cli commands for building web assembly +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/helloworld.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8080 +``` + +- [x] console, errors, timing +- [x] timers, render loops, intervals +- [x] random numbers +- [ ] DOM +- [ ] canvas +- [ ] webgl + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `web` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web/src/lib.rs new file mode 100644 index 0000000..34ed279 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web/src/lib.rs @@ -0,0 +1,12 @@ +#![no_std] +pub use class_names::*; +pub use html_color::*; +pub use js::*; +pub use spin::{Mutex, MutexGuard}; +pub use web_canvas::*; +pub use web_common::*; +pub use web_console::*; +pub use web_dom::*; +pub use web_local_storage::*; +pub use web_random::*; +pub use web_timer::*; diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/Cargo.toml new file mode 100644 index 0000000..ff80705 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "web_canvas" +version = "0.0.7" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for canvas 2D" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/README.md new file mode 100644 index 0000000..f80a4e3 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/README.md @@ -0,0 +1,20 @@ +# web_console + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'web_console' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/src/lib.rs new file mode 100644 index 0000000..9a57c56 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_canvas/src/lib.rs @@ -0,0 +1,71 @@ +#![no_std] +use js::*; + +pub struct CanvasContext { + pub handle: f64, +} + +pub trait Canvas2dApi { + fn set_fill_color(&self, color: &str); + fn fill_rect(&self, x: impl Into, y: impl Into, w: impl Into, h: impl Into); + fn clear_rect( + &self, + x: impl Into, + y: impl Into, + w: impl Into, + h: impl Into, + ); +} + +impl CanvasContext { + pub fn from_canvas_element(el: impl Into) -> CanvasContext { + CanvasContext { + handle: { + js!(r#"function(el){ + el = this.getObject(el); + let ctx = el.getContext("2d"); + return this.storeObject(ctx); + }"#) + .invoke_1(el.into()) + }, + } + } +} + +impl Canvas2dApi for CanvasContext { + fn set_fill_color(&self, color: &str) { + js!("function(ctx,strPtr,strLen){ + ctx = this.getObject(ctx); + ctx.fillStyle = this.readUtf8FromMemory(strPtr,strLen); + }") + .invoke_3(self.handle, color.as_ptr() as u32, color.len() as u32); + } + + fn fill_rect( + &self, + x: impl Into, + y: impl Into, + w: impl Into, + h: impl Into, + ) { + js!("function(ctx,x,y,w,h){ + ctx = this.getObject(ctx); + ctx.fillRect(x,y,w,h); + }") + .invoke_5(self.handle, x, y, w, h); + } + + fn clear_rect( + &self, + x: impl Into, + y: impl Into, + w: impl Into, + h: impl Into, + ) { + js!("function(ctx,x,y,w,h){ + ctx = this.getObject(ctx); + ctx.clearRect(x,y,w,h); + }") + .invoke_5(self.handle, x, y, w, h); + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/Cargo.toml new file mode 100644 index 0000000..732ac01 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "web_common" +version = "0.4.3" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for common operations" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/README.md new file mode 100644 index 0000000..969d0f7 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/README.md @@ -0,0 +1,20 @@ +# web_common + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `web_common` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/src/lib.rs new file mode 100644 index 0000000..f874360 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_common/src/lib.rs @@ -0,0 +1,222 @@ +#![no_std] +use js::*; +extern crate alloc; + +pub trait GetProperty { + fn get_property(el: impl Into, name: &str) -> Option + where + Self: Sized; +} + +impl GetProperty for f64 { + fn get_property(el: impl Into, name: &str) -> Option { + let v = el.into(); + if !is_property_number(v, name) { + return None; + } + Some( + js!("function(el,strPtr,strLen){ + el = this.getObject(el); + return el[this.readUtf8FromMemory(strPtr,strLen)]; + }") + .invoke_3(v, name.as_ptr() as u32, name.len() as u32), + ) + } +} + +impl GetProperty for bool { + fn get_property(el: impl Into, name: &str) -> Option { + let v = js!(r#"function(el,strPtr,strLen){ + el = this.getObject(el); + let i = el[this.readUtf8FromMemory(strPtr,strLen)]; + if(typeof i !== "boolean"){ + return -1; + } + return el[this.readUtf8FromMemory(strPtr,strLen)] ? 1 : 0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + if v == -1.0 { + return None; + } else { + Some(v == 1.0) + } + } +} + +impl GetProperty for alloc::string::String { + fn get_property(el: impl Into, name: &str) -> Option { + let attr = js!(r#"function(o,strPtr,strLen){ + o = this.getObject(o); + const a = o[this.readUtf8FromMemory(strPtr,strLen)]; + if(a === null){ + return -1; + } + return this.writeUtf8ToMemory(a); + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + if attr == -1.0 { + return None; + } else { + let allocation_id = attr as usize; + let s = extract_string_from_memory(allocation_id); + clear_allocation(allocation_id); + Some(s) + } + } +} + +impl GetProperty for JSObject { + fn get_property(el: impl Into, name: &str) -> Option { + let o = js!(r#"function(o,strPtr,strLen){ + o = this.getObject(o); + const a = o[this.readUtf8FromMemory(strPtr,strLen)]; + if(a === null){ + return -1; + } + return this.storeObject(a); + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + if o == -1.0 { + return None; + } else { + Some(JSObject::from(o)) + } + } +} + +pub fn get_property(el: impl Into, id: &str) -> Option +where + T: GetProperty, +{ + T::get_property(el, id) +} + +pub trait SetProperty { + fn set_property(el: impl Into, id: &str, s: Self); +} + +impl SetProperty for f64 { + fn set_property(el: impl Into, id: &str, v: Self) { + js!("function(el,strPtr,strLen,value){ + el = this.getObject(el); + return el[this.readUtf8FromMemory(strPtr,strLen)] = value; + }") + .invoke_4(el.into(), id.as_ptr() as u32, id.len() as u32, v); + } +} + +impl SetProperty for &str { + fn set_property(el: impl Into, name: &str, txt: Self) { + js!(r#"function(o,strPtr,strLen,valPtr,valLen){ + o = this.getObject(o); + o[this.readUtf8FromMemory(strPtr,strLen)] = this.readUtf8FromMemory(valPtr,valLen); + }"#) + .invoke_5( + el.into(), + name.as_ptr() as u32, + name.len() as u32, + txt.as_ptr() as u32, + txt.len() as u32, + ); + } +} + +impl SetProperty for bool { + fn set_property(el: impl Into, name: &str, value: Self) { + js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + o[this.readUtf8FromMemory(strPtr,strLen)] = val > 0; + }"#) + .invoke_4( + el.into(), + name.as_ptr() as u32, + name.len() as u32, + if value { 1.0 } else { 0.0 }, + ); + } +} + +impl SetProperty for JSObject { + fn set_property(el: impl Into, name: &str, value: Self) { + js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + o[this.readUtf8FromMemory(strPtr,strLen)] = this.getObject(val); + }"#) + .invoke_4( + el.into(), + name.as_ptr() as u32, + name.len() as u32, + value.handle, + ); + } +} + +pub fn set_property(el: impl Into, id: &str, v: T) +where + T: SetProperty, +{ + T::set_property(el, id, v) +} + +pub fn is_property_null(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return o[this.readUtf8FromMemory(strPtr,strLen)] === null ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} + +pub fn is_property_undefined(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return o[this.readUtf8FromMemory(strPtr,strLen)] === undefined ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} + +pub fn is_property_number(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return typeof o[this.readUtf8FromMemory(strPtr,strLen)] === "number" ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} + +pub fn is_property_bool(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return typeof o[this.readUtf8FromMemory(strPtr,strLen)] === "boolean" ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} + +pub fn is_property_string(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return typeof o[this.readUtf8FromMemory(strPtr,strLen)] === "string" ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} + +pub fn is_property_object(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return typeof o[this.readUtf8FromMemory(strPtr,strLen)] === "object" ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} + +pub fn is_property_array(el: impl Into, name: &str) -> bool { + let v = js!(r#"function(o,strPtr,strLen,val){ + o = this.getObject(o); + return Array.isArray(o[this.readUtf8FromMemory(strPtr,strLen)]) ? 1.0 : 0.0; + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + v == 1.0 +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/Cargo.toml new file mode 100644 index 0000000..8ead089 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "web_console" +version = "0.3.7" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for console" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/README.md new file mode 100644 index 0000000..f80a4e3 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/README.md @@ -0,0 +1,20 @@ +# web_console + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'web_console' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/src/lib.rs new file mode 100644 index 0000000..dfab465 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_console/src/lib.rs @@ -0,0 +1,55 @@ +#![no_std] + +use js::*; + +pub fn console_clear() { + let func = js!(r###"function(){ + console.clear(); + }"###); + func.invoke_0(); +} + +pub fn console_log(msg: &str) { + let a0 = msg.as_ptr() as u32; + let a1 = msg.len() as u32; + let func = js!(r###"function(msgPtr,msgLen){ + console.log(this.readUtf8FromMemory(msgPtr,msgLen)); + }"###); + func.invoke_2(a0, a1); +} + +pub fn console_warning(msg: &str) { + let a0 = msg.as_ptr() as u32; + let a1 = msg.len() as u32; + let func = js!(r###"function(msgPtr,msgLen){ + console.warn(this.readUtf8FromMemory(msgPtr,msgLen)); + }"###); + func.invoke_2(a0, a1); +} + +pub fn console_error(msg: &str) { + let a0 = msg.as_ptr() as u32; + let a1 = msg.len() as u32; + let func = js!(r###"function(msgPtr,msgLen){ + console.error(this.readUtf8FromMemory(msgPtr,msgLen)); + }"###); + func.invoke_2(a0, a1); +} + +pub fn console_time(msg: &str) { + let a0 = msg.as_ptr() as u32; + let a1 = msg.len() as u32; + let func = js!(r###"function(msgPtr,msgLen){ + console.time(this.readUtf8FromMemory(msgPtr,msgLen)); + }"###); + func.invoke_2(a0, a1); +} + +pub fn console_time_end(msg: &str) { + let a0 = msg.as_ptr() as u32; + let a1 = msg.len() as u32; + let func = js!(r###"function(msgPtr,msgLen){ + console.timeEnd(this.readUtf8FromMemory(msgPtr,msgLen)); + }"###); + func.invoke_2(a0, a1); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/Cargo.toml new file mode 100644 index 0000000..219f885 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "web-dom" +version = "0.3.10" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for DOM manipulation" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} +web_common = {path="../web_common", version="0"} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/README.md new file mode 100644 index 0000000..1286527 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/README.md @@ -0,0 +1,20 @@ +# web_dom + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `web_dom` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/src/lib.rs new file mode 100644 index 0000000..3c5355d --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_dom/src/lib.rs @@ -0,0 +1,221 @@ +#![no_std] +use js::*; +extern crate alloc; +use alloc::boxed::Box; +use alloc::string::String; +use web_common::*; + +pub fn get_element_by_id(id: &str) -> JSObject { + js!("function(strPtr,strLen){ + const el = document.getElementById(this.readUtf8FromMemory(strPtr,strLen)); + return this.storeObject(el); + }") + .invoke_2(id.as_ptr() as u32, id.len() as u32) + .into() +} + +pub fn query_selector(id: &str) -> JSObject { + js!("function(strPtr,strLen){ + const selector = document.querySelector(this.readUtf8FromMemory(strPtr,strLen)); + return this.storeObject(selector); + }") + .invoke_2(id.as_ptr() as u32, id.len() as u32) + .into() +} + +pub fn set_style(dom: impl Into, name: &str, value: &str) { + js!("function(el,strPtr,strLen,valPtr,valLen){ + el = this.getObject(el); + const name = this.readUtf8FromMemory(strPtr,strLen); + const value = this.readUtf8FromMemory(valPtr,valLen); + el.style[name] = value; + }") + .invoke_5( + dom.into(), + name.as_ptr() as u32, + name.len() as u32, + value.as_ptr() as u32, + value.len() as u32, + ); +} + +pub fn add_event_listener( + dom: impl Into, + event: &str, + handler: impl FnMut(f64) + Send + 'static, +) { + let cb = create_callback_1(handler); + js!("function(el,strPtr,strLen,callback){ + el = this.getObject(el); + const event = this.readUtf8FromMemory(strPtr,strLen); + el.addEventListener(event,this.createCallback(callback)); + }") + .invoke_4(dom.into(), event.as_ptr() as u32, event.len() as u32, cb); +} + +pub struct KeyDownEvent { + pub handle: JSObject, +} + +impl KeyDownEvent { + pub fn from_event(ev: impl Into) -> KeyDownEvent { + KeyDownEvent { handle: ev.into() } + } + + pub fn key_code(&self) -> u32 { + js!("function(ev){ + ev = this.getObject(ev); + return ev.keyCode; + }") + .invoke_1(&self.handle) as u32 + } +} + +pub fn attach_shadow(el: impl Into, open: bool) -> JSObject { + js!(r#"function(el,open){ + el = this.getObject(el); + el.attachShadow({mode:open?"open":"closed"}); + return this.storeObject(el.shadowRoot); + }"#) + .invoke_2(el.into(), if open { 1.0 } else { 0.0 }) + .into() +} + +pub fn set_inner_html(el: impl Into, html: &str) { + js!(r#"function(el,strPtr,strLen){ + el = this.getObject(el); + el.innerHTML = this.readUtf8FromMemory(strPtr,strLen); + }"#) + .invoke_3(el.into(), html.as_ptr() as u32, html.len() as u32); +} + +pub fn get_attribute(el: impl Into, name: &str) -> Option { + let attr = js!(r#"function(el,strPtr,strLen){ + el = this.getObject(el); + const a = el.getAttribute(this.readUtf8FromMemory(strPtr,strLen)); + if(a === null){ + return -1; + } + return this.writeUtf8ToMemory(a); + }"#) + .invoke_3(el.into(), name.as_ptr() as u32, name.len() as u32); + if attr == -1.0 { + None + } else { + let allocation_id = attr as usize; + let s = extract_string_from_memory(allocation_id); + clear_allocation(allocation_id); + Some(s) + } +} + +pub struct KeyEventHandler { + pub handler: Option>, +} + +impl KeyEventHandler { + pub fn new(f: impl Sync + FnMut(KeyEvent) + 'static + Send) -> KeyEventHandler { + KeyEventHandler { + handler: Some(Box::new(f)), + } + } +} + +pub struct KeyEvent { + obj: JSObject, +} + +impl KeyEvent { + pub fn new(o: f64) -> KeyEvent { + KeyEvent { + obj: JSObject::from(o), + } + } + + pub fn key_code(&self) -> usize { + let key_code: f64 = get_property(self.obj.handle, "keyCode").unwrap(); + key_code as usize + } + + pub fn target(&self) -> JSObject { + get_property(self.obj.handle, "target").unwrap() + } +} + +pub struct InputElement { + obj: JSObject, +} + +impl InputElement { + pub fn new(o: f64) -> InputElement { + InputElement { + obj: JSObject::from(o), + } + } + + pub fn from(o: JSObject) -> InputElement { + InputElement { obj: o } + } + + pub fn value(&self) -> Option { + get_property(&self.obj, "value") + } + + pub fn set_value(&mut self, s: &str) { + set_property(&self.obj, "value", s) + } +} + +pub struct MouseEventHandler { + pub handler: Option>, +} + +impl MouseEventHandler { + pub fn new(f: impl Sync + FnMut(MouseEvent) + 'static + Send) -> MouseEventHandler { + MouseEventHandler { + handler: Some(Box::new(f)), + } + } +} + +pub struct MouseEvent { + obj: JSObject, +} + +impl MouseEvent { + pub fn new(o: f64) -> MouseEvent { + MouseEvent { + obj: JSObject::from(o), + } + } + pub fn target(&self) -> JSObject { + get_property(self.obj.handle, "target").unwrap() + } +} + +pub struct EventHandler { + pub handler: Option>, +} + +impl EventHandler { + pub fn new(f: impl Sync + FnMut(Event) + 'static + Send) -> EventHandler { + EventHandler { + handler: Some(Box::new(f)), + } + } +} + +pub struct Event { + obj: JSObject, +} + +impl Event { + pub fn new(o: f64) -> Event { + Event { + obj: JSObject::from(o), + } + } + pub fn target(&self) -> JSObject { + get_property(self.obj.handle, "target").unwrap() + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/Cargo.toml new file mode 100644 index 0000000..b32ba53 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "web_local_storage" +version = "0.0.3" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for local storage" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/README.md new file mode 100644 index 0000000..77b4a07 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/README.md @@ -0,0 +1,20 @@ +# web_console + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'web_local_storage' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/src/lib.rs new file mode 100644 index 0000000..403f0db --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_local_storage/src/lib.rs @@ -0,0 +1,53 @@ +#![no_std] +extern crate alloc; +use alloc::string::String; + +use js::*; + +pub fn local_storage_set_item(id: &str, data: &str) { + let a0 = id.as_ptr() as u32; + let a1 = id.len() as u32; + let d0 = data.as_ptr() as u32; + let d1 = data.len() as u32; + let func = js!(r###"function(idPtr,idLen,dataPtr,dataLen){ + window.localStorage.setItem(this.readUtf8FromMemory(idPtr,idLen),this.readUtf8FromMemory(dataPtr,dataLen)); + }"###); + func.invoke_4(a0, a1, d0, d1); +} + +pub fn local_storage_get_item(id: &str) -> Option { + let a0 = id.as_ptr() as u32; + let a1 = id.len() as u32; + let func = js!(r###"function(idPtr,idLen){ + const a = window.localStorage.getItem(this.readUtf8FromMemory(idPtr,idLen)); + if(a === null){ + return -1; + } + return this.writeUtf8ToMemory(a); + }"###); + let txt = func.invoke_2(a0, a1); + if txt == -1.0 { + return None; + } else { + let allocation_id = txt as usize; + let s = extract_string_from_memory(allocation_id); + clear_allocation(allocation_id); + Some(s) + } +} + +pub fn local_storage_remove_item(id: &str) { + let a0 = id.as_ptr() as u32; + let a1 = id.len() as u32; + let func = js!(r###"function(idPtr,idLen){ + window.localStorage.removeItem(this.readUtf8FromMemory(idPtr,idLen)); + }"###); + func.invoke_2(a0, a1); +} + +pub fn local_storage_clear() { + let func = js!(r###"function(idPtr,idLen,dataPtr,dataLen){ + window.localStorage.clear(); + }"###); + func.invoke_0(); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/Cargo.toml new file mode 100644 index 0000000..94621da --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "web_random" +version = "0.1.5" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for randomness" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/README.md new file mode 100644 index 0000000..2df8643 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/README.md @@ -0,0 +1,20 @@ +# web_random + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'web_random' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/src/lib.rs new file mode 100644 index 0000000..255e415 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_random/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] +use js::*; + +pub fn random() -> f64 { + js!("function(){ + return Math.random(); + }") + .invoke_0() +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/Cargo.toml new file mode 100644 index 0000000..c0531a1 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "web_timer" +version = "0.2.5" +authors = ["Richard Anaya"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Web functions for timers" +repository = "https://github.com/richardanaya/js-wasm" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = {path="../js",version="0"} \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/README.md new file mode 100644 index 0000000..188c191 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/README.md @@ -0,0 +1,20 @@ +# web_timer + +docs.rs docs + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in 'web_timer' by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/src/lib.rs new file mode 100644 index 0000000..f894157 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/web_timer/src/lib.rs @@ -0,0 +1,79 @@ +#![no_std] +use core::future::Future; +use js::*; + +pub type Handle = f64; + +pub fn set_timeout( + callback: impl FnMut() -> () + Send + 'static, + milliseconds: impl Into, +) -> (Handle, JSFunction) { + let cb = create_callback_0(callback); + let handle = js!("function(handler,time){ + window.setTimeout(this.createCallback(handler),time); + }") + .invoke_2(cb, milliseconds); + (handle, cb.into()) +} + +pub fn sleep(milliseconds: impl Into) -> impl Future { + let (future, cb) = create_callback_future_0(); + js!("function(handler,time){ + window.setTimeout(this.createCallback(handler),time); + }") + .invoke_2(cb, milliseconds); + future +} + +pub fn set_interval( + callback: impl FnMut() -> () + Send + 'static, + milliseconds: impl Into, +) -> (Handle, JSFunction) { + let cb = create_callback_0(callback); + let handle = js!("function(handler,time){ + window.setInterval(this.createCallback(handler),time); + }") + .invoke_2(cb, milliseconds); + (handle, cb.into()) +} + +pub fn request_animation_frame(callback: impl FnMut() -> () + Send + 'static) -> JSFunction { + let cb = create_callback_0(callback); + js!("function(handler){ + window.requestAnimationFrame(this.createCallback(handler)); + }") + .invoke_1(cb); + cb.into() +} + +pub fn request_animation_loop(callback: impl FnMut(f64) -> () + Send + 'static) -> JSFunction { + let cb = create_callback_1(callback); + js!("function(cb){ + cb = this.createCallback(cb); + let time = Date.now(); + function run(){ + let new_time = Date.now(); + let delta = new_time-time; + time = new_time; + window.requestAnimationFrame(run); + cb(delta); + } + window.requestAnimationFrame(run); + }") + .invoke_1(cb); + cb.into() +} + +pub fn clear_timeout(handle: Handle) { + js!("function(handle){ + window.clearTimeout(handle); + }") + .invoke_1(handle); +} + +pub fn clear_interval(handle: Handle) { + js!("function(handle){ + window.clearInterval(handle); + }") + .invoke_1(handle); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/Cargo.toml new file mode 100644 index 0000000..79e3df2 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "webcomponent" +version = "0.6.2" +edition = "2018" +authors = ["Richard Anaya"] +categories = ["wasm", "no-std", "web"] +include = [ + "src/**/*.rs", + "Cargo.toml", +] +license = "MIT OR Apache-2.0" +homepage = "https://github.com/richardanaya/webcomponent" +repository = "https://github.com/richardanaya/webcomponent" +description = "A library for creating web components" + +[dependencies] +js = {path="../js",version="0"} +callback= {path="../callback",version="0.5.0"} +spin = "0.7.0" + +[dependencies.lazy_static] +version = "1" +default-features = false +features = ["spin_no_std"] diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/README.md b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/README.md new file mode 100644 index 0000000..466db03 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/README.md @@ -0,0 +1,168 @@ +# webcomponent + +docs.rs docs + +[Web components](https://www.webcomponents.org/) are a W3C standard for writing your own HTML element. `webcomponent` is a Rust library for easily writing your own web components in Rust with [`js_ffi`](https://github.com/richardanaya/js_ffi). + +Features: +- [x] Shadow DOM +- [x] Observable attributes +- [x] Helper functions +- [x] `#![no_std]` and `alloc` + +# Hello World +```toml +[lib] +crate-type =["cdylib"] # configures rust project to build a web assembly module + +[dependencies] +webcomponent="0.5" # for registering our web component +``` +```rust +use webcomponent::*; + +struct HelloWorld { + element: HTMLElement +} + +impl CustomElement for HelloWorld { + fn new(element:HTMLElement) -> Self { + HelloWorld(element) + } + fn connected(&mut self){ + set_html(&self.element,"Hello World!"); + } +} + +#[no_mangle] +fn main() { + HelloWorld::register("hello-world"); +} +``` +```html + + + + + + + + +``` +```makefile +# cli commands for building web assembly I find useful +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/helloworld.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8080 +``` + + +See demo [here](https://richardanaya.github.io/webcomponent/examples/helloworld/) + +# Shadow DOM + +```rust +struct HelloWorld { + element:HTMLElement +} + +impl CustomElement for HelloWorld { + fn new(element: HTMLElement) -> Self { + HelloWorld(element) + } + fn connected(&mut self) { + let shadow_dom = attach_shadow(&self.element, true); + set_html(&shadow_dom, r#"
Hello !
"#); + set_html(&self.element, r#"Richard"#); + } +} +``` + +See demo [here](https://richardanaya.github.io/webcomponent/examples/shadowdom/) + +# Observable Attributes + +```rust +struct HelloPerson { + element: HTMLElement +} + +impl CustomElement for HelloPerson { + fn new(element: HTMLElement) -> Self { + HelloPerson(element) + } + + fn observed_attributes() -> Vec<&'static str> { + vec!["first_name"] + } + + fn connected(&mut self) { + self.render(); + } + + fn attribute_changed(&mut self, _name: String, _old_value: Option, _new_value: Option) { + self.render(); + } +} + +impl HelloPerson { + fn render(&mut self){ + let first_name = get_attribute(&self.element, "first_name").unwrap_or("human".to_string()); + let msg = "Hello ".to_string() + &first_name; + set_html(&self.element, &msg); + } +} +``` + +See demo [here](https://richardanaya.github.io/webcomponent/examples/observable_attributes/) + +# What about the rest of Javscript? + +With `webcomponent` you have a handle to an html element, this is simply a reference to your component that exists in the DOM. With it we can use [`js_ffi`](https://github.com/richardanaya/js_ffi) ( or any [`js_ffi` based library](https://github.com/richardanaya/js_ffi#standard-web-libraries) ) to do whatever we want to do. + +```rust +use webcomponent::*; +use js_ffi::*; + +struct LoudButton { + element: HTMLElement +} + +impl CustomElement for LoudButton { + fn new(element:HTMLElement) -> Self { + LoudButton(element) + } + fn connected(&mut self){ + set_html(&self.element,r#""#); + js!(Node.prototype.addEventListener).call_2( + &self.element, + "click", + create_callback_0(|| { + js!(window.alert).invoke_1("I was clicked!"); + }), + ); + } +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `webcomponent` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Cargo.toml new file mode 100644 index 0000000..ec0f3c2 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["richard "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +web = {path="../../../web"} + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Makefile b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Makefile new file mode 100644 index 0000000..148ef8a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/Makefile @@ -0,0 +1,7 @@ +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/example.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8089 \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/example.wasm b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/example.wasm new file mode 100755 index 0000000000000000000000000000000000000000..970bc8a89cc4b91d9a9802d36b83e0679957d6a7 GIT binary patch literal 35915 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 S!csQ1_VUwcpIN2;&HoR}H$)u( literal 0 HcmV?d00001 diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/index.html b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/index.html new file mode 100644 index 0000000..5cb8904 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/src/lib.rs new file mode 100644 index 0000000..83a35fc --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/helloworld/src/lib.rs @@ -0,0 +1,17 @@ +use web::*; + +struct HelloWorld(HTMLElement); + +impl CustomElement for HelloWorld { + fn new(element: HTMLElement) -> Self { + HelloWorld(element) + } + fn connected(&mut self) { + set_inner_html(self.0, "Hello World!"); + } +} + +#[no_mangle] +fn main() { + HelloWorld::register("hello-world"); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Cargo.toml new file mode 100644 index 0000000..93f39b1 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["richard "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +webcomponent = {path="../../"} +js_ffi = "0.6" + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Makefile b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Makefile new file mode 100644 index 0000000..148ef8a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/Makefile @@ -0,0 +1,7 @@ +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/example.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8089 \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/example.wasm b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/example.wasm new file mode 100755 index 0000000000000000000000000000000000000000..b565d474f5fe3e9017db7a213517605f8a6f679a GIT binary patch literal 43601 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 pW+;w{4dKL^gsXr literal 0 HcmV?d00001 diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/index.html b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/index.html new file mode 100644 index 0000000..e3341a4 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/src/lib.rs new file mode 100644 index 0000000..e95db09 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/loudbutton/src/lib.rs @@ -0,0 +1,27 @@ +use js_ffi::*; +use webcomponent::*; + +struct LoudButton { + element: HTMLElement, +} + +impl CustomElement for LoudButton { + fn new(element: HTMLElement) -> Self { + LoudButton { element } + } + fn connected(&mut self) { + set_html(&self.element, ""); + js!(Node.prototype.addEventListener).call_2( + &self.element, + "click", + create_callback_0(|| { + js!(window.alert).invoke_1("I was clicked!"); + }), + ); + } +} + +#[no_mangle] +fn main() { + LoudButton::register("loud-button"); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Cargo.toml new file mode 100644 index 0000000..93f39b1 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["richard "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +webcomponent = {path="../../"} +js_ffi = "0.6" + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Makefile b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Makefile new file mode 100644 index 0000000..148ef8a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/Makefile @@ -0,0 +1,7 @@ +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/example.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8089 \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/example.wasm b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/example.wasm new file mode 100755 index 0000000000000000000000000000000000000000..f0b48e2d69a6f0a0efc1dc0b34ea95b6d57d7914 GIT binary patch literal 44388 zcmeIb37lP3o$tG+GgO^Z$q57qNg(@_5h@Z$WvWWTR6CMD1i{vJ9+Dy{AeB%>swx4W zK%Fo-D|Ywo<~q{t0M2-?SGhJV@m*9@RP

+gzo6_-Wtg7Ee!4hts;}Z%9HkeZ5kz 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 + + + + + + + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/src/lib.rs new file mode 100644 index 0000000..ca4e55a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/observable_attributes/src/lib.rs @@ -0,0 +1,39 @@ +use webcomponent::*; + +struct HelloPerson(HTMLElement); + +impl CustomElement for HelloPerson { + fn new(element: HTMLElement) -> Self { + HelloPerson(element) + } + + fn observed_attributes() -> Vec<&'static str> { + vec!["first_name"] + } + + fn connected(&mut self) { + self.render(); + } + + fn attribute_changed( + &mut self, + _name: String, + _old_value: Option, + _new_value: Option, + ) { + self.render(); + } +} + +impl HelloPerson { + fn render(&mut self) { + let first_name = get_attribute(&self.0, "first_name").unwrap_or("human".to_string()); + let msg = "Hello ".to_string() + &first_name; + set_html(&self.0, &msg); + } +} + +#[no_mangle] +fn main() { + HelloPerson::register("hello-person"); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Cargo.toml new file mode 100644 index 0000000..93f39b1 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["richard "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +webcomponent = {path="../../"} +js_ffi = "0.6" + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Makefile b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Makefile new file mode 100644 index 0000000..148ef8a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/Makefile @@ -0,0 +1,7 @@ +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/example.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8089 \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/example.wasm b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/example.wasm new file mode 100755 index 0000000000000000000000000000000000000000..027272f01402225f0ab718fe201c50e712bd9cc9 GIT binary patch literal 43287 zcmeIbdz@Wmeeb_+`!aj)ne0G-+#qX@5hf7GaF)`s!=$>z%gka)Y zrC!T-#5b3mE?o0=<)+|nxGSc2+;(KQ+?N{nJd~RcJoyv;wVO-VUOSQg~f zuyf}MZ-x>oX`!8i17m|;wY|(TZ)SVKa_^Y%&6h?&mluTkRFBPjVLps>AB3}J9p?q! zvB!re%%0`V3HbOy;LQp7=KpN|_=Lw%GzjK;VQ_319(O|Lap7Fj=K8)L<@~GsQ%=c+ zzBe;JC!Fw;dVRlFp74@89&Nc6UY*ZhIe6vB=sN?iv}x1Uf$@P&gTq@xzr1PF6@vp; zZMux1gh6!W!1iJ9wGIm!@nr*Bc6hHV+kmg+d1Qh zDksd&9Y1r{$tza&^{-pCdd)d!uf1TydCB^7FZrF)pT0l1^hX`}h}qK&>hBeGK3)>< z=nfXzZLqfeUotx>R&P?F?r?pl7l(2~^nrwVGr871uM(Cuyd#wGyt2SQ zatZp+uMTI&xplr9z9!2}XbbiVn#h8~UZIJ-LIZmRhrNQs9>@vPxok%uC}>CEj}Jj0 z_-#XAF)qY~Ll78%K&1+-X|h8@;C}>q3JyI5haQK57Q`@@jL9J;Y9c0TASQB%iQ35u zG(;lpj+C@JMB1WzsHl=u8#LD;n(K%Qq;es%$R*boL|jrroIR9$risLk>8Y@!4u!-V zRG2d=gds$QN~P!NvW*HwL@$j;Abtrli{g^VEOK~s7&{M@WFN`Bx|b}j-XhYj8i6Od z*iWK3&tHkZV%6w>ZicyBG9jT5z(8d-reOIRX*UC)zce?kHF9UIR06GKEX-~isz$f9_ zMt_6l-r`$SBi|%s@99w>xGOLGK|sQ$g>?-XhQI_acN{CTGs@@$xD&+kRi!yM-tTL z!ATBD)-$�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 + + + + + + + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/src/lib.rs new file mode 100644 index 0000000..5d2510c --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/shadowdom/src/lib.rs @@ -0,0 +1,19 @@ +use webcomponent::*; + +struct HelloWorld(HTMLElement); + +impl CustomElement for HelloWorld { + fn new(element: HTMLElement) -> Self { + HelloWorld(element) + } + fn connected(&mut self) { + let shadow_dom = attach_shadow(&self.0, true); + set_html(&shadow_dom, r#"

"#); + set_html(&self.0, r#"Richard"#); + } +} + +#[no_mangle] +fn main() { + HelloWorld::register("hello-world"); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Cargo.toml new file mode 100644 index 0000000..9ed56c5 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["richard "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +webcomponent = {path="../../"} +js_ffi = "0.6" +web_console = "0" +web-dom = "0" +globals = "1" + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Makefile b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Makefile new file mode 100644 index 0000000..148ef8a --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/Makefile @@ -0,0 +1,7 @@ +build: + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/example.wasm . +lint: + @cargo fmt +serve: + python3 -m http.server 8089 \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/example.wasm b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/example.wasm new file mode 100755 index 0000000000000000000000000000000000000000..13dce475d35ca4d26fe1beb76ce0c86f082713e6 GIT binary patch literal 51009 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 + + +Todo + + + + + + + + + +
+ + Write Rust + Read that book + Hang picture + +
+ + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/lib.rs new file mode 100644 index 0000000..302f5b0 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/lib.rs @@ -0,0 +1,118 @@ +use js_ffi::*; +use web_console::*; +use web_dom::*; +use webcomponent::*; + +struct TodoList { + items: Vec, +} + +impl Default for TodoList { + fn default() -> Self { + TodoList { + items: vec![TodoItem { + done: true, + description: "write some rust".to_string(), + }], + } + } +} + +struct TodoItem { + done: bool, + description: String, +} + +struct TodoListComponent { + element: HTMLElement, + shadow_root: HTMLElement, +} + +impl CustomElement for TodoListComponent { + fn new(element: HTMLElement) -> Self { + TodoListComponent { + shadow_root: attach_shadow(&element, true), + element, + } + } + fn connected(&mut self) { + self.render(); + let state = globals::get::(); + append_html(self.element,r#""#); + } +} + +impl TodoListComponent { + fn render(&mut self) { + set_html(&self.shadow_root, include_str!("todo-list.html")); + } +} + +struct TodoItemComponent { + element: HTMLElement, + shadow_root: HTMLElement, + is_done: bool, +} + +impl CustomElement for TodoItemComponent { + fn new(element: HTMLElement) -> Self { + TodoItemComponent { + shadow_root: attach_shadow(&element, true), + element: element, + is_done: false, + } + } + + fn connected(&mut self) { + set_html(&self.shadow_root, include_str!("todo-item.html")); + let btn = query_selector(&self.shadow_root, "button"); + add_event_listener( + &btn, + "click", + create_callback_0(|| { + js!(window.alert).invoke_1("I was clicked!"); + }), + ); + self.render(); + } + + fn observed_attributes() -> Vec<&'static str> { + vec!["done"] + } + + fn attribute_changed( + &mut self, + name: String, + _old_value: Option, + new_value: Option, + ) { + if name == "done" { + if let Some(value) = new_value { + if value == "yes" { + self.is_done = true; + } else { + self.is_done = false; + } + } else { + self.is_done = false; + } + } + self.render(); + } +} + +impl TodoItemComponent { + fn render(&mut self) { + if self.is_done { + log("done"); + } else { + log("not done"); + } + } +} + +#[no_mangle] +fn main() { + TodoListComponent::register("todo-list"); + TodoItemComponent::register("todo-item"); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-item.html b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-item.html new file mode 100644 index 0000000..46c2cf5 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-item.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-list.html b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-list.html new file mode 100644 index 0000000..5157361 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/examples/todo/src/todo-list.html @@ -0,0 +1,7 @@ +
+
+

Todo List

+
+
+
+
\ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/src/lib.rs new file mode 100644 index 0000000..8d3be6c --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/crates/webcomponent/src/lib.rs @@ -0,0 +1,147 @@ +#![no_std] +use js::*; +#[macro_use] +extern crate alloc; +use alloc::string::String; +use alloc::sync::Arc; +use alloc::vec::Vec; +use spin::Mutex; + +pub type HTMLElement = f64; + +#[derive(Copy, Clone)] +struct Destructable { + function: Option, +} + +pub trait CustomElement { + fn new(element: HTMLElement) -> Self + where + Self: core::marker::Sized + core::marker::Sync + core::marker::Send + 'static; + fn register(name: &str) + where + Self: core::marker::Sized + core::marker::Sync + core::marker::Send + 'static, + { + let construct = create_callback_1(|element| { + let el = Arc::new(Mutex::new(Self::new(element.into()))); + let el1 = el.clone(); + let el2 = el.clone(); + let el3 = el.clone(); + + let destruct_connect = Arc::new(Mutex::new(Destructable { function: None })); + let connect = create_callback_0(move || { + el1.lock().connected(); + }); + destruct_connect.lock().function = Some(connect.into()); + + let destruct_attribute_change = Arc::new(Mutex::new(Destructable { function: None })); + let attribute_change = create_callback_3(move |name_obj, old_obj, new_obj| { + let name = cstr_to_string(name_obj as i32); + let old = if old_obj == -1.0 { + None + } else { + Some(cstr_to_string(old_obj as i32)) + }; + let new = if new_obj == -1.0 { + None + } else { + Some(cstr_to_string(new_obj as i32)) + }; + el3.lock().attribute_changed(name, old, new); + }); + + destruct_attribute_change.lock().function = Some(connect.into()); + + let destruct_disconnect = Arc::new(Mutex::new(Destructable { function: None })); + let destruct_disconnect2 = destruct_disconnect.clone(); + let disconnect = create_callback_0(move || { + el2.lock().disconnected(); + remove_callback(destruct_connect.lock().function.as_ref().unwrap().into()); + remove_callback(destruct_disconnect.lock().function.as_ref().unwrap().into()); + remove_callback( + destruct_attribute_change + .lock() + .function + .as_ref() + .unwrap() + .into(), + ); + }); + destruct_disconnect2.lock().function = Some(disconnect.into()); + + lazy_static::lazy_static! { + static ref FN: JSFunction= { + register_function( + r#"function(e,a,b,c){ + e.addHooks(a,b,c); + }"#, + ) + };}; + FN.invoke_4(element, connect, disconnect, attribute_change); + }); + let attrs = Self::observed_attributes().join(","); + lazy_static::lazy_static! { + static ref FN: JSFunction= { + register_function( + r#"function(construct,elementNamePtr, elementNameLen,attrNamesPtr,attrNamesLen){ + const elementName = this.readUtf8FromMemory(elementNamePtr,elementNameLen); + const attrNames = this.readUtf8FromMemory(attrNamesPtr,attrNamesLen); + let attrs = attrNames.split(","); + class GeneratedCustomElement extends HTMLElement { + constructor() { + super(); + construct(this); + } + + static get observedAttributes() { + return attrs; + } + + connectedCallback() { + self.connect(); + } + + disconnectedCallback() { + self.disconnect(); + } + + attributeChangedCallback(attributeName, oldValue, newValue) { + self.attributeChange(attributeName,oldValue,newValue) + } + + addHooks(connect,disconnect,attributeChange){ + self.connect = connect; + self.disconnect = disconnect; + self.attributeChange = attributeChange; + } + } + + // tell the dom to associate it with an html tag name + customElements.define(elementName, GeneratedCustomElement); + }"#, + ) + };}; + FN.invoke_5( + construct, + name.as_ptr() as u32, + name.len() as u32, + attrs.as_ptr() as u32, + attrs.len() as u32, + ); + } + + fn observed_attributes() -> Vec<&'static str> { + vec![] + } + + fn created(&mut self) {} + fn connected(&mut self) {} + fn disconnected(&mut self) {} + fn attribute_changed( + &mut self, + _name: String, + _old_value: Option, + _new_value: Option, + ) { + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/Cargo.toml b/__wasm/js-wasm/helloworld/js-wasm/electron/Cargo.toml new file mode 100644 index 0000000..a0fa613 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["Richard "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +js = "0" + +[lib] +crate-type =["cdylib"] + +[profile.release] +lto = true \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/Makefile b/__wasm/js-wasm/helloworld/js-wasm/electron/Makefile new file mode 100644 index 0000000..64c803d --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/Makefile @@ -0,0 +1,27 @@ +build: tmp/electron.zip dist/js-wasm.js dist/app.wasm dist/index.html dist/index.js + +run: build + cd dist && ./electron . + + dist/index.js: index.js + cp index.js dist/index.js + +dist/app.wasm: src/**.rs + @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release + @cp target/wasm32-unknown-unknown/release/example.wasm dist/app.wasm + +dist/js-wasm.js: + wget -O dist/js-wasm.js https://unpkg.com/js-wasm/js-wasm.js + +tmp/electron.zip: + mkdir -p tmp + mkdir -p dist + wget -O tmp/electron.zip https://github.com/electron/electron/releases/download/v11.0.2/electron-v11.0.2-linux-x64.zip + cd tmp && unzip electron.zip -d ../dist + +clean: + rm -rf dist + rm -rf tmp + +dist/index.html: index.html + cp index.html dist/index.html \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/README.md b/__wasm/js-wasm/helloworld/js-wasm/electron/README.md new file mode 100644 index 0000000..a3408e8 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/README.md @@ -0,0 +1,68 @@ +# Electron + WebAssembly = :heart: + +

+ +

+ + +Creating desktop apps with WebAssembly is as simple as making website! `electron` is a technology that packages chrome into an desktop app-like minimalistic web view experience. It gives the user access to the local systems resources via the `nodejs` JavaScript api. Since `js-wasm` is a technology agnostic library for executing javascript from WebAssembly, we can easily bind to the parts of the `electron` API we need. + +# Getting Started + +This directory contains an example to get started using quickly. + +``` +git clone git@github.com:richardanaya/js-wasm.git +cd js-wasm/electron +make run +``` + +Let's take a look at the various files: + +| File | Description | +|------|-------------| +| `index.js` | Electron wants a javascript file to tell it where to start, this is just basic setup you can tweak like starting width/height and does your app have a menubar. | +| `index.html` | This is the index file that gets loaded by `index.js` to be the first thing you see. Consider this just like any old web page. | + +All our `index.html` does is quickly tell WebAssembly to start like any old web application + +```html + + + My App! + + + + + + + + +``` + +## Getting what you need + +Now you can create JavaScript binding functions to invoke using [`js-wasm`](https://github.com/richardanaya/js-wasm/) as normal. + +```rust +pub fn read_file(msg: &str) -> String { + lazy_static::lazy_static! { + static ref FN: JSFunction= { + register_function( + "function(pathPtr,pathLen){ + const fs = require('fs'); + const data String(fs.readFileSync(this.readUtf8FromMemory(pathPtr,pathLen))); + return this.writeCStringToMemory(data); + }", + ) + };}; + cstr_to_string(FN.invoke_2(msg.as_ptr() as u32, msg.len() as u32) as i32) +} + +#[no_mangle] +pub fn main() { + let fileContent = read_file("foo.txt"); + ... +} +``` + diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/index.html b/__wasm/js-wasm/helloworld/js-wasm/electron/index.html new file mode 100644 index 0000000..c474536 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/index.html @@ -0,0 +1,17 @@ + + + + My App! + + + + + + + + + \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/index.js b/__wasm/js-wasm/helloworld/js-wasm/electron/index.js new file mode 100644 index 0000000..bc81259 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/index.js @@ -0,0 +1,33 @@ +const {app, BrowserWindow} = require('electron') +function createWindow () { + const mainWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + // OPTIONAL: disable node integrations by commenting this line + nodeIntegration: true + } + }) + // OPTIONAL: Hide the menubar + // mainWindow.setMenu(null). + mainWindow.loadFile('index.html') + + // OPTIONAL: Open the DevTools on startup + // mainWindow.webContents.openDevTools() +} + +app.whenReady().then(() => { + createWindow() + app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow() + }) +}) + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on('window-all-closed', function () { + if (process.platform !== 'darwin') app.quit() +}) \ No newline at end of file diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/resources/webassembly.svg b/__wasm/js-wasm/helloworld/js-wasm/electron/resources/webassembly.svg new file mode 100644 index 0000000..9c08129 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/resources/webassembly.svg @@ -0,0 +1,35 @@ + + + + + web-assembly-logo + + + + + + + + + + + + + + + + + + + + + + diff --git a/__wasm/js-wasm/helloworld/js-wasm/electron/src/lib.rs b/__wasm/js-wasm/helloworld/js-wasm/electron/src/lib.rs new file mode 100644 index 0000000..b1604a6 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/electron/src/lib.rs @@ -0,0 +1,37 @@ +#[no_mangle] +pub fn main() { + let fn_get_2d_context = js::register_function( + r#" + function(selectorStart, selectorEnd){ + let selector = this.readUtf8FromMemory(selectorStart,selectorEnd); + let obj = document.querySelector(selector); + return context.storeObject(obj.getContext("2d")); + }"#, + ); + let fn_set_color = js::register_function( + r#" + function(ctxHandle, colorStart, colorEnd){ + let color = this.readUtf8FromMemory(colorStart, colorEnd); + let ctx = this.getObject(ctxHandle); + ctx.fillStyle = color; + }"#, + ); + let fn_fill_rect = js::register_function( + r#" + function(ctxHandle, x, y, width, height){ + let ctx = this.getObject(ctxHandle); + ctx.fillRect(x, y, width, height); + }"#, + ); + let target = "#screen"; + let ctx = fn_get_2d_context.invoke_2(target.as_ptr() as u32,target.len() as u32); + let color = "red"; + fn_set_color.invoke_3(ctx, color.as_ptr() as u32, color.len() as u32); + fn_fill_rect.invoke_5(ctx, 10.0, 10.0, 50.0, 50.0); + let color = "blue"; + fn_set_color.invoke_3(ctx, color.as_ptr() as u32, color.len() as u32); + fn_fill_rect.invoke_5(ctx, 20.0, 20.0, 50.0, 50.0); + let color = "green"; + fn_set_color.invoke_3(ctx, color.as_ptr() as u32, color.len() as u32); + fn_fill_rect.invoke_5(ctx, 30.0, 30.0, 50.0, 50.0); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/headers/js-wasm.h b/__wasm/js-wasm/helloworld/js-wasm/headers/js-wasm.h new file mode 100644 index 0000000..2dfdd38 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/headers/js-wasm.h @@ -0,0 +1,63 @@ +#ifndef export +#define export __attribute__((visibility("default"))) +#endif + +#ifndef JS_H + +unsigned int +js_strlen(const char *str) +{ + const char *s; + + for (s = str; *s; ++s) + ; + return (s - str); +} + +typedef double JSValue; +typedef int JSFunction; +extern JSFunction js_register_function(char*,unsigned int); +extern JSValue js_invoke_function(JSFunction,JSValue,JSValue,JSValue,JSValue,JSValue,JSValue,JSValue,JSValue,JSValue,JSValue); +extern void js_release(JSValue); + +JSValue const JS_NULL = 0.0; +JSValue const JS_UNDEFINED = 1.0; +JSValue const DOM_SELF = 2.0; +JSValue const DOM_WINDOW = 2.0; +JSValue const DOM_DOCUMENT = 3.0; +JSValue const DOM_BODY = 4.0; + +JSValue js_invoke_function_0(JSFunction fn){ + return js_invoke_function(fn,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_1(JSFunction fn, JSValue a){ + return js_invoke_function(fn,a,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_2(JSFunction fn, JSValue a, JSValue b){ + return js_invoke_function(fn,a,b,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_3(JSFunction fn, JSValue a, JSValue b, JSValue c){ + return js_invoke_function(fn,a,b,c,0.0,0.0,0.0,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_4(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d){ + return js_invoke_function(fn,a,b,c,d,0.0,0.0,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_5(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d, JSValue e){ + return js_invoke_function(fn,a,b,c,d,e,0.0,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_6(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d, JSValue e, JSValue f){ + return js_invoke_function(fn,a,b,c,d,e,f,0.0,0.0,0.0,0.0); +} +JSValue js_invoke_function_7(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d, JSValue e, JSValue f, JSValue g){ + return js_invoke_function(fn,a,b,c,d,e,f,g,0.0,0.0,0.0); +} +JSValue js_invoke_function_8(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d, JSValue e, JSValue f, JSValue g, JSValue h){ + return js_invoke_function(fn,a,b,c,d,e,f,g,h,0.0,0.0); +} +JSValue js_invoke_function_9(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d, JSValue e, JSValue f, JSValue g, JSValue h, JSValue i){ + return js_invoke_function(fn,a,b,c,d,e,f,g,h,i,0.0); +} +JSValue js_invoke_function_10(JSFunction fn, JSValue a, JSValue b, JSValue c, JSValue d, JSValue e, JSValue f, JSValue g, JSValue h, JSValue i, JSValue j){ + return js_invoke_function(fn,a,b,c,d,e,f,g,h,i,j); +} +#endif diff --git a/__wasm/js-wasm/helloworld/js-wasm/headers/web_canvas.h b/__wasm/js-wasm/helloworld/js-wasm/headers/web_canvas.h new file mode 100644 index 0000000..3530e4c --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/headers/web_canvas.h @@ -0,0 +1 @@ +#include "js-wasm.h" diff --git a/__wasm/js-wasm/helloworld/js-wasm/headers/web_console.h b/__wasm/js-wasm/helloworld/js-wasm/headers/web_console.h new file mode 100644 index 0000000..26c41d3 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/headers/web_console.h @@ -0,0 +1,65 @@ +#include "js-wasm.h" + +void console_clear(){ + static int fn; + char *fn_code = "function(){ console.clear(); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_0(fn); +} + +void console_log(char * msg){ + static int fn; + unsigned int a0 = (unsigned int)msg; + unsigned int a1 = js_strlen(msg); + char *fn_code = "function(msgPtr,msgLen){ console.log(this.readUtf8FromMemory(msgPtr,msgLen)); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_2(fn, a0, a1); +} + +void console_warning(char * msg){ + static int fn; + unsigned int a0 = (unsigned int)msg; + unsigned int a1 = js_strlen(msg); + char *fn_code = "function(msgPtr,msgLen){ console.warn(this.readUtf8FromMemory(msgPtr,msgLen)); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_2(fn, a0, a1); +} + +void console_error(char * msg){ + static int fn; + unsigned int a0 = (unsigned int)msg; + unsigned int a1 = js_strlen(msg); + char *fn_code = "function(msgPtr,msgLen){ console.error(this.readUtf8FromMemory(msgPtr,msgLen)); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_2(fn, a0, a1); +} + +void console_time(char * msg){ + static int fn; + unsigned int a0 = (unsigned int)msg; + unsigned int a1 = js_strlen(msg); + char *fn_code = "function(msgPtr,msgLen){ console.time(this.readUtf8FromMemory(msgPtr,msgLen)); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_2(fn, a0, a1); +} + +void console_time_end(char * msg){ + static int fn; + unsigned int a0 = (unsigned int)msg; + unsigned int a1 = js_strlen(msg); + char *fn_code = "function(msgPtr,msgLen){ console.timeEnd(this.readUtf8FromMemory(msgPtr,msgLen)); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + js_invoke_function_2(fn, a0, a1); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/headers/web_dom.h b/__wasm/js-wasm/helloworld/js-wasm/headers/web_dom.h new file mode 100644 index 0000000..969104c --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/headers/web_dom.h @@ -0,0 +1,12 @@ +#include "js-wasm.h" + +double document_get_element_by_id(char * id){ + static int fn; + unsigned int a0 = (unsigned int)id; + unsigned int a1 = js_strlen(id); + char *fn_code = "function(idPtr,idLen){ return this.storeObject(document.getElementById(this.readUtf8FromMemory(idPtr,idLen))); }"; + if(fn == 0){ + fn = js_register_function(fn_code,js_strlen(fn_code)); + } + return js_invoke_function_2(fn, a0, a1); +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/js-wasm.js b/__wasm/js-wasm/helloworld/js-wasm/js-wasm.js new file mode 100644 index 0000000..5ab7765 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/js-wasm.js @@ -0,0 +1,244 @@ +"use strict"; +class Index { + constructor(index, generation) { + this.index = index; + this.generation = generation; + } + toNum() { + return Number((BigInt(this.generation) << BigInt(32)) | BigInt(this.index)); + } + static fromNum(n) { + const i = Number(((BigInt(n) & BigInt(0xffffffff00000000)) >> BigInt(32)) & + BigInt(0xffffffff)); + const g = n & 0xffffffff; + return new Index(g, i); + } +} +class GenerationalArena { + constructor() { + this.items = []; + this.generation = 0; + this.free_list_head = undefined; + this.length = 0; + } + insert(v) { + // lets use the first free entry if we have one + if (this.free_list_head !== undefined) { + let i = this.free_list_head; + this.free_list_head = this.items[i].nextFree; + this.items[i] = { + generation: this.generation, + value: v, + }; + this.length += 1; + return new Index(i, this.generation); + } + this.items.push({ + generation: this.generation, + value: v, + }); + const idx = new Index(this.items.length - 1, this.generation); + this.length += 1; + return idx; + } + contains(idx) { + return this.get(idx) !== undefined; + } + get(i) { + let e = this.items[i.index]; + if (e && e.generation === i.generation) { + return e.value; + } + return undefined; + } + remove(idx) { + if (idx.index >= this.items.length) { + return undefined; + } + let e = this.items[idx.index]; + if (e.generation !== undefined && e.generation == idx.generation) { + this.generation += 1; + this.items[idx.index] = { + nextFree: this.free_list_head, + }; + this.free_list_head = idx.index; + this.length -= 1; + return e.value; + } + return undefined; + } + *[Symbol.iterator]() { + for (let i = 0; i < this.items.length; i++) { + const x = this.items[i]; + if (x.generation !== undefined) { + yield { index: new Index(i, x.generation), value: x.value }; + } + } + } + indices() { + return { + items: this.items, + [Symbol.iterator]: function* iter() { + for (let i = 0; i < this.items.length; i++) { + const x = this.items[i]; + if (x.generation !== undefined) { + yield new Index(i, x.generation); + } + } + }, + }; + } + values() { + return { + items: this.items, + [Symbol.iterator]: function* iter() { + for (let i = 0; i < this.items.length; i++) { + const x = this.items[i]; + if (x.generation !== undefined) { + yield x.value; + } + } + }, + }; + } +} +const JsWasm = { + createEnvironment() { + const arena = new GenerationalArena(); + arena.insert(undefined); + arena.insert(null); + arena.insert(self); + arena.insert(typeof document != "undefined" ? document : null); + arena.insert(typeof document != "undefined" ? document.body : null); + const context = { + functions: [ + function () { + debugger; + return 0; + }, + ], + objects: arena, + utf8dec: new TextDecoder("utf-8"), + utf8enc: new TextEncoder(), + utf16dec: new TextDecoder("utf-16"), + toCallbackArg: function (arg) { + if (typeof arg === "object") { + return context.storeObject(arg); + } + return arg; + }, + createCallback: function (cb) { + if (!this.module) { + throw new Error("module not set"); + } + const fnHandleCallback = this.module.instance.exports.handle_callback; + return function () { + const arg = arguments; + fnHandleCallback(cb, context.toCallbackArg(arg[0]), context.toCallbackArg(arg[1]), context.toCallbackArg(arg[2]), context.toCallbackArg(arg[3]), context.toCallbackArg(arg[4]), context.toCallbackArg(arg[5]), context.toCallbackArg(arg[6]), context.toCallbackArg(arg[7]), context.toCallbackArg(arg[8]), context.toCallbackArg(arg[9])); + }; + }, + readUtf8FromMemory: function (start, len) { + const text = this.utf8dec.decode(this.getMemory().subarray(start, start + len)); + return text; + }, + createAllocation: function (size) { + if (!this.module) { + throw new Error("module not set"); + } + const allocationId = this.module.instance.exports.create_allocation(size); + const allocationPtr = this.module.instance.exports.allocation_ptr(allocationId); + return [allocationId, allocationPtr]; + }, + writeUtf8ToMemory: function (str) { + const bytes = this.utf8enc.encode(str); + const len = bytes.length; + const [id, start] = this.createAllocation(len); + this.getMemory().set(bytes, start); + return id; + }, + readUtf16FromMemory: function (start, len) { + const text = this.utf16dec.decode(this.getMemory().subarray(start, start + len)); + return text; + }, + readUint8ArrayFromMemory(start) { + if (!this.module) { + throw new Error("module not set"); + } + const data32 = new Uint32Array(this.module.instance.exports.memory.buffer); + const ptr = data32[start / 4]; + const length = data32[ptr / 4]; + let b = this.getMemory().slice(ptr + 4, ptr + 4 + length); + return new Uint8Array(b); + }, + storeObject: function (obj) { + const index = this.objects.insert(obj); + return index.toNum(); + }, + getObject: function (handle) { + return this.objects.get(Index.fromNum(handle)); + }, + releaseObject: function (handle) { + this.objects.remove(Index.fromNum(handle)); + }, + getMemory: function () { + if (!this.module) { + throw new Error("module not set"); + } + return new Uint8Array(this.module.instance.exports.memory.buffer); + }, + }; + return [{ + abort() { + throw new Error("WebAssembly module aborted"); + }, + js_release(obj) { + context.releaseObject(obj); + }, + js_register_function(start, len, utfByteLen) { + let functionBody; + if (utfByteLen === 16) { + functionBody = context.readUtf16FromMemory(start, len); + } + else { + functionBody = context.readUtf8FromMemory(start, len); + } + let id = context.functions.length; + context.functions.push(Function(`"use strict";return(${functionBody})`)()); + return id; + }, + js_invoke_function(funcHandle, a, b, c, d, e, f, g, h, i, j) { + return context.functions[funcHandle].call(context, a, b, c, d, e, f, g, h, i, j); + }, + }, context]; + }, + async loadAndRunWasm(wasmURL) { + const [env, context] = JsWasm.createEnvironment(); + const response = await fetch(wasmURL); + const bytes = await response.arrayBuffer(); + const module = await WebAssembly.instantiate(bytes, { + env, + }); + context.module = module; + module.instance.exports.main(); + }, +}; +document.addEventListener("DOMContentLoaded", function () { + const wasmScripts = document.querySelectorAll("script[type='application/wasm']"); + for (let i = 0; i < wasmScripts.length; i++) { + const src = wasmScripts[i].src; + if (src) { + JsWasm.loadAndRunWasm(src); + } + else { + console.error("Script tag must have 'src' property."); + } + } +}); +if (window.WasmScriptComponents) { + window.WasmScriptComponents["js-wasm"] = function (e) { + return { + ...e, + ...JsWasm.createEnvironment(), + }; + }; +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/js-wasm.ts b/__wasm/js-wasm/helloworld/js-wasm/js-wasm.ts new file mode 100644 index 0000000..cbb3736 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/js-wasm.ts @@ -0,0 +1,368 @@ +class Index { + index: number; + generation: number; + + constructor(index: number, generation: number) { + this.index = index; + this.generation = generation; + } + + toNum() { + return Number((BigInt(this.generation) << BigInt(32)) | BigInt(this.index)); + } + + static fromNum(n: number) { + const i = Number( + ((BigInt(n) & BigInt(0xffffffff00000000)) >> BigInt(32)) & + BigInt(0xffffffff) + ); + const g = n & 0xffffffff; + return new Index(g, i); + } +} + +interface GenerationItem { + generation?: number; + value?: T; + nextFree?: number; +} + +class GenerationalArena { + items: GenerationItem[]; + generation: number; + length: number; + free_list_head?: number; + + constructor() { + this.items = []; + this.generation = 0; + this.free_list_head = undefined; + this.length = 0; + } + + insert(v: T) { + // lets use the first free entry if we have one + if (this.free_list_head !== undefined) { + let i = this.free_list_head; + this.free_list_head = this.items[i].nextFree; + this.items[i] = { + generation: this.generation, + value: v, + }; + this.length += 1; + return new Index(i, this.generation); + } + + this.items.push({ + generation: this.generation, + value: v, + }); + const idx = new Index(this.items.length - 1, this.generation); + this.length += 1; + return idx; + } + + contains(idx: Index) { + return this.get(idx) !== undefined; + } + + get(i: Index) { + let e = this.items[i.index]; + if (e && e.generation === i.generation) { + return e.value; + } + return undefined; + } + + remove(idx: Index) { + if (idx.index >= this.items.length) { + return undefined; + } + + let e = this.items[idx.index]; + if (e.generation !== undefined && e.generation == idx.generation) { + this.generation += 1; + this.items[idx.index] = { + nextFree: this.free_list_head, + }; + this.free_list_head = idx.index; + this.length -= 1; + return e.value; + } + return undefined; + } + + *[Symbol.iterator]() { + for (let i = 0; i < this.items.length; i++) { + const x = this.items[i]; + if (x.generation !== undefined) { + yield { index: new Index(i, x.generation), value: x.value }; + } + } + } + + indices() { + return { + items: this.items, + [Symbol.iterator]: function* iter() { + for (let i = 0; i < this.items.length; i++) { + const x = this.items[i]; + if (x.generation !== undefined) { + yield new Index(i, x.generation); + } + } + }, + }; + } + + values() { + return { + items: this.items, + [Symbol.iterator]: function* iter() { + for (let i = 0; i < this.items.length; i++) { + const x = this.items[i]; + if (x.generation !== undefined) { + yield x.value; + } + } + }, + }; + } +} + +interface JSWasmHandlerContext { + functions: (( + a: number, + b: number, + c: number, + d: number, + e: number, + f: number, + g: number, + h: number, + i: number, + j: number + ) => number)[]; + objects: GenerationalArena; + utf8dec: TextDecoder; + utf8enc: TextEncoder; + utf16dec: TextDecoder; + toCallbackArg: (arg: number | object) => number; + storeObject: (obj: any) => number; + releaseObject: (objHandle: number) => void; + module?: WebAssembly.WebAssemblyInstantiatedSource; + readUtf8FromMemory: (start: number, end: number) => string; + readUtf16FromMemory: (start: number, end: number) => string; + getMemory: () => Uint8Array; + createAllocation: (size: number) => [number,number] ; + createCallback: (cb: number) => () => void; + writeUtf8ToMemory: (txt: string) => number; + readUint8ArrayFromMemory: (start: number) => Uint8Array; + getObject: (handle: number) => any; +} + +const JsWasm = { + createEnvironment(): [WebAssembly.ModuleImports, JSWasmHandlerContext] { + const arena = new GenerationalArena(); + arena.insert(undefined); + arena.insert(null); + arena.insert(self); + arena.insert(typeof document != "undefined" ? document : null); + arena.insert(typeof document != "undefined" ? document.body : null); + const context: JSWasmHandlerContext = { + functions: [ + function () { + debugger; + return 0; + }, + ], + objects: arena, + utf8dec: new TextDecoder("utf-8"), + utf8enc: new TextEncoder(), + utf16dec: new TextDecoder("utf-16"), + toCallbackArg: function (arg: number | object) { + if (typeof arg === "object") { + return context.storeObject(arg); + } + return arg; + }, + createCallback: function (cb: number) { + if (!this.module) { + throw new Error("module not set"); + } + const fnHandleCallback = this.module.instance.exports.handle_callback as ( + cb: number, + a: number, + b: number, + c: number, + d: number, + e: number, + f: number, + g: number, + h: number, + i: number, + j: number + ) => void; + return function () { + const arg = arguments; + fnHandleCallback( + cb, + context.toCallbackArg(arg[0]), + context.toCallbackArg(arg[1]), + context.toCallbackArg(arg[2]), + context.toCallbackArg(arg[3]), + context.toCallbackArg(arg[4]), + context.toCallbackArg(arg[5]), + context.toCallbackArg(arg[6]), + context.toCallbackArg(arg[7]), + context.toCallbackArg(arg[8]), + context.toCallbackArg(arg[9]) + ); + }; + }, + readUtf8FromMemory: function (start: number, len: number) { + const text = this.utf8dec.decode( + this.getMemory().subarray(start, start + len) + ); + return text; + }, + createAllocation: function (size: number): [number,number] { + if (!this.module) { + throw new Error("module not set"); + } + const allocationId = (this.module.instance.exports.create_allocation as ( + size: number + ) => number)(size); + const allocationPtr = (this.module.instance.exports.allocation_ptr as ( + size: number + ) => number)(allocationId); + return [allocationId, allocationPtr]; + }, + writeUtf8ToMemory: function (str: string) { + const bytes = this.utf8enc.encode(str); + const len = bytes.length; + const [id,start] = this.createAllocation(len); + this.getMemory().set(bytes, start); + return id; + }, + readUtf16FromMemory: function (start: number, len: number) { + const text = this.utf16dec.decode( + this.getMemory().subarray(start, start + len) + ); + return text; + }, + readUint8ArrayFromMemory(start: number) { + if (!this.module) { + throw new Error("module not set"); + } + const data32 = new Uint32Array( + (this.module.instance.exports.memory as WebAssembly.Memory).buffer + ); + const ptr = data32[start / 4]; + const length = data32[ptr / 4]; + let b = this.getMemory().slice(ptr + 4, ptr + 4 + length); + return new Uint8Array(b); + }, + storeObject: function (obj: unknown) { + const index = this.objects.insert(obj); + return index.toNum(); + }, + getObject: function (handle: number) { + return this.objects.get(Index.fromNum(handle)); + }, + releaseObject: function (handle: number) { + this.objects.remove(Index.fromNum(handle)); + }, + getMemory: function () { + if (!this.module) { + throw new Error("module not set"); + } + return new Uint8Array( + (this.module.instance.exports.memory as WebAssembly.Memory).buffer + ); + }, + }; + return [{ + abort() { + throw new Error("WebAssembly module aborted"); + }, + js_release(obj: number) { + context.releaseObject(obj); + }, + js_register_function(start: number, len: number, utfByteLen: number) { + let functionBody; + if (utfByteLen === 16) { + functionBody = context.readUtf16FromMemory(start, len); + } else { + functionBody = context.readUtf8FromMemory(start, len); + } + let id = context.functions.length; + context.functions.push( + Function(`"use strict";return(${functionBody})`)() + ); + return id; + }, + js_invoke_function( + funcHandle: number, + a: number, + b: number, + c: number, + d: number, + e: number, + f: number, + g: number, + h: number, + i: number, + j: number + ) { + return context.functions[funcHandle].call( + context, + a, + b, + c, + d, + e, + f, + g, + h, + i, + j + ); + }, + },context]; + }, + + async loadAndRunWasm(wasmURL: string) { + const [env,context] = JsWasm.createEnvironment(); + const response = await fetch(wasmURL); + const bytes = await response.arrayBuffer(); + const module = await WebAssembly.instantiate(bytes, { + env, + }); + context.module = module; + (module.instance.exports.main as ()=>void)(); + }, +}; + +document.addEventListener("DOMContentLoaded", function () { + const wasmScripts = document.querySelectorAll( + "script[type='application/wasm']" + ); + for (let i = 0; i < wasmScripts.length; i++) { + const src = (wasmScripts[i] as HTMLSourceElement).src; + if (src) { + JsWasm.loadAndRunWasm(src); + } else { + console.error("Script tag must have 'src' property."); + } + } +}); + +if ((window as any).WasmScriptComponents) { + (window as any).WasmScriptComponents["js-wasm"] = function (e: any) { + return { + ...e, + ...JsWasm.createEnvironment(), + }; + }; +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/package-lock.json b/__wasm/js-wasm/helloworld/js-wasm/package-lock.json new file mode 100644 index 0000000..e33411d --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "js-wasm", + "version": "0.3.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "0.3.1", + "license": "MIT OR Apache-2.0", + "devDependencies": { + "typescript": "^4.7" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + } + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/package.json b/__wasm/js-wasm/helloworld/js-wasm/package.json new file mode 100644 index 0000000..27af7f7 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/package.json @@ -0,0 +1,33 @@ +{ + "name": "js-wasm", + "version": "0.4.1", + "description": "Call JavaScript from WebAssembly ", + "main": "js-wasm.js", + "directories": { + "example": "examples" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/richardanaya/js-wasm.git" + }, + "keywords": [ + "wasm", + "js" + ], + "author": "Richard Anaya", + "license": "MIT OR Apache-2.0", + "bugs": { + "url": "https://github.com/richardanaya/js-wasm/issues" + }, + "homepage": "https://github.com/richardanaya/js-wasm#readme", + "files": [ + "js-wasm.js" + ], + "devDependencies": { + "typescript": "^4.7" + } +} diff --git a/__wasm/js-wasm/helloworld/js-wasm/tsconfig.json b/__wasm/js-wasm/helloworld/js-wasm/tsconfig.json new file mode 100644 index 0000000..88838e2 --- /dev/null +++ b/__wasm/js-wasm/helloworld/js-wasm/tsconfig.json @@ -0,0 +1,74 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + //"module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "lib": ["es2020","DOM"], + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + "outFile": "js-wasm.js", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + }, + "files": [ + "js-wasm.ts" + ] +}