├── .gitignore ├── Makefile ├── rust-webcomponent.wasm ├── cargo.toml ├── index.html ├── LICENSE ├── README.md ├── Cargo.lock ├── src └── main.rs └── rust-webcomponent.js /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start: 2 | cargo +nightly web start --target-webasm 3 | -------------------------------------------------------------------------------- /rust-webcomponent.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/richardanaya/rust-webcomponent/HEAD/rust-webcomponent.wasm -------------------------------------------------------------------------------- /cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-webcomponent" 3 | version = "0.1.0" 4 | 5 | [dependencies] 6 | stdweb = "0.2.2" 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Richard Anaya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What is this? 2 | 3 | I wanted to play around with [stdweb](https://github.com/koute/stdweb) to create a proof of concept to allow Web Components easily. If you aren't familiar with them. They are blocks of code that allow us to create our own html tags. Here's an example of where i'm going: 4 | 5 | ```rust 6 | struct HelloWorld; 7 | 8 | impl WebComponent for HelloWorld { 9 | fn get_element_name() -> &'static str {"hello-world"} 10 | 11 | fn constructor(){ 12 | set_inner_html(r#" 13 | 21 | 22 | "#); 23 | add_event_listener("click",||{ 24 | alert("Surprise!"); 25 | }) 26 | } 27 | } 28 | 29 | ... 30 | 31 | define_web_component(HelloWorld); 32 | ``` 33 | 34 | ```html 35 | 36 | ``` 37 | 38 | Would output in the browser a button with "Hello World!" that alerts when clicked. 39 | 40 | Here's a simple demo of this working: https://richardanaya.github.io/rust-webcomponent/ 41 | 42 | If you are familiar with chrome dev tools, try inspecting the elements and modify the "greeting" and "name" attributes. For more details check out the source code of this project! 43 | 44 | Overall I think I was pleased how easy this mostly was to do. I would like a more rust native API for interacting with the DOM within the web component as a next step. 45 | 46 | # How to run this 47 | 48 | ```bash 49 | curl -s https://static.rust-lang.org/rustup.sh | sh -s -- --channel=nightly 50 | rustup update nightly 51 | rustup target add wasm32-unknown-unknown --toolchain=nightly 52 | cargo +nightly web start --target-webasm 53 | ``` 54 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "dtoa" 3 | version = "0.4.2" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | 6 | [[package]] 7 | name = "itoa" 8 | version = "0.3.4" 9 | source = "registry+https://github.com/rust-lang/crates.io-index" 10 | 11 | [[package]] 12 | name = "num-traits" 13 | version = "0.1.41" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | 16 | [[package]] 17 | name = "rust-webcomponent" 18 | version = "0.1.0" 19 | dependencies = [ 20 | "stdweb 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 21 | ] 22 | 23 | [[package]] 24 | name = "serde" 25 | version = "1.0.26" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | 28 | [[package]] 29 | name = "serde_json" 30 | version = "1.0.8" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | dependencies = [ 33 | "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "serde 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", 37 | ] 38 | 39 | [[package]] 40 | name = "stdweb" 41 | version = "0.2.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | dependencies = [ 44 | "serde 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 46 | ] 47 | 48 | [metadata] 49 | "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" 50 | "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" 51 | "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" 52 | "checksum serde 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "d1d6af49db29f2f2678e442f4eb82e7d78f59dbbd3e373ccffc17fe70c1b94f8" 53 | "checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839" 54 | "checksum stdweb 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1a9e0841ed7c77ebd9efadb4176de788dc32c17b0d84cc10e98e465284248f6" 55 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit="256"] 2 | #[macro_use] 3 | extern crate stdweb; 4 | 5 | // This function allows us to define a new html element hooked up to the static members of a type 6 | fn define_web_component(_:T) { 7 | 8 | // we need to use the array of attribute names we should be observing 9 | // and pass them in as a joined string since giving arrays to stdweb 10 | // isn't possible or expensive 11 | let observed_attributes = T::get_observable_attributes().join(":"); 12 | 13 | js! { 14 | // use a global variable that allows us to give a context for what element 15 | // is currently handling an event 16 | window.currentElement = null; 17 | 18 | // create a generated custom element 19 | class GeneratedCustomElement extends HTMLElement { 20 | static get observedAttributes() {return (@{observed_attributes}).split(":"); } 21 | 22 | constructor() { 23 | super(); 24 | window.currentElement = this; 25 | (@{T::constructor})(); 26 | window.currentElement = null; 27 | } 28 | 29 | connectedCallback() { 30 | window.currentElement = this; 31 | (@{T::connected})(); 32 | window.currentElement = null; 33 | } 34 | 35 | disconnectedCallback() { 36 | window.currentElement = this; 37 | (@{T::disconnected})(); 38 | window.currentElement = null; 39 | } 40 | 41 | attributeChangedCallback(attributeName, oldValue, newValue) { 42 | window.currentElement = this; 43 | (@{T::attribute_changed})(attributeName,oldValue||"",newValue||""); 44 | window.currentElement = null; 45 | } 46 | } 47 | 48 | // tell the dom to associate it with an html tag name 49 | customElements.define(@{T::get_element_name()}, GeneratedCustomElement); 50 | } 51 | } 52 | 53 | fn log(msg:&str) { 54 | js! { 55 | console.log(@{msg}); 56 | } 57 | } 58 | 59 | fn get_attribute(attr_name:&str) -> String{ 60 | let result = js! { 61 | return window.currentElement.getAttribute(@{attr_name})||""; 62 | }; 63 | result.as_str().unwrap().to_string() 64 | } 65 | 66 | fn alert(msg:&str) { 67 | js! { 68 | alert(@{msg}); 69 | } 70 | } 71 | 72 | fn set_inner_html(html:&str){ 73 | js! { 74 | window.currentElement.innerHTML = @{html}; 75 | } 76 | } 77 | 78 | fn set_child_inner_html(target:&str,html:&str){ 79 | js! { 80 | window.currentElement.querySelector(@{target}).innerHTML = @{html}; 81 | } 82 | } 83 | 84 | fn add_event_listener(event_type:&str,handler:fn()->()){ 85 | js! { 86 | window.currentElement.addEventListener(@{event_type}, () => { 87 | (@{handler})(); 88 | }) 89 | } 90 | } 91 | 92 | trait WebComponent { 93 | fn get_element_name() -> &'static str {""} 94 | fn get_observable_attributes() -> Vec<&'static str> {vec![]} 95 | fn constructor(){} 96 | fn connected(){} 97 | fn disconnected(){} 98 | fn attribute_changed(_attribute_name:String,_old_value:String,_new_value:String){} 99 | } 100 | 101 | struct HelloWorld; 102 | 103 | // this is an example web component that does some stuff on web component lifecycles 104 | // since there are defaul definitions in the trait, these aren't really all necessary 105 | impl WebComponent for HelloWorld { 106 | fn get_element_name() -> &'static str {"hello-world"} 107 | 108 | fn get_observable_attributes() -> Vec<&'static str> {vec!["greeting","name"]} 109 | 110 | fn constructor(){ 111 | set_inner_html(r#" 112 | 120 | 121 | "#); 122 | add_event_listener("click",||{ 123 | alert("Surprise!"); 124 | }) 125 | } 126 | 127 | fn connected(){ 128 | log("connected"); 129 | } 130 | 131 | fn disconnected(){ 132 | log("disconnected"); 133 | } 134 | 135 | fn attribute_changed(attribute_name:String,_old_value:String,new_value:String){ 136 | if attribute_name == "greeting" { 137 | let name_attr = get_attribute("name"); 138 | let name = match name_attr.len() { 139 | 0 => "World", 140 | _ => &name_attr 141 | }; 142 | set_child_inner_html("button",&format!("{} {}!",new_value,name)); 143 | } else if attribute_name == "name" { 144 | let greeting_attr = get_attribute("greeting"); 145 | let greeting = match greeting_attr.len() { 146 | 0 => "Hello", 147 | _ => &greeting_attr 148 | }; 149 | set_child_inner_html("button",&format!("{} {}!",new_value,greeting)); 150 | } 151 | } 152 | } 153 | 154 | fn main() { 155 | // get std wb started 156 | stdweb::initialize(); 157 | 158 | // define the web components we will use 159 | define_web_component(HelloWorld); 160 | 161 | // inject some dom into the body to show it off! 162 | js! { 163 | document.body.innerHTML = @{r#" 164 | 165 | 166 | "#}; 167 | } 168 | 169 | // keep std event going 170 | stdweb::event_loop(); 171 | } 172 | -------------------------------------------------------------------------------- /rust-webcomponent.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | if( typeof Rust === 'undefined' ) { 4 | var Rust = {}; 5 | } 6 | 7 | (function( root, factory ) { 8 | if( typeof define === "function" && define.amd ) { 9 | define( [], factory ); 10 | } else if( typeof module === "object" && module.exports ) { 11 | module.exports = factory(); 12 | } else { 13 | factory(); 14 | } 15 | }( this, function() { 16 | const Module = {}; 17 | let HEAP8 = null; 18 | let HEAP16 = null; 19 | let HEAP32 = null; 20 | let HEAPU8 = null; 21 | let HEAPU16 = null; 22 | let HEAPU32 = null; 23 | let HEAPF32 = null; 24 | let HEAPF64 = null; 25 | 26 | Object.defineProperty( Module, 'nodejs', { value: (typeof window === 'undefined') } ); 27 | Object.defineProperty( Module, 'exports', { value: {} } ); 28 | 29 | const __imports = { 30 | env: { 31 | "__extjs_de942ef9ccd064c41dc92d5b5bf83c61aeb00278": function($0) { 32 | Module.STDWEB.increment_refcount( $0 ); 33 | }, 34 | "__extjs_d8a439451216bbc6cd9f3012f189d2ad6a2e9459": function($0) { 35 | Module.STDWEB.decrement_refcount( $0 ); 36 | }, 37 | "__extjs_3e980b7ec07b16bf683b3070c11e3eb388759904": function($0, $1, $2, $3, $4, $5, $6) { 38 | $1 = Module.STDWEB.to_js($1);$2 = Module.STDWEB.to_js($2);$3 = Module.STDWEB.to_js($3);$4 = Module.STDWEB.to_js($4);$5 = Module.STDWEB.to_js($5);$6 = Module.STDWEB.to_js($6);Module.STDWEB.from_js($0, (function(){window.currentElement = null ; class GeneratedCustomElement extends HTMLElement {static get observedAttributes (){return (($1)). split (":");}constructor (){super (); window.currentElement = this ; (($2))(); window.currentElement = null ;}connectedCallback (){window.currentElement = this ; (($3))(); window.currentElement = null ;}disconnectedCallback (){window.currentElement = this ; (($4))(); window.currentElement = null ;}attributeChangedCallback (attributeName , oldValue , newValue){window.currentElement = this ; (($5))(attributeName , oldValue || "" , newValue || ""); window.currentElement = null ;}}customElements.define (($6), GeneratedCustomElement);})()); 39 | }, 40 | "__extjs_a2d32a1ea1e21316fb2cdf51556ed49fdd1c8471": function($0, $1) { 41 | $1 = Module.STDWEB.to_js($1);Module.STDWEB.from_js($0, (function(){console.log (($1));})()); 42 | }, 43 | "__extjs_7976e807bcaa0e17f784a4adc473de9dcc8933c2": function($0, $1) { 44 | $1 = Module.STDWEB.to_js($1);Module.STDWEB.from_js($0, (function(){return window.currentElement.getAttribute (($1))|| "" ;})()); 45 | }, 46 | "__extjs_fc56ed462cfddb37d8b68e5cf169edc763b66d09": function($0, $1) { 47 | $1 = Module.STDWEB.to_js($1);Module.STDWEB.from_js($0, (function(){alert (($1));})()); 48 | }, 49 | "__extjs_6c8b611b1490d2820837892879c6acc1d8dd5643": function($0, $1) { 50 | $1 = Module.STDWEB.to_js($1);Module.STDWEB.from_js($0, (function(){window.currentElement.innerHTML = ($1);})()); 51 | }, 52 | "__extjs_662c9e03ca86141f7383cf881ad273d3d244421c": function($0, $1, $2) { 53 | $1 = Module.STDWEB.to_js($1);$2 = Module.STDWEB.to_js($2);Module.STDWEB.from_js($0, (function(){window.currentElement.querySelector (($1)). innerHTML = ($2);})()); 54 | }, 55 | "__extjs_d0ffaf58f88d1f1e26121656bcd33820a563f6f6": function($0, $1, $2) { 56 | $1 = Module.STDWEB.to_js($1);$2 = Module.STDWEB.to_js($2);Module.STDWEB.from_js($0, (function(){window.currentElement.addEventListener (($1), ()=> {(($2))();})})()); 57 | }, 58 | "__extjs_559c1045853f5282b358888babc6fe308becdb2e": function($0, $1) { 59 | $1 = Module.STDWEB.to_js($1);Module.STDWEB.from_js($0, (function(){document.body.innerHTML = ($1);})()); 60 | }, 61 | "__extjs_d0f9580b9cfe82e2ee67d3707e52d87bbabe59f2": function() { 62 | Module.STDWEB = {}; 63 | }, 64 | "__extjs_4985c7263834081d123cc7eff225fe2010747092": function() { 65 | Module.STDWEB.alloc = Module.web_malloc ; Module.STDWEB.dyncall = function (signature , ptr , args){return Module.web_table.get (ptr). apply (null , args);}; Module.STDWEB.utf8_len = function utf8_len (str){let len = 0 ; for (let i = 0 ; i < str.length ; ++i){let u = str.charCodeAt (i); if (u >= 0xD800 && u <= 0xDFFF){u = 0x10000 + ((u & 0x3FF)<< 10)| (str.charCodeAt (++i)& 0x3FF);}if (u <= 0x7F){++len ;}else if (u <= 0x7FF){len += 2 ;}else if (u <= 0xFFFF){len += 3 ;}else if (u <= 0x1FFFFF){len += 4 ;}else if (u <= 0x3FFFFFF){len += 5 ;}else {len += 6 ;}}return len ;}; 66 | }, 67 | "__extjs_a986a787f7d7d1abc8c97008ceb5c6945d3f620f": function() { 68 | Module.STDWEB.to_utf8 = function to_utf8 (str , addr){for (var i = 0 ; i < str.length ; ++i){var u = str.charCodeAt (i); if (u >= 0xD800 && u <= 0xDFFF){u = 0x10000 + ((u & 0x3FF)<< 10)| (str.charCodeAt (++i)& 0x3FF);}if (u <= 0x7F){HEAPU8 [addr ++]= u ;}else if (u <= 0x7FF){HEAPU8 [addr ++]= 0xC0 | (u >> 6); HEAPU8 [addr ++]= 0x80 | (u & 63);}else if (u <= 0xFFFF){HEAPU8 [addr ++]= 0xE0 | (u >> 12); HEAPU8 [addr ++]= 0x80 | ((u >> 6)& 63); HEAPU8 [addr ++]= 0x80 | (u & 63);}else if (u <= 0x1FFFFF){HEAPU8 [addr ++]= 0xF0 | (u >> 18); HEAPU8 [addr ++]= 0x80 | ((u >> 12)& 63); HEAPU8 [addr ++]= 0x80 | ((u >> 6)& 63); HEAPU8 [addr ++]= 0x80 | (u & 63);}else if (u <= 0x3FFFFFF){HEAPU8 [addr ++]= 0xF8 | (u >> 24); HEAPU8 [addr ++]= 0x80 | ((u >> 18)& 63); HEAPU8 [addr ++]= 0x80 | ((u >> 12)& 63); HEAPU8 [addr ++]= 0x80 | ((u >> 6)& 63); HEAPU8 [addr ++]= 0x80 | (u & 63);}else {HEAPU8 [addr ++]= 0xFC | (u >> 30); HEAPU8 [addr ++]= 0x80 | ((u >> 24)& 63); HEAPU8 [addr ++]= 0x80 | ((u >> 18)& 63); HEAPU8 [addr ++]= 0x80 | ((u >> 12)& 63); HEAPU8 [addr ++]= 0x80 | ((u >> 6)& 63); HEAPU8 [addr ++]= 0x80 | (u & 63);}}}; 69 | }, 70 | "__extjs_8ab00422b82c3698a22113bfc2ea26c5363d1db1": function() { 71 | Module.STDWEB.noop = function (){}; Module.STDWEB.to_js = function to_js (address){var kind = HEAPU8 [address + 12]; if (kind ===0){return undefined ;}else if (kind ===1){return null ;}else if (kind ===2){return HEAP32 [address / 4];}else if (kind ===3){return HEAPF64 [address / 8];}else if (kind ===4){var pointer = HEAPU32 [address / 4]; var length = HEAPU32 [(address + 4)/ 4]; return Module.STDWEB.to_js_string (pointer , length);}else if (kind ===5){return false ;}else if (kind ===6){return true ;}else if (kind ===7){var pointer = HEAPU32 [address / 4]; var length = HEAPU32 [(address + 4)/ 4]; var output = []; for (var i = 0 ; i < length ; ++i){output.push (Module.STDWEB.to_js (pointer + i * 16));}return output ;}else if (kind ===8){var value_array_pointer = HEAPU32 [address / 4]; var length = HEAPU32 [(address + 4)/ 4]; var key_array_pointer = HEAPU32 [(address + 8)/ 4]; var output = {}; for (var i = 0 ; i < length ; ++i){var key_pointer = HEAPU32 [(key_array_pointer + i * 8)/ 4]; var key_length = HEAPU32 [(key_array_pointer + 4 + i * 8)/ 4]; var key = Module.STDWEB.to_js_string (key_pointer , key_length); var value = Module.STDWEB.to_js (value_array_pointer + i * 16); output [key]= value ;}return output ;}else if (kind ===9 || kind ===11 || kind ===12){return Module.STDWEB.acquire_js_reference (HEAP32 [address / 4]);}else if (kind ===10){var adapter_pointer = HEAPU32 [address / 4]; var pointer = HEAPU32 [(address + 4)/ 4]; var deallocator_pointer = HEAPU32 [(address + 8)/ 4]; var output = function (){var args = Module.STDWEB.alloc (16); Module.STDWEB.serialize_array (args , arguments); Module.STDWEB.dyncall ("vii" , adapter_pointer , [pointer , args]); var result = Module.STDWEB.tmp ; Module.STDWEB.tmp = null ; return result ;}; output.drop = function (){output.drop = Module.STDWEB.noop ; Module.STDWEB.dyncall ("vi" , deallocator_pointer , [pointer]);}; return output ;}else if (kind ===13){var adapter_pointer = HEAPU32 [address / 4]; var pointer = HEAPU32 [(address + 4)/ 4]; var deallocator_pointer = HEAPU32 [(address + 8)/ 4]; var output = function (){if (pointer ===0){throw new ReferenceError ("Already called or dropped FnOnce function called!");}output.drop = Module.STDWEB.noop ; var function_pointer = pointer ; pointer = 0 ; var args = Module.STDWEB.alloc (16); Module.STDWEB.serialize_array (args , arguments); Module.STDWEB.dyncall ("vii" , adapter_pointer , [function_pointer , args]); var result = Module.STDWEB.tmp ; Module.STDWEB.tmp = null ; return result ;}; output.drop = function (){output.drop = Module.STDWEB.noop ; var function_pointer = pointer ; pointer = 0 ; Module.STDWEB.dyncall ("vi" , deallocator_pointer , [function_pointer]);}; return output ;}}; 72 | }, 73 | "__extjs_2171fbf7dcd6cce3ad90767662e531aee9577813": function() { 74 | Module.STDWEB.serialize_object = function serialize_object (address , value){var keys = Object.keys (value); var length = keys.length ; var key_array_pointer = Module.STDWEB.alloc (length * 8); var value_array_pointer = Module.STDWEB.alloc (length * 16); HEAPU8 [address + 12]= 8 ; HEAPU32 [address / 4]= value_array_pointer ; HEAPU32 [(address + 4)/ 4]= length ; HEAPU32 [(address + 8)/ 4]= key_array_pointer ; for (var i = 0 ; i < length ; ++i){var key = keys [i]; var key_length = Module.STDWEB.utf8_len (key); var key_pointer = Module.STDWEB.alloc (key_length); Module.STDWEB.to_utf8 (key , key_pointer); var key_address = key_array_pointer + i * 8 ; HEAPU32 [key_address / 4]= key_pointer ; HEAPU32 [(key_address + 4)/ 4]= key_length ; Module.STDWEB.from_js (value_array_pointer + i * 16 , value [key]);}}; Module.STDWEB.serialize_array = function serialize_array (address , value){var length = value.length ; var pointer = Module.STDWEB.alloc (length * 16); HEAPU8 [address + 12]= 7 ; HEAPU32 [address / 4]= pointer ; HEAPU32 [(address + 4)/ 4]= length ; for (var i = 0 ; i < length ; ++i){Module.STDWEB.from_js (pointer + i * 16 , value [i]);}}; Module.STDWEB.from_js = function from_js (address , value){var kind = Object.prototype.toString.call (value); if (kind ==="[object String]"){var length = Module.STDWEB.utf8_len (value); var pointer = 0 ; if (length > 0){pointer = Module.STDWEB.alloc (length); Module.STDWEB.to_utf8 (value , pointer);}HEAPU8 [address + 12]= 4 ; HEAPU32 [address / 4]= pointer ; HEAPU32 [(address + 4)/ 4]= length ;}else if (kind ==="[object Number]"){if (value ===(value | 0)){HEAPU8 [address + 12]= 2 ; HEAP32 [address / 4]= value ;}else {HEAPU8 [address + 12]= 3 ; HEAPF64 [address / 8]= value ;}}else if (value ===null){HEAPU8 [address + 12]= 1 ;}else if (value ===undefined){HEAPU8 [address + 12]= 0 ;}else if (value ===false){HEAPU8 [address + 12]= 5 ;}else if (value ===true){HEAPU8 [address + 12]= 6 ;}else {var refid = Module.STDWEB.acquire_rust_reference (value); var id = 9 ; if (kind ==="[object Object]"){id = 11 ;}else if (kind ==="[object Array]" || kind ==="[object Arguments]"){id = 12 ;}HEAPU8 [address + 12]= id ; HEAP32 [address / 4]= refid ;}}; 75 | }, 76 | "__extjs_8a13e041b26592fd43280496ac01f5f3e049218e": function() { 77 | Module.STDWEB.to_js_string = function to_js_string (index , length){index = index | 0 ; length = length | 0 ; var end = (index | 0)+ (length | 0); var output = "" ; while (index < end){var x = HEAPU8 [index ++]; if (x < 128){output += String.fromCharCode (x); continue ;}var init = (x & (0x7F >> 2)); var y = 0 ; if (index < end){y = HEAPU8 [index ++];}var ch = (init << 6)| (y & 63); if (x >= 0xE0){var z = 0 ; if (index < end){z = HEAPU8 [index ++];}var y_z = ((y & 63)<< 6)| (z & 63); ch = init << 12 | y_z ; if (x >= 0xF0){var w = 0 ; if (index < end){w = HEAPU8 [index ++];}ch = (init & 7)<< 18 | ((y_z << 6)| (w & 63));}}output += String.fromCharCode (ch); continue ;}return output ;}; 78 | }, 79 | "__extjs_b67f2836bfcab57acb8e21dbe580790ff03192f9": function() { 80 | var id_to_ref_map = {}; var id_to_refcount_map = {}; var ref_to_id_map = new WeakMap (); var ref_to_id_symbol_map = {}; var last_refid = 1 ; Module.STDWEB.acquire_rust_reference = function (reference){if (reference ===undefined || reference ===null){return 0 ;}var refid = ref_to_id_map.get (reference); if (refid ===undefined){refid = ref_to_id_symbol_map [reference];}if (refid ===undefined){refid = last_refid ++; if (typeof reference ==="symbol"){ref_to_id_symbol_map [reference]= refid ;}else {ref_to_id_map.set (reference , refid);}id_to_ref_map [refid]= reference ; id_to_refcount_map [refid]= 1 ;}else {id_to_refcount_map [refid]++;}return refid ;}; Module.STDWEB.acquire_js_reference = function (refid){return id_to_ref_map [refid];}; Module.STDWEB.increment_refcount = function (refid){id_to_refcount_map [refid]++;}; Module.STDWEB.decrement_refcount = function (refid){id_to_refcount_map [refid]--; if (id_to_refcount_map [refid]===0){var reference = id_to_ref_map [refid]; delete id_to_ref_map [refid]; delete id_to_refcount_map [refid]; if (typeof reference ==="symbol"){delete ref_to_id_symbol_map [reference];}else {ref_to_id_map.delete (reference);}}}; 81 | }, 82 | "__extjs_dc2fd915bd92f9e9c6a3bd15174f1414eee3dbaf": function() { 83 | console.error( 'Encountered a panic!' ); 84 | }, 85 | "__extjs_b00b05929b445348eab177b6d3f509bcaa28782e": function($0, $1) { 86 | console.error( 'Panic error message:', Module.STDWEB.to_js_string( $0, $1 ) ); 87 | }, 88 | "__extjs_20637d8f642203b38c263a5d0f43b9d88ec67c31": function($0, $1, $2) { 89 | console.error( 'Panic location:', Module.STDWEB.to_js_string( $0, $1 ) + ':' + $2 ); 90 | }, 91 | "__extjs_ff2c75b4783fd5c9d8c934bbd4a03e66527e05e4": function($0) { 92 | Module.STDWEB.tmp = Module.STDWEB.to_js( $0 ); 93 | }, 94 | "__web_on_grow": function() { 95 | const buffer = Module.instance.exports.memory.buffer; 96 | HEAP8 = new Int8Array( buffer ); 97 | HEAP16 = new Int16Array( buffer ); 98 | HEAP32 = new Int32Array( buffer ); 99 | HEAPU8 = new Uint8Array( buffer ); 100 | HEAPU16 = new Uint16Array( buffer ); 101 | HEAPU32 = new Uint32Array( buffer ); 102 | HEAPF32 = new Float32Array( buffer ); 103 | HEAPF64 = new Float64Array( buffer ); 104 | } 105 | } 106 | }; 107 | 108 | function __load( instance ) { 109 | Object.defineProperty( Module, 'instance', { value: instance } ); 110 | Object.defineProperty( Module, 'web_malloc', { value: Module.instance.exports.__web_malloc } ); 111 | Object.defineProperty( Module, 'web_free', { value: Module.instance.exports.__web_free } ); 112 | Object.defineProperty( Module, 'web_table', { value: Module.instance.exports.__web_table } ); 113 | 114 | if( typeof module !== 'undefined' && module.exports ) { 115 | module.exports = Module.exports; 116 | } else { 117 | Rust.rust_webcomponent.exports = Module.exports; 118 | } 119 | 120 | __imports.env.__web_on_grow(); 121 | Module.instance.exports.__web_main(); 122 | } 123 | 124 | if( Module.nodejs ) { 125 | const fs = require( 'fs' ); 126 | const path = require( 'path' ); 127 | const wasm_path = path.join( __dirname, "rust-webcomponent.wasm" ); 128 | const buffer = fs.readFileSync( wasm_path ); 129 | const mod = new WebAssembly.Module( buffer ); 130 | const instance = new WebAssembly.Instance( mod, __imports ); 131 | __load( instance ); 132 | return Module.exports; 133 | } else { 134 | const __promise = fetch( "rust-webcomponent.wasm" ) 135 | .then( response => response.arrayBuffer() ) 136 | .then( bytes => WebAssembly.instantiate( bytes, __imports ) ) 137 | .then( results => { 138 | __load( results.instance ); 139 | console.log( "Finished loading Rust wasm module 'rust_webcomponent'" ); 140 | return Module.exports; 141 | }) 142 | .catch( error => { 143 | console.log( "Error loading Rust wasm module 'rust_webcomponent':", error ); 144 | throw error; 145 | }); 146 | 147 | Rust.rust_webcomponent = __promise; 148 | return __promise; 149 | } 150 | })); 151 | --------------------------------------------------------------------------------