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
+
+
+*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
+
+
+
+```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
+
+