├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── test.hq9+ ├── src └── main.rs └── wapm.toml /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | wasi-example.wasm 13 | wapm.lock -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasi-example" 3 | version = "0.1.0" 4 | description = "A tool for executing HQ9+ source code to demo WASI" 5 | authors = ["The Wasmer Engineering Team "] 6 | repository = "https://github.com/wasmerio/rust-wasi-example" 7 | edition = "2018" 8 | 9 | [dependencies] 10 | structopt = "0.2" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Wasmer, Inc. and its affiliates. 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 | # Rust WASI Example 2 | 3 | A toy program implementing [HQ9+][3] to demo compiling Rust to [WASI][1] and running it with [Wasmer][2]. 4 | 5 | ## Setting up 6 | 7 | You will need the Rust toolchain installed. 8 | 9 | First, let's clone the repo: 10 | 11 | ```shell 12 | git clone https://github.com/wasmerio/rust-wasi-example.git 13 | cd rust-wasi-example 14 | ``` 15 | 16 | Ensure you have an up to date version of Rust and run: 17 | 18 | ```shell 19 | rustup target add wasm32-wasi 20 | ``` 21 | 22 | ## Building 23 | 24 | ```shell 25 | cargo build --target=wasm32-wasi --release 26 | cp target/wasm32-unknown-wasi/release/wasi-example.wasm . 27 | ``` 28 | 29 | ## Running 30 | 31 | ```shell 32 | # Install wasmer 33 | curl https://get.wasmer.io -sSfL | sh 34 | 35 | # Run the WebAssembly file with Wasmer! 36 | wasmer run wasi-example.wasm -- -e "HQ9+" 37 | 38 | # Run again, giving access to the current directory and passing a file to `hq9+` 39 | wasmer run wasi-example.wasm --dir=. -- -f examples/test.hq9+ 40 | ``` 41 | 42 | ## Uploading to WAPM 43 | 44 | ### Setting up `wapm` cli 45 | 46 | To upload to [WAPM][4] we must first make an account: 47 | 48 | 1. Go to [wapm.io][4] 49 | 2. Create an account (sign up) 50 | 3. Log in with the `wapm` cli client 51 | 52 | ```shell 53 | # Log in to WAPM 54 | wapm login 55 | # Enter username and password 56 | 57 | # Success! 58 | ``` 59 | 60 | ### Setting up the project for `wapm` 61 | 62 | To run the project with `wapm` we must create a [`wapm.toml`][5] manifest file to instruct `wapm` how to run the wasm binary. 63 | 64 | Our `wapm.toml` contains 3 sections: 65 | 66 | - `[package]` 67 | This is where the metadata about the package lives 68 | - `[[module]]` 69 | This is where metadata about the module (wasm binary) lives 70 | - `[[command]]` 71 | This is where we tell `wapm` how to run the module and what to call it 72 | 73 | For more information about these sections see the [documentation][6]. 74 | 75 | **IMPORTANT**: 76 | To publish the project to the wapm registry, you must change the namespace (the `package.name` field before the `/`) to match the username you made while signing up and that you are now logged in as (`wapm whoami`). 77 | 78 | For your convenience, you may run the following snippet to edit it for you. 79 | ```shell 80 | # Update the example `wapm.toml` to be namespaced under your name 81 | sed -i '' "s/YOUR-USERNAME/$(wapm whoami)/" wapm.toml 82 | ``` 83 | 84 | When making a new `wapm` project, this step is not necessary; the `wapm init` command creates a `wapm.toml` skeleton, with your name as the namespace, for you. 85 | 86 | ### Running the project with `wapm` locally 87 | 88 | Now that we're all set up, we can use `wapm` to run our wasm binary! 89 | 90 | ```shell 91 | # Run our module using `--` as a divider to avoid the ambiguity of who should process the argument 92 | wapm run hq9+ -- --help 93 | 94 | # Run our module without a divider as a convenience, `-e`valuating some HQ9+ source code 95 | wapm run hq9+ -e "+9QH" 96 | ``` 97 | 98 | ### Uploading to WAPM 99 | 100 | Now that we've set up `wapm` and verified that it works locally, we're ready to upload to the WAPM registry: 101 | 102 | ```shell 103 | # Upload to the wapm registry! 104 | wapm publish 105 | 106 | # Success! 107 | ``` 108 | 109 | ### Running from WAPM 110 | 111 | ```shell 112 | # Make a clean directory to test installing and running our wapm module 113 | mkdir ../wapm-test 114 | cd ../wapm-test 115 | 116 | # Install from the registry, this will create a lockfile for us 117 | wapm install YOUR-USERNAME/rust-example 118 | 119 | # Run the command we made in our package 120 | wapm run hq9+ -e "H" 121 | 122 | # Run a source file, by pre-opening the current directory and passing the source file as an argument to hq9+ 123 | wapm run hq9+ --dir=. -f examples/test.hq9+ 124 | ``` 125 | 126 | [1]: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/ 127 | [2]: https://github.com/wasmerio/wasmer 128 | [3]: https://esolangs.org/wiki/HQ9%2B 129 | [4]: https://wapm.io 130 | [5]: https://github.com/wasmerio/rust-wasi-example/blob/master/wapm.toml 131 | [6]: https://wapm.io/help/reference 132 | -------------------------------------------------------------------------------- /examples/test.hq9+: -------------------------------------------------------------------------------- 1 | HHHH+Q 2 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io::Read; 3 | use structopt::StructOpt; 4 | 5 | #[derive(Debug, StructOpt)] 6 | struct Opt { 7 | /// Evaluate HQ9+ source code 8 | #[structopt(short = "e", long = "eval")] 9 | source_code: Option, 10 | /// Evaluate HQ9+ source code from a file 11 | #[structopt(short = "f", long = "file")] 12 | source_file: Option, 13 | /// Force evaluation of the `H` instruction 14 | #[structopt(short = "h", long = "hello-world")] 15 | hello_world: bool, 16 | /// Force evaluation of the `9` instruction 17 | #[structopt(short = "9", long = "nintey-nine-bottles")] 18 | ninety_nine_bottles: bool, 19 | } 20 | 21 | fn print_hello_world() { 22 | println!("Hello, world!\n"); 23 | } 24 | 25 | fn print_nintey_nine_bottles_of_beer_on_the_wall() { 26 | for i in (1..100).rev() { 27 | println!("{} bottles of beer on the wall,\n{} bottles of beer.\nTake one down, pass it around,\n{} bottles of beer on the wall.", i, i, i - 1); 28 | } 29 | } 30 | 31 | fn run(source_code: String) { 32 | #[allow(unused_variables)] 33 | let mut accumulator = 0; 34 | 35 | for c in source_code.chars() { 36 | match c { 37 | 'H' => print_hello_world(), 38 | '9' => print_nintey_nine_bottles_of_beer_on_the_wall(), 39 | 'Q' => println!("{}\n", source_code), 40 | '+' => accumulator += 1, 41 | _ => (), 42 | } 43 | } 44 | } 45 | 46 | fn main() { 47 | let opt = Opt::from_args(); 48 | 49 | if opt.hello_world { 50 | print_hello_world(); 51 | return; 52 | } 53 | 54 | if opt.ninety_nine_bottles { 55 | print_nintey_nine_bottles_of_beer_on_the_wall(); 56 | return; 57 | } 58 | 59 | if let Some(src) = opt.source_code { 60 | run(src); 61 | return; 62 | } 63 | if let Some(src_file) = opt.source_file { 64 | let mut src_file_handle = 65 | fs::File::open(&src_file).expect(&format!("Could not open file: {}", &src_file)); 66 | let mut buf = String::new(); 67 | src_file_handle 68 | .read_to_string(&mut buf) 69 | .expect(&format!("Failed to read data from file: {}", &src_file)); 70 | run(buf); 71 | } else { 72 | eprintln!( 73 | "Error: please pass HQ9+ source code via the `-e` flag or as a file via the `-f` flag" 74 | ); 75 | ::std::process::exit(-1); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /wapm.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "YOUR-USERNAME/rust-example" 3 | version = "0.1.0" 4 | description = "A tool for running HQ9+ source code" 5 | readme = "README.md" 6 | repository = "https://github.com/wapm-packages/rust-wasi-example" 7 | license = "MIT" 8 | 9 | [[module]] 10 | name = "wasi-example" 11 | source = "target/wasm32-unknown-wasi/release/wasi-example.wasm" 12 | abi = "wasi" 13 | 14 | [[command]] 15 | name = "hq9+" 16 | module = "wasi-example" 17 | --------------------------------------------------------------------------------