From bf39e3ed804297e9e0f9399a5260826ed9fad9e8 Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Mon, 30 Jul 2018 15:49:40 -0400 Subject: [PATCH] feat(doc): move book over --- docs/.gitignore | 1 + docs/book.toml | 5 + docs/src/SUMMARY.md | 16 ++ docs/src/command/pack-and-publish.md | 1 + docs/{ => src/commands}/build.md | 0 docs/src/commands/index.md | 1 + docs/{ => src/commands}/init.md | 0 docs/{ => src/commands}/pack-and-publish.md | 0 docs/{ => src}/contributing.md | 0 docs/{ => src}/prerequisites.md | 0 docs/{ => src}/setup.md | 0 docs/src/tutorial/getting-started.md | 1 + docs/src/tutorial/index.md | 1 + docs/src/tutorial/initialize.md | 81 +++++++++++ docs/src/tutorial/introduction.md | 17 +++ docs/src/tutorial/next-steps.md | 6 + docs/src/tutorial/packaging-and-publishing.md | 37 +++++ docs/src/tutorial/setup.md | 30 ++++ docs/src/tutorial/using-your-library.md | 90 ++++++++++++ docs/src/tutorial/wasm-pack.png | Bin 0 -> 21088 bytes docs/src/tutorial/writing-a-libary.md | 137 ++++++++++++++++++ .../writing-a-rust-webassembly-library.md | 1 + 22 files changed, 425 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/book.toml create mode 100644 docs/src/SUMMARY.md create mode 100644 docs/src/command/pack-and-publish.md rename docs/{ => src/commands}/build.md (100%) create mode 100644 docs/src/commands/index.md rename docs/{ => src/commands}/init.md (100%) rename docs/{ => src/commands}/pack-and-publish.md (100%) rename docs/{ => src}/contributing.md (100%) rename docs/{ => src}/prerequisites.md (100%) rename docs/{ => src}/setup.md (100%) create mode 100644 docs/src/tutorial/getting-started.md create mode 100644 docs/src/tutorial/index.md create mode 100644 docs/src/tutorial/initialize.md create mode 100644 docs/src/tutorial/introduction.md create mode 100644 docs/src/tutorial/next-steps.md create mode 100644 docs/src/tutorial/packaging-and-publishing.md create mode 100644 docs/src/tutorial/setup.md create mode 100644 docs/src/tutorial/using-your-library.md create mode 100644 docs/src/tutorial/wasm-pack.png create mode 100644 docs/src/tutorial/writing-a-libary.md create mode 100644 docs/src/tutorial/writing-a-rust-webassembly-library.md diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..7585238 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 0000000..0f3ec66 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,5 @@ +[book] +authors = ["Ashley Williams"] +multilingual = false +src = "src" +title = "Hello wasm-pack!" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 0000000..8dda69e --- /dev/null +++ b/docs/src/SUMMARY.md @@ -0,0 +1,16 @@ +# Summary + +- [Prerequisites](./prerequisites.md) +- [Setup](./setup.md) +- [Commands](./commands/index.md) + - [`init`](./commands/init.md) + - [`build`](./commands/build.md) + - [`pack` and `publish`](./command/pack-and-publish.md) +- [Tutorial](./tutorial/index.md) + - [Setup](./tutorial/setup.md) + - [Getting Started](./tutorial/getting-started.md) + - [Writing a Rust-WebAssembly Library](./tutorial/writing-a-rust-webassembly-library.md) + - [Packaging and Publishing](./tutorial/packaging-and-publishing.md) + - [Using your Library](./tutorial/using-your-library.md) + - [Next Steps](./tutorial/next-steps.md) +- [Contributing](./contributing.md) diff --git a/docs/src/command/pack-and-publish.md b/docs/src/command/pack-and-publish.md new file mode 100644 index 0000000..181e274 --- /dev/null +++ b/docs/src/command/pack-and-publish.md @@ -0,0 +1 @@ +# pack and publish diff --git a/docs/build.md b/docs/src/commands/build.md similarity index 100% rename from docs/build.md rename to docs/src/commands/build.md diff --git a/docs/src/commands/index.md b/docs/src/commands/index.md new file mode 100644 index 0000000..61c515e --- /dev/null +++ b/docs/src/commands/index.md @@ -0,0 +1 @@ +# Commands diff --git a/docs/init.md b/docs/src/commands/init.md similarity index 100% rename from docs/init.md rename to docs/src/commands/init.md diff --git a/docs/pack-and-publish.md b/docs/src/commands/pack-and-publish.md similarity index 100% rename from docs/pack-and-publish.md rename to docs/src/commands/pack-and-publish.md diff --git a/docs/contributing.md b/docs/src/contributing.md similarity index 100% rename from docs/contributing.md rename to docs/src/contributing.md diff --git a/docs/prerequisites.md b/docs/src/prerequisites.md similarity index 100% rename from docs/prerequisites.md rename to docs/src/prerequisites.md diff --git a/docs/setup.md b/docs/src/setup.md similarity index 100% rename from docs/setup.md rename to docs/src/setup.md diff --git a/docs/src/tutorial/getting-started.md b/docs/src/tutorial/getting-started.md new file mode 100644 index 0000000..bad5562 --- /dev/null +++ b/docs/src/tutorial/getting-started.md @@ -0,0 +1 @@ +# Getting Started diff --git a/docs/src/tutorial/index.md b/docs/src/tutorial/index.md new file mode 100644 index 0000000..4f50ecc --- /dev/null +++ b/docs/src/tutorial/index.md @@ -0,0 +1 @@ +# Tutorial diff --git a/docs/src/tutorial/initialize.md b/docs/src/tutorial/initialize.md new file mode 100644 index 0000000..2860a71 --- /dev/null +++ b/docs/src/tutorial/initialize.md @@ -0,0 +1,81 @@ +# Project Initialization + +Now that we've installed all of our tools and setup our npm account we can actually start coding! +We'll be writing up a small crate that adds two numbers and outputs the numbers. While this will +be a simple example, we're really trying to focus on how to use wasm-pack. You'll be provided links +to other resources so you can make more complicated code to package and ship them to npm! + +Let's get started then! First off run this command to create our project: + +```bash +$ cargo new --lib wasm-add +``` + +This will create a new Rust project in a directory called `wasm-add`. We've also specified that +we're building a library, since we'll be calling this code from JS. + +Now just: + +```bash +$ cd wasm-add +``` + +You'll find everything in here ready to get started. First though we'll need to add a dependency to +our code and make a few small changes. Open up your `Cargo.toml` file. You should see something like +this inside: + +```toml +[package] +name = "wasm-add" +version = "0.1.0" +authors = ["Michael Gattozzi "] + +[dependencies] +``` + +This configuration file sets up everything we need to get started but we'll need a few extra fields +and settings to get this to work for wasm and be ready for npm + +```toml +[package] +name = "wasm-add" +version = "0.1.0" +authors = ["Michael Gattozzi "] +description = "Code used to demonstrate how to use wasm-pack" +license = "MIT/Apache-2.0" +repository = "https://github.com/mgattozzi/wasm-add" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wasm-bindgen = "0.2" +``` + +First off lets look at the last three fields added to the package section `description`, `license`, +and `repository`. npm requires this metadata and so `wasm-pack` won't package your code up until you +have them set. There are more fields that you can add that are more specific to `crates.io` that you +can find [here](https://doc.rust-lang.org/cargo/reference/manifest.html) but for the sake of this +tutorial that's all you need for that section. + +You'll also notice we add a new section titled `[lib]`. In here we added this line: + +```toml +crate-type = ["cdylib"] +``` + +Normally Rust compiles the code for the library in a format meant for other Rust packages. We want +our code to work with wasm though! We specify that it's a dynamic library that's C compatible. This +sounds a bit weird but the `wasm32` target will know to interpret this option and instead produce +a wasm binary properly. This is meant to get `cargo` to pass the right parameters to the compiler! + +Alright the last thing we added was this to the `[dependencies]` section: + +```toml +wasm-bindgen = "0.2" +``` + +This is the `wasm-bindgen` crate. We'll be using it very shortly to make our functions work nicely +with wasm and not have to worry about a lot of nitty gritty details. + +We've got our package's metadata all set up, so let's actually write some code! diff --git a/docs/src/tutorial/introduction.md b/docs/src/tutorial/introduction.md new file mode 100644 index 0000000..c77a449 --- /dev/null +++ b/docs/src/tutorial/introduction.md @@ -0,0 +1,17 @@ +# Introduction + +`wasm-pack` is a brand new tool designed to make packaging up binaries that include wasm (that may +or may not have JS in them) and make publishing them on npm easy to do. We can't necessarily +distribute Rust code to developers directly and expect them +to build it from scratch. npm is used to install packages for frontend work but it doesn't know how +to compile Rust! With wasm though it's not a problem. Once it's compiled it's all good to go. +However, getting it ready to be distributed, packaging it up properly for npm, and then sending it +to npm can be a bit of a hassle. `wasm-pack` is here to make that easier. + +We'll step through creating a simple Rust library, using `wasm-pack` to get it ready for +distribution, sending it to npm, then using it as a package from npm to verify it works! + +As with all software in the early stages, this is bleeding edge! Expect some nicks and bruises! If +you run into issues or a bug please file an issue over at it's [repo]. + +[repo]: https://github.com/rustwasm/wasm-pack/issues diff --git a/docs/src/tutorial/next-steps.md b/docs/src/tutorial/next-steps.md new file mode 100644 index 0000000..c621339 --- /dev/null +++ b/docs/src/tutorial/next-steps.md @@ -0,0 +1,6 @@ +# Next Steps + +This was an introduction to wasm-pack but also using wasm code from npm. From here you could +actually improve on the project setup, expand out what your wasm code can actually do, or expand out +how you would use the package you've created. The whole wasm space is completely open so there's no +limit to what you can and can't do really! Go out there and try some cool new things. Happy hacking! diff --git a/docs/src/tutorial/packaging-and-publishing.md b/docs/src/tutorial/packaging-and-publishing.md new file mode 100644 index 0000000..adf6912 --- /dev/null +++ b/docs/src/tutorial/packaging-and-publishing.md @@ -0,0 +1,37 @@ +# Package Code for npm + +We've made our code so now we need to package it all up. In your project directory run the following +command: + +```bash +$ wasm-pack init --scope MYSCOPE +``` + +where `MYSCOPE` is your npm username. Normally you could just type `wasm-pack init` but since +other people are doing this tutorial as well we don't want conflicts with the `wasm-add` package +name! This command when run does a few things: + +1. It'll compile your code to wasm if you haven't already +2. It'll generate a pkg folder with the wasm file, a JS wrapper file around the wasm, your README, + and a `package.json` file. + +This is everything you need to upload your code to npm! Let's do just that! + +First off you'll need to login to npm with the account you made earlier if you didn't already have +one: + +```bash +$ npm login +``` + +Next you'll need to go into the `pkg` directory and actually upload the package: + +```bash +$ cd pkg +$ npm publish --access=public +``` + +Now normally if things are not scoped you can just do `npm publish` but if you give it a scope +you'll need to tell npm that this is actually public so it can publish it. We need to do that here +since we gave our packages a scope to avoid conflicting with each other! Next up is actually running +the code and verifying we got it from npm and how we can use that code. diff --git a/docs/src/tutorial/setup.md b/docs/src/tutorial/setup.md new file mode 100644 index 0000000..728ce0c --- /dev/null +++ b/docs/src/tutorial/setup.md @@ -0,0 +1,30 @@ +# Tools Setup + +## Rust + +If you haven't already, you'll need to install nightly Rust with the wasm toolchain! +See [the setup section](setup.html) for more details. Once you've done that you'll need to install +the latest version of `wasm-pack`. + +```bash +$ cargo install wasm-pack +``` + +## npm + +If you also have not installed npm already you'll need to do so! Follow the docs available on +[npm](https://www.npmjs.com/get-npm). + +To confirm you've succeeded run: + +```bash +$ npm --version +``` + +You should see the version number pop out in your terminal if you installed it successfully! + +## npm account + +After you have npm installed you'll need to sign up for an account on npm if you have not already +done so in order to complete the tutorial and so you can publish your package. The sign up page can +be found [here](https://www.npmjs.com/signup). diff --git a/docs/src/tutorial/using-your-library.md b/docs/src/tutorial/using-your-library.md new file mode 100644 index 0000000..ae7b0d1 --- /dev/null +++ b/docs/src/tutorial/using-your-library.md @@ -0,0 +1,90 @@ +# Run The Code From npm + +Alright let's make a new small directory to test that we can now run this code and pull it from npm. + +```bash +$ mkdir test +$ cd test +``` + +Now we need to create a `package.json` file that looks like this: + +```json +{ + "scripts": { + "serve": "webpack-dev-server" + }, + "dependencies": { + "@MYSCOPE/wasm-add": "^0.1.0" + }, + "devDependencies": { + "webpack": "^4.0.1", + "webpack-cli": "^2.0.10", + "webpack-dev-server": "^3.1.0" + } +} +``` + +where `MYSCOPE` is your npm username. You can expand this to be a more complete file but +we're really just trying to verify that this works! + +Next up we'll need to create a small webpack configuration so that we can use the +`webpack-dev-server` to serve the wasm file properly. It should be noted that webpack isn't +a requirement. It's just what was chosen for this tutorial. You just need something to server the +code! Here's what your `webpack.config.js` should look like: + +```javascript +const path = require('path'); +module.exports = { + entry: "./index.js", + output: { + path: path.resolve(__dirname, "dist"), + filename: "index.js", + }, + mode: "development" +}; +``` + +This tells webpack that if it's going to start things up use `index.js`. Before we do that though +we'll need to setup a small html file. Create a new file called `index.html` and put this inside it: + +```html + + + + + wasm-pack example + + + + + +``` + +We're almost set. Now we need to setup our JS file so that we can run some wasm code! +Make a file called `index.js` and put this inside of it: + +```javascript +const js = import("@MYSCOPE/wasm-add/wasm_add.js"); +js.then(js => { + js.alert_add(3,2); +}); +``` + +Since web pack [can't load wasm synchronously yet](https://github.com/webpack/webpack/issues/6615) +we are using the import statement above followed +by the promise in order to load it properly. This is what lets us then call `alert_add`. We're +importing from the `node_module` folder we haven't gotten yet so let's import all of our +dependencies finally and run the example! + +```bash +$ npm install +$ npm run serve +``` + +Then in a web browser navigate to `http://localhost:8080` you should see something like this: + +![An alert box saying "Hello from Rust! 3 + 2 = 5"](./wasm-pack/wasm-pack.png) + +If you did congrats you've successfully uploaded your first bit of wasm code to npm and used it +properly! diff --git a/docs/src/tutorial/wasm-pack.png b/docs/src/tutorial/wasm-pack.png new file mode 100644 index 0000000000000000000000000000000000000000..02f51b1cdb10317c65df0a6fc5289df8877ea35c GIT binary patch literal 21088 zcmbrmWl&tvwk_PG@JA=DKki6zFO96X>>N#mvcaf`-rNS?V8~0438S2d zx^?t*^~;0U%ThT4Hr+JVx`_td38N&iW)sl5lR7+fo>ku7IqBF|It}Tj3(<9t;46#l zv?lnm@e~@hP(Bpx@9iC=Cf`(68d2osyWxp&V%erb8W3xOY0B*0imi*{sCB;QGacr%FnS#Ua+O&K9q;kPR?QcB0S@0-=mmF zmO;!0bYjS06V$#R%*846)UG{L`omf7QExL&PF*xV=%d-@DNPjI8hU%zr23mQ ziWnLf4Qes@M%=BiBvW8?o0`fL8V(#YT3kGPHN*j9E78i(8vDW3k5ObAYr?CRRca^t z<>S<>WF}=A6SbjFp7*dw6x_?6wdz;oWVrenC+_nS*+N~DNyM31ORXDBppzbA;f|d&R>ukbuCypsQ9S-^j+f^m!e6st z*c2S5O#E}WT^xDywH1us*e@AJu|h-RdN{f1u3QBJW)taf7G*W|U!v8i`^0cB&NP2I zhH3o7tE=~ilWYk4_->80Ri5|bayzySolK&yn8(+AZ-aVwJ*t`ktvG4Uh7N(5dj%Qb zb+ZTz2CPfVUu4`zBYq^cmB23~Yff+@Ri@kw9Opwd!@ol`mAPKE)J3;-r@M)z#&Z@@ zLi`XRko+t3rr8|jUBKJ>TzXrTr+u^L;ByVk{5-*AWU!27v=a64fEaIF{EISS*3PEr zq;yK;2a$k40lMxMlci|Fi2~E-b2eZ6g90lYzd*M3e{}^e5tYLijTLsV)DbtoL(B1Z zr{&rfXWXOOW@79!>yr-u!`qw?f02-`{JyXNjco~YreXGbO+rV#AQxr6iuL#K%83cf zD?{ao@?tgqT?$*;JuN#LIuGVbh}LGgD$;9@qS#iins2O`vf(CEU%2OZIf!i~;Edg= ze0bm+FGMLrsr5!7jp}8+n!hYzH;?I%P?45UG5j}>_}O!nDmVS+zcC~XmYt8?S%_mKH+XMhO)zkeiG%KgC~XP-PNuU^EHAgJh%7VSL3=9juExY;A{Cpp z>;{KrqOS&n9-lK&r(Y{+yilX^#S2)D?}ek%rx5V=MEl4J$_?@|ANwSjjj)(vHj2Zn zCmmiTa?PJ9d?xsG5d!ZENL&z_1oN%6BCiF8q^Gzt+*tZ{y7c4se%8&fT}L zC+W-V0(J%7Nxc43fd6(yLj|};1-WVTM$z^Lz?-AlavhM%heGhOzT$evwOUlLmEpg< z_BY6mqH%yb!WmB>Pyc5WBPRLMpikn!91@mgjpPZ@jiS(o4DT!i&$afz5OeCI8;1u5 zy?6oMIV^<<~F-Ek7FzBs5X#@MXbn=vi*hGr`c!1IhR!V z>l|Cm@gQqmU6VfBAKm)qS**PdtM8ryOP6sXrb%Cs2|-bQ zOi;giSSk+_b*wf{o$@=a-R75mdKAVHhHt^l9+roUcLGZ~Z-4Gg?kvYuy-^b{O#VEe z+cU5wrMs;>-*)57qE#zFWmtqY*tE>{>F9kaU7w(5}LM9 zjwI7gU?D|-*Q+-q;iuur8{lvEl2N1uL3=*e?-UR(^cpuBoP`gY+E3{88_yLUkN z8k5i2R5$OQ zh26lY$&^%Wk#WSF&Fq-kkRLzI?K)fIEJd37Gf5BK-lK_~LTR0HS`K0)yc7p`jfrwf zPhr9R4?46dZmP_&i{MhKsAsD`FcYK->$yJ{D`$4 zrY`m-GfB@To&40%Ke?pATGq}8OZ~u4!bXp3U@7n@nghHb@G##$pwNpi<1&$5~K8}Fj9a! z1>FIiS)B={yyU~u4a}VsaX;FsH3ZC|hzyU|zD#pZMB<;6t;MV1{64)~NEicbmG~d@ z)!5Y|Tzs+^FH`m-n{;Gr`VRhpyTivMuKXebe)>LJ(b$PeAna&2QK~6npr==t#iRXW z9?IiY%tIKNxazsur#&oRx=gxp&gbJzN)~raL)$~`bN|+%!RhS*QcgnrVMl2~|1E`o zpc|G~d}yms!Ow0li7tNZ6PqG`_2o`IM1LRcc{1%rC?SR^9x0A) zX-pcFWh>g7M=Ru2l$MK^gk3rBs{1!D9w-6%0n=7OW@cBIE$;%Pmy{Pt(+HQdr`PY| zqy8O1sRwvDviA(>C+@Y7_XdI_kzjKiq2(1^D7=3GU=516=rNF-EuKwclC3J2Gb^X4e2qrFy- z2v=}Xtxg?=CZ8|7H`ZajlO4zk-o+y7jA)g$&&ws-Y!Sy6#_;KsM4^ zfyAT6LW?qIlUx7cB7(%F=XGvQj2!%T7y}xGJT+VeH!Lw$dK-SV{Cp9DeKw;oN2#EU zQ+5vq`c4esaSfYK@$u|N_#$Gc{V!}u$&9i0wtv=l&Vn8>9#e#=xd}$H7ZSrD;IOTN zaTYR!w1vHA_4U4PJ4RcXIU;%WT1#J?eDnK6Ss@8qKIQZq)E%iEt9gs*9W` z1_N`P4aJ_5t;O|LHv~p&5TX!0e=Q7rIHCIlQveIcUfG#@HI*@8YnqWSUSb?Ts7Wau-yXE~G3{ykA1~Ys91#!{}KLjhF zVh?^9Ma=2L@n%|InKZ71Rx^V``89g2Y+B%4qU65fTy`Nn)iq8&drx z=IUmc^4`*Kv^18sSMJy)7DT9~Hrp(6_@xhPlrEN4I=ot3&Au470+(N1wmKE^+7;K~ z4^JT+lbU@HFAAOsmmne$8E(^von#f3`4iURaAr_V{h`qPwy=QRU_h4)H@A05fl%z{ zQX6NJa4P@2TvPVQ67$JRIxpU)(C|xd<{~$)#n`QD zZ5Ow}g?L2q%P<9cBFUeI)dqp%s)2r8IXRhfObRiHJ}v3pv?aA`zNB}pE$)xE4UUJ? z+#4~tQYeE%5MGCUuA7}~((|33{RQV(T?!C?-_gi)M{16uEVsY2<55Btk#F?YQ0$Ef z)+lqy6rJ*&`zq4i0)L||LCDn9Cx}RkWHm!vy%JH8!o(_N2P%6oR8;96d0FU)0Im;Yi zXxR6>ACW`F0DJKg0}xuEEzUdG;ss+6+ue2m2!&J+g(pp*$Sg5p+mj-D?EMc7bZl2i zUzcerg`aF5hpx-MN4CS<+d-5OQRy1v5EE}_wG}^XS+3jt%1G|5q(irDzFuNNh+R+W z7#Ee{=ezn_L;4&Cb=Aaq+mSCg6<+AupJql4Y4IHVoLE2=227D}uKZ1Y>u6mRCmo=a>)3 zUkDzP-Wx#Vcp-J2lHVu3{78Wxjlq120_L8N-)b%`Vt!$&Mn*sS6>hXVFaVSkQb)O^ zgZse?=MmO0R-EiJ#+RV3ds^6aQZQPo;{K58TlD~^0<--;!+BX%LTW<%o~nqW1h!YX zoXf(zpEp~N4q%lu%0vXX9T#45JM@`vkbI$y+4B6NR?#Wh8cO_q-u!!10*-U?%A#jD z-{R8_HPbP%L6=V1r0>1b9rGN`a7FJfKubP&4?;ut#u76LX#}GixvaN{kBoUtaeIP@ z_QY$Iqast{k=AVgcXeJmunwIdL=5ypte?|eL^8tSMU%c3B0S+bLEZkfug)mPpVwEo z=f;j*H{;qiUUn>Lhdq8kPNuIfkjQZM$OTUSURB2!ag^Bh!nVTo#_c|-)_7N2zhx%z z*EmFd5TcF`*0{tgNlxWsaQK6t#qkn*ApXrB8Y6mhrj3J!otslcPJ;ON1YYTD1J2?A ziL|#2&^Tqp#V3K-brDV8AAi#RxH9HDbp%&7LWv*stu?sjw8Xr6@h=&TCZ;d+ulB`Mp$VMJrRC2 zosm(DOx~^8+icct!NK+RwMN8GpXOyepAA5^zgg^LLg>K(FQWA>d2Qrg#N6Wf5gap}sS0(juSz9n28C%acew5%3Gu#+T2n4qM+%Dg zxOF1cO}&AQ{w%SB=ru%_i%h8AZ_7>}g_~~*uH#k>@B{2D1^fe>9Iz?)jU#d)~+HE=l=O;f0@f8Ez7-}*Zv31|h zauJiB+W2t{ecZ%E6(SOQT?v3Uc3pR&j2PD{TGix3U%9*wU!@359b6k5Nl-&WJ%Wkq zG|$`lbl!)@TRMiwp?rt?g^N!F_M5hDq|l> zv3~GZV$;#Li@eOw?dBS}dkcK9KpnUtnOAm{g9PlWrqVdb5bOMLceJIs-xCWAkanby zxy?!z5{z2uk!VcD944!2W}fP536uU;z&`BsKzv2L4w5>qA3*Q#^y?!>^bz}NgI>GP zxj2d5rtpzX`)26$Me7ku=0a@saNlsWo0)~34wVAeGP441c0L?mRKzPHiB+#&wgX4@ z&nnhY^RwI|+_(bD_zM{Fao>V<(Pnfz4R+NbR5zH5@E-j#MX#mcV3QdGBP*ywLZIRh;ptug&=pwI?hi%g1F1-QLIB!6sIQ2zMF+J zoYjDu26~hx-ooTUj)QG+2-V2InjNcKF)%YJx5O4R7FEd7%4H@RdgaV?wKr~qP9fsiS;(J3 z_Dd1R&%k<#J!sQ z_B0jVK#J5^X!AA>;pJA((-1;*P;0LMU&crxZR%0nK3~^qDj#Z}UhX(7LH0mNPM(!sULk-~TXo zCV?oAO>|77WvSQYk=^ZQ#8CO_olqqXfsN98&0_1^vzO3pa!yw!>$y(~t~VpP{$nmg z?OfK01N-yMXH1*t)DdCff&;nbtQbsL#Ol`m#uGcmH5! zZX{bX?|B0du(Ms+NfR+!Ux^9(49N-$m1ctXwY-R#>G!**k}E*RBnG?V2PEjw8Y|;* zR|t;2>a`WyLb~!IsquHoFSKGE7Z4)JDSuyvFdwX}~wo0xP-iGr!EG>}bh%348~ zUe0xEfk2HYx`iR#E}Vhb>ERC;$2$wnT($*#50!C>twDieYd{cIi;Xln1r6-p!pG9i%I$&^6^l-gNw6w9?mTjR!EnG?Gm_2p&Xo|9+# zZt3bBz}nz4p}I|?F;@0bhLi(Cie6G@+*&FNmuORA?X{yLd9i zoVv)Yn#dNkayQYkHdcBSdoi5gEi;yVaO=Oct`f^P?nBJcd@j1O&Nms)eqlSJ_zuV` zAe77wbTlxN{yWLR)!IOjU$3o94)TTG>TrG{R7H)^*M<;s<;}8ViIAHUtoLndXtuOF6n*d7a_NfhapYUv(A2DAbh?Juay4Dk%zn^AV3b;}f5aV{RdZtEeZ-Fe~Hb0mSlfB8N$6} z%r&C)oulugvtlIjwom)a$ zfwIINBd$xQtLUCrYAla?r4M^rm-RFB7S^FJman>*&IhzED$Gio9O$>2a$0T|4;vY{1A5VuYJx;YB zHnp|fJ!Z5$@5uv+DpCaSkne^@JT5AYX$2pSBeidT%{+8l-UW;pFtl^xun>l)ANf%) z?8-Vq?%dA{weRnjAMf8WHl0O2UPaCb9u2aN+^N(5u57w&I&3<0KfGPo7PvIzY#{JZ zNk98e-4aIm#l9u{z#I#p8?$$ZcX!#Y?AYQ zN&f3Txra;7N5@AmaPSH<{~Bhb5SLrS{Nll=D0Tf={njF`vpZ5Kfw)<3}7Tg&a)%*J4vPICX zV=EtcOZQq+OONAFZCIJ*vs_O9674I0Z7+&ZFvFqe<1KUxZ?PVBA|H(D!_99xNG{6q z_%>-q;i!+3N8GmbNpEL?U#u@koEGh8G~LgqUQ~dm!8=wa*423#9z0cUJEEk&j`9ys znHCv;;;Lrfmfzc0=)$(%ok!?~dU6U|yLgmkYjFIEogZGs-0O&kA!cLr|Fn=r%d<7k z6}QFK#N|75*v-eTc8Gf;)_CfJ*9eNTTXNq1R_J*>pdGMX@o)`uxO5c2*|_$+^y;Ff ztPL7DU<(epad^D592(Xzc;k_eeZ2uW}J(BrZpQPW{A+`=yVT-^O6 zHiPeS!B+4%SdJ{!PaRg(JM@g&^Mu;-($VuWoAiEX4u~ex9L2bI40RhL5BnoRupdf0 zP!W(n$%+*{p2U`42h%6)?K0 zvWz(1-*=;Zb6hhf%kDyL9<*6e!q;JCCu`A?C%9FERw0@tvLDH*g!H!4+L4!i`N?1 zxoVRM96Gk#lIv)M64>b+ZzgI#WFqh*;on!0!QAgj>Vf3ZIvF|yvs=2cpf{z-@vtdR!qE0bIBnE zSW1_iWUxZ9R&id14go_C)22`|eLouQqr?Zf2>h7oU&8YyHy`MJVL__z#n{9|D1^~m z<7Z-Fe<0NCh$-DqP4!k1Z$J(~79VdXNlu~yolb9;A0OmAPO#79=*$D4vGNJ!0iZzK z$hu1J`b*jFKzN`Xe>|g4rj~t ze|{(<_qOjq<7`cKpPyd}aGSd^wl7p)L>8TIx&GP`tcsNgbGxv~;P{EY`Wxuivzp4Y(hREb<$(5sO>baJqZ%1e6<*Vhcy9J0gdzM_W~**$y_sTQ2c<_hYr1!5mo#-+ zl^V`GgVHEC-AjnwUxg9f{y2_WKh`cr*a|5r}=xs0r9-CkX-hb!H@F< zA4{bI?*y43rYA+rQ;wLKF+4UDf0|GN-;45(tto}DlV>JniP*@Y)A)mZa`USPlRYvB zO-q28sKTG1=Y)A2U1XxjJqFl?t3WOS0Y@Mig)G+fA|lbM}WM_9k{2XPO25{ z-#G`=Mp6y_H;egBztxwKb67_(W`BK_!aHWf3YB_WlEIVoBTK;A330T$*q%9%vV}?h z%H(Vcc+o2{$Cnz$zoauFT=gP;`*_U0qK;+3A^n=X?;yZ08RkDTq59}CqTRvVL*y%P zT^{LP#Cu2XB0eH1X@2raH862?a!D&~jYzyW8_$>9s)FeVSsN*WDL|NT3m}hp|G=ys z>k3nyeD>;U%(t^S<{53tAO?mIgC_ML!8aB;soc5( zqN5xBcpuI_vJciplYFd1|MUV-n%*iiv6it9O9!zAQ_%3grZX_CiboJ5(@@e+ykKJ^ z;SwwLI4{IpB=Wdg1!@2#GcH(6h#M}e>!<8Qjy19P#LA9R_oqBkq zWIE|Z-Oywg*u$(#1z@SeKC`bc}R8PL$rt7(i&VH9~%kte8 zrwU#yCpE|r@U%eR9Qv zXtYwsw8p59W@LO#OEH$T#lu@M)2&+_1kuQTeusO;gOVA!o-#6PKMg!kwDfbx<~b9T zHDT}dKHcnHjI}kaZ(@fD0mo+&4vO?4Mwy`0wwc0(S*9IggRm*|zs=*v6q?Z0pYTGv z^)KGS6hbP41mVX59L*lSKUq+%*%jkY6EF7T=GL*>TuwMM<@)%4Jue!(Y{QPTeQmgT zOJEpQOxkyiGZg+nTZ&x1B`iU8;{J>6*L-zkjgprdANe&W>IZiP7 zE4tRg%8YLt5G&e$Kf(1S*%h8TCSOM2DIqM1o?BP6c5`^XpF%6&A*=&WM1fM<7=|`U zI!azt#H?-rWiGPeE>O_`1pikFduM$rRa0shLE}P1MIJ|)Pj`@Ed}SQ;t51sinfft1 zXLzL_H9hqGjsHcMaQqj-#5Aev{Yx0uv2sN3tkbmkvoZ;y+hG6!Oa zx8kxnhR<<9+w3Je5I)dZ;iuK>JllKd22r%c!%!)jq)&LE?oy)XyJb+nhdJ~92VK${ zkt{3+c|8+*-NsBRudO!jcGJqE`{uf5K#BdrVO>!HSd!P0z*E0HG=Z;lppO(%h?qfB z*9TDLr5OK_mCk-(G+qE+W5em>H_bSgv*>YNwo;oVuj}#>p%a?jl;F3!h zqD#3Nh@a5dF6rN;NRh&!L;09-Ty@BUVam%Q?HwZ+KqU$`p2lGWcvfW(sMIHJ^VUBy*U>BP5 z<-gF^a#PE+L@^F&9RCsM1#NC|6n3lnsAMzv8!9|GnlK@gu##>eGhbE7GebskG1x2=#Dz-jVZ6Z|9XS)(7PKwUd>DHU^mnPEXCOqOQA*ge@BxftX-DN)R%N? zS-8A`(iL9-Dj3M+G{Q7Z{5{{S6~kS~IA}X7Y#*>61G0*+cU|1&HV3i3>k!L)C_BrM(kx`duOaZlxb1 z5#UMSOUX+1Ut=9D_7k|&c4+B-wea^BPzm46`kPA4!FH={dV%sHB~^@paOa4L+0mv<%x-r(Z<^MmD(g-L%Jh^AP2`OY{0$|5 zCt+Uhk>v4v_qpWF#0$ZaD+kynE63-jJY`*oyF=!W+ocpM%xD}-x=$DteL$HJ=T8v?PDlF^3}|zhX8aJShW?9t~9=| zK1fa!By^V zrznp3zcwO5!u6M@&?2|f2I&y>DuFh2hQH-cCDD~T@LC0&BVpNJ{eB%P%yjAwR*&V= z;oC8M{bdUrhw;vE>>XuiJ55u1H_3rxffNuQgedt3mO_ZFjOkj1$P{buspj_;hrE98;iICal7967l#Y`_sVziDfW`(@ zBLyzFa%bk}7plBcK%*iv(4}mQ?up{EcZ*U%{+ZiPsIC%S2vyfUqoAULl|geZNgdJJ z`{;t<%_&C(D@18(k=Zgr5vV8oh!q=*JAvzQhuH6}SziS&Itz_p>aU)&DL2p22mtS% zqzaq}P@v^6@lG$9y%J}FTIYKG>1Y0pL=8qLfvNbrzZD{s%_Xyl@dmLw(Ll)k$4=;x2O`&Eom;wISr&PqquEbwwqhF6n6C zV?a;Uu(>5>W+HSUNU^^7RY}_51Oh&#@9aJ1Wk#!!6>Zkr4l;p$?3Y0jpf83KTczd3 z!-vqFtA;~;j(i61`&Xe_`}AUrqFRaQcOi3UpBK?`G;ufm1 zkKkBG7YyyG`_ZlxjkIWIBSr;Zz%d@)Jr;L+R-slBLeY=%2Vyxi=*j5+O}1@r2p4Lb z566tS=9K^r@;?+R za3`QpZQTM2RVdAGB#UU0kHn-W?p|y+z6@BMQ)U#m$4;oW@*sD?Uw%2Py$}XQef_>t z$d95i$J=%k#v<2wMHgT}LMZ#p8mLckeaGG4qUcyr>s-%w@0^^)IhpyDaY1klHjG?+ zS!9}EV1aEoD(yS;M04RLf6SFWrCS6=lG!(B>-gVKu(*tbC zHxu`2;~P4~M^vT!C;Szz5vE(-bCu7OWH)|>XpPeWTY2h5=ccgmh1{O~SzY-?9e}@H z{u}(IwE+(P|0Px-e3ggbkK8N}< zG|(uOx@saE2!15g3*P+f6ks4ZXsvc)e+LP^<4}OHg5w6Zk>2I_&}hJ=E3HiT_DPz4A$bG3jzLYJzd&H2EVcL zH%Ul0uv|z1al6DgufMUgfADz9P^8eTVAl>9DZ13T*mn8B$R#Q6T!a>Kr+19}0{doq z>g0s_hFlRW<)L7hH8QYV46M6PaEyj#_T(1Sn)FW$)`hN)ZmW8UATX>_3b)hAlrZ+@ z)T`vs7fl*3`H0FA4;eOqs0{dCJ-=6z8HQPfhM+{^(FFLPhf`6Nc zuS;Pb7mG)zP!4N{^eJp8jY&v$3%$LNU-qP5EiK@U*Y6QE^{dZ)i?6o zMq#wBWQAJlkFjlqLCPV$_}3?h;%(NShH|8p?*bQJeT&ZgMH0ffermp*1u20DW}R6dwR%vc1y2YZM)eN`t>!6ToGL zLD7BUGn1E?M4`hcWbl(~`MC4b$1wpT_qQkx zWQ`QwH&Ix#?-Ss0eK%$kz2Jvw9K!wNrJlS(8qVW&@xaF>t3a;jWf+;PTSxCLIl|K_ zY;>F)(Oh)>-E0ny=n)v4+TQNH{6$UtHG%FJ^GFY2*Wm@t_gCUtR8TB7#G6(Dtq~?D zPu=XWl;t*AZC$sxPd*)&kCEcDFF${!W3ma}gpV1{ zobzX7XO~@0Uyuc0OToXxW8X-lOGeMxEWuSrC;M0__>@Bz4|;crA6`#o6`B?~d{wjp zc95w9GJI9Dq8Ez^7*wG0%GtHyY&OLY&+zArR6zc$ZicI7g47-`YOr!UYqW=AS3Q>; zjka2#6L0c9K7xy{T&LJNB6@coCPnWUbJAy_h8Auea}C|1Gac_$a)9{|UL>uwcX}I6 zQWU`G<$gkfWcqem0oPY&>lRW?<=pBtIwU_k2=kgefoNp(Q;@%+3x7EO!r{kg;1O)N z@{7w}7+!~|Us&w>C*mm@P2$$wJi+m__e?xqZdH^k=(XEDK7W>x-k{L+t4!{z!m{g7 z{eGxI}pdyomcXojNbb@!*VQs@AuDBp0tygop%dJP( znBMKYI2Bh(gA2OQbl!}oPO}>kMd!Cul-1#STiSfH2S|$=_#64z5hTN(-lz3}pr@00 zF!IVZrSPp5CB%pluUcbW4@Z$CYUbI#SrWl)iu!*thr4~4J&VyT%C;^;dnH#C3b%53 zKhC)LC&jE}sp+IkB`;hrOaxT+HM8f|L6z*Dh8B#|?XgFEJwqcQ->eRNay$Y({ zd$_~Vl!8J+n*PrNYC=PFiN(4A0S9ugbV5KVQbpEQ)*m(wyDUFGe=#^P$1AD@xY)e7 zg5(V&+R#eWqn^(5bI1i$RUp`K@5h;%HbaW6Oa#(c!p7Q-F3I?EUo&gWWO= zgFTCYSY2KJ{A(KW8+Ed#mVWs3(yJ#b01#cNQ~w`HFX_ROF8+vxw{hl&a)gfC16o3si%o3hlWQfMYsi2fJYR0Jtc*A5r= zYpSJ_P))jLjP{jt4Hc#gSa? z@Vu+Tj=wy5FD@Go@2QvWEhLv#FT$T&>n&fmEW7{tx^$OuXp^`t@SDKtb@8?$@%}v# z4zw8(Pe4R=-&yE0>!=Sf7FR-!w1cblw|JArxBAueYgY-T!P`|_sjU9z8=xZ`+tsud z3Dcoh^rLN%*X0j)c+F>Cx67q%0;FfXl6sC1%Y0PM%M_jJ&)noY+yUm^0?|3nMS4F!C>*t6z?1RLAPdmKIH zR%tpvcD`3CPbv-#lEsxsT`!Pbjjm z6z=_*z-9Byvgd&izWZN88c{4B7b;a6TNhRzxSBmUHtFkFAMA*F)ElUApQ5e2`zD5Q0DG ztmfiN7|?rA@vUkrUglNsw-fZ({?u74o7%V?q!%2cBqs+r+i&}D&XU;~BQVzjh~F4r ze=I7nF09VxJJj<|&*QG^8&0!y`BNx(axCX|l}#!NhZ=j{f<-LE$H-)!PqyOW|qz~-=~D4j_XSuQHLx={`0a*D9+ zueL>gK+bS5FbJHqE=E6%hO!+r`$SH%PrU4 zPnt-#E6a8CyZekkpu;Vm`!O#s+XFyHcyiDU_K*FfgeT8eq6zgX;2&o@eLIjtp;XGbcw4}brPH3lG-5}BY-K>(T-3|KgVnI=vI|VQ$;`HQow$y%!}|NgL>EBK2_0Y9MOR|Vf>&|4D)Mzz-yOljQEH2 zAk}08u-o?wuGMXc_Z1Gwl_tBkQ&QJ;UldTjU)FS4EC2>k?5!|9BovTz>=Je;KIcH- zI{$1o9~qvD+u7w?z*DF1Rut%5_smDsgt@YnaR*x_ZX;)GaQmpup!};C4(B+$4wiK)s(@nU11+;Qo5@icP&KBk$?}&(p?& zZA-c9U5rLk8{+N;=c3b%l9lD+neS|5YJ*4i75(?Q1+qK}!)@9`;FW-Yk<}W&^1jtZe z>*86fJ^Y*5KacwdWLtG<@Et_d``XJ`{+mt+ zQOQ-r;_q~;s1XHzzL>o?P7Qx@s#`i zp*Lqp2n5s1xwmK67uPH9JY}BYw{|Jc@@gwO<*m39 zpqYDrGb-xHP)**v)ey=ZDK3j2SxZMJEB~aa6ZQ!HIqmx2(bUS@t2FE`WrWS33ujmu z791|cf8P{gzxi#lzv__}0$p3V*WLrXAIODN0Y>Au?z8P%lzffdz%j7cFQyoKyV*O{ zvU^_P&)(wKAt}V6nec-Kiy649RN_G;^@39$p+pu7l*pQZ9PD)nLkkd6X^?m;-Hko{ z*S=jd>|RBY*_HnzQ>~~ahD5?+Mwr><(#9Rb7r_GNX6db@?2T#3B#lsPmSgK0ihJp> z4ThRTuz7wP7r9j`xl-Z+n?UwEwA>VV*aHw*1*}M<*jziSRx^+uyT9n#TR8 zOM<6k6dVLhRN$cj6BW&tz(hsE{&~nh1}c;{ZPcV? z;#Rmcx_mBWL^pB9a5AAbi+3%s)+jWV-wR4caOUmig$+_Lqa6MhPmOZBRZ@QQM-~p6 zzRE#5K*Ri>i0UJm|AweOqQ1d5FoZ{{!#rRSGmCK}czwa)veeolFCAc+5mMovps%&xnCcwgi94b=d+Na3=XJh7hPI{`r@iWO zq&1O3dgj5r)$aZa7M|0N$e4w%$NyE}&`-8Ko2L-IDF;RA{!dIbs?<-h@kW+t_lz1zU+3twv6~Ge`EVl2GFBQkRtqH%t_3yp z=(g4nt~@)v+r^Rl6;y6e#Qoo#0)@KY3$CWe7$~PcTuQbi%=UD35YOV48cLHzFH@O5 zja2j~{|_S-p+#HkR&WJ(u(~2NLWxxO6R3!raz{os81cxHR)Oyz)-M&}a;aFyLHgjKsn8J&{h#`p*mQ@GolBg6n zg;IyxJj9@@*Z;f7%Z=w*`M;31ApQ_h910Mw?8$5I_x|aTJJvTv>C6` zbR1sVa?(%x4`)VFCEUtQ(~&siob#-%tz^Kxn3w(N7v$^&S?*07uNor3)tmySEBUXA z9yVK2n_uVI)|jQ?_FgKzEarap5v5p1C0Mv`jIv2p%`V(&a?+{y;t$aMNaNjKwg0b1 z?){(1{*MDVX+|x}p+#bjvDn%uhq%WSNvwlIPSwaEH=&Sj!)&GlF(KtNa;DN+g@{N- z$SHEFi5R(^Nho};Yj@p0eIMV)_xb~_!}j?+uJ_}8z1~ltvr#>?`gfiYI2}RqMF7Fk zhPejh#$e`RQiegW*mmICEO8-UHzyPBrpT~zx9z&lO>tp5r*3(93lX?dgr5 z%?QMvz+B2a4bc%*1ECW*GdYLZT2kkWRoOg#LqBJHRnTp6%BTAB@+_r3Z%!hT*w|1} z;@GaZtZu?G%T+*M*-yHV)ggb#^G}%aTN*ePJ)zZS04sQQ*c3>#t-*Nf;|tQ?b6a&I z0@oH?MFOhY!j$4s&l3{R(ZwR(DA+BFbeLD+!>$`Xs~S?r=D z!9P)mTcw50nf|!w^}{=JA(-Onw!^ci^Nm{OQIW~FPNaGnHkc4XnMTX@SRH096lP0j%knZ>Mk-%K&$;Y|5Z7N z3>{qbu$rbr9=@*h2Bedb#DD@!GaNZyE<u6ULbgHo)YtrG<%6v~F@ie8%bUN?dTPWTRGp8d*$e$vD41tyhx zDo(~BI%MXDDg4`3hUOb`)HXVxLy25U?03mXueMb zE#W#u|Cc`szya^oC~|2hTzPt4k#3CnEYE_+Q1T%BJOa)71_ych!@lUSwIQk+0J7YhxdVEU}LFd}%O59v1*3OV)a`G#4oZ7X=(`yk!co70xr z<`(cRTNMvUS{#wzPGzyQ56qV-KAJ$>K{xzWGbtD58dqg>FkrpT5Hp!5&SsaUV0O*< zG4fX>*9EKh8`8EVm;;f71$m!{UQ1!sw}GN4Admq3?5XI6Dg|-_k3`fSJXa&ppF=|X zw@&MUp2tB{ zLAS88i}}Ylhc-R8jQ!y?1z-)f_@R#5+DnM>2dQ5W4$xrKP9m*0D`H%!v7?E#oG zSh9J0WiIKX1lBrMw! zhehAhy;r4tP%U?Y`}L^V!nae5uUF%Z<57EzCV^B%`6`K$V%*djXmZ z_WC~)u!ay4f1AGL;sjc#V=kxnIp3bQ{b=YraC(7>3Sr&#KZ8H}W&LJPHS=aa$}Qtb zu9~s(qDqvS$YNcgq*=J;RkF4lk)^KIe#z;NC zNE7kb@9qt8yF2*HLaoAnDb5O*w6i>>nhDEDc%^CCRg`R+RDR5&TLx*0A={`&W^jEy zUedN3jd}CSG%-bbV^`tejc3Ia(-ia*0viB7M7oMT86*?&E7b8wiw}@&eU+YOL%mP} z+br-7RHaK$oZ!~m(jhh?m?FAaTjw22mXw1?{?YOefH``J;0=gb5a!arRui~=>JkpMhnZk6C4Q`(Wq7t zM^5SAJ?6aV@gm&hkqtb!^uzX%8z$&Z^;|03Q!iqIDy#`*;cSLVzJ^yQ0ohH&^`zWw z@$n?{R1h@D`IN1U@EAHKN|%8an8_Y7g6l|W3wd=fF?>sR2WmoY%tbo{rP;GbMVywl z0=|jm)l+{mvU?@ZeBbH!%7y_`BSI?N*YUW@3dZ*a6GLxVUj*mi$D&WPJ2L}1uNNIR zeFvWP+u!$}j*bs4Ps$Y^m@_#KiuspN4-MPBvct5ywr0c@_Jlh?n zEza!GUd_bt)U}S%-t7T=-=sVA*#yZ4fjO0q+#HuLJ#PhAZcZ-$pKpTwV7edOymMEj zXZtogAbl4Ajr2I+bYg$}WIN#u2zDqiIf?W)w^ZiEX(J7-X*SDjYGC8G9Gvd`Y!s1ut(L|seuKP za#c%lzKNeIUkHaj_e-w1)Veq>yF=x15U&U~lhbb;$#I@>P4v+}^YEG7E2kK4nytfk zX!&U9H%I@rZ;P@E;xN)t>&hF@{w}=K46Ri-J0<4L!-&(zUr}kuB@Y$Z+1~8me%m-I z#2HU+$aet?BWk8W9?(h?&;io`f=f}Sjc#WT<(St5Yj{f6>{YxN@@w-B^M}1l@80?}+zehZcVTTz z2&p=)QC=X2zx5M1Q*qM+z;Z$gX%@QxDa`%P^Ve@U=$qy#n4mH(wL)-k^{lmCK!!c_fB9sn!S-MT3`ay_Bykg{MJU4H|~Ae6@ko35`30LM{N K;^7h#674_5r!a&7 literal 0 HcmV?d00001 diff --git a/docs/src/tutorial/writing-a-libary.md b/docs/src/tutorial/writing-a-libary.md new file mode 100644 index 0000000..71e9c78 --- /dev/null +++ b/docs/src/tutorial/writing-a-libary.md @@ -0,0 +1,137 @@ +# Rust Code + +If you open up `src/lib.rs` you should see a file that looks like this: + +```rust +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} +``` + +Let's quickly modify the test suite to work for what we'll be doing. It should look like this: + +```rust +#[test] +fn it_works() { + assert_eq!(add(2, 2), 4); +} +``` + +We'll use this later to make sure our `add` function works! + +Now we need to add this to the top of the file: + +```rust +#![feature(use_extern_macros, wasm_import_module, wasm_custom_section)] +extern crate wasm_bindgen; +use wasm_bindgen::prelude::*; +``` + +Let's step through this line by line. First up is the list of nightly features. We're enabling this for +the whole crate. What this means is that we will later tag code with an attribute and this will +allow Rust to generate code that we don't have to write by hand. In our case it'll use +`wasm-bindgen.` It should be noted that `#![feature(...)]` implies using the nightly +compiler. This gated feature will hopefully be stabilized and landed soon so that you won't need it! + +`wasm-bindgen` knows how to make code that works well with wasm so we don't have to +worry about it too much and just write Rust code for the most part. If you want to know the full +extent of its capabilities check out the README on its repo which can be found +[here](https://github.com/alexcrichton/wasm-bindgen). For our purposes we need to know that if we +want functions to work with wasm easily we'll need it. + +The next line says we're importing the `wasm-bindgen` crate and the line after that imports the +prelude from `wasm-bindgen`. The `extern crate` call lets the compiler know what crates to link in +and the `prelude` contains all the types and functions that `wasm-bindgen` needs to work properly! + +Cool let's import the `alert` function from JS so that we can call it in our Rust code! + +```rust +#[wasm_bindgen] +extern { + fn alert(s: &str); +} +``` + +Alright so we have our external bit of code and we have everything imported so let's write the +actual `add` function, as well as an `add_alert` function that will use `add` in itself but also +call `alert` to print out the results before returning the value. + +```rust +#[wasm_bindgen] +pub fn add(a: i32, b: i32) -> i32 { + a + b +} + +#[wasm_bindgen] +pub fn alert_add(a: i32, b: i32) -> i32 { + let c = add(a, b); + alert(&format!("Hello from Rust! {} + {} = {}", a, b, c)); + c +} +``` + +These functions are fairly straightforward if you're familiar with Rust, but if you're not we'll walk +through it. Both functions take a value `a` and a value `b`. We have said that both are 32 bit +integers (`i32`). We then say both will return an `i32`. The last line in a function returns the value +if there is no semicolon. So in the `add` function the value of `a + b` gets calculated and it's +value is returned! In the case of `alert_add` we store the value of the `add` function we just made +into the variable `c`. We then call `alert` saying what the add operation looked like and what the +value was! We then return what was inside `c`. Neat! + +This is all the Rust code we need to write. Your `lib.rs` file should look like this by now: + +```rust +#![feature(use_extern_macros, wasm_import_module, wasm_custom_section)] +extern crate wasm_bindgen; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern { + fn alert(s: &str); +} + +#[wasm_bindgen] +pub fn add(a: i32, b: i32) -> i32 { + a + b +} + +#[wasm_bindgen] +pub fn alert_add(a: i32, b: i32) -> i32 { + let c = add(a, b); + alert(&format!("Hello from Rust! {} + {} = {}", a, b, c)); + c +} + +#[test] +fn it_works() { + assert_eq!(add(2, 2), 4); +} +``` + +Just to make sure that `add` works we'll run the test we wrote earlier: + +```bash +$ cargo test +``` + +You should get output that looks sort of like this: + +```bash + Compiling wasm-add v0.1.1 (file:///home/michael/Code/wasm-add) + Finished dev [unoptimized + debuginfo] target(s) in 0.54 secs + Running target/debug/deps/wasm_add-5d5676e23e39dbea +running 1 test +test it_works ... ok +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +``` + +Yay it all works! Notice we didn't add a test for `alert_add`. This is because Rust won't know what +`alert` is unless the wasm code is running in the browser! Don't worry though. Once we package this +code up and upload it to npm we'll then test out that function to make sure everything works like we +expect it too! + +You can find all of the above code [here](https://github.com/mgattozzi/wasm-add). diff --git a/docs/src/tutorial/writing-a-rust-webassembly-library.md b/docs/src/tutorial/writing-a-rust-webassembly-library.md new file mode 100644 index 0000000..7701135 --- /dev/null +++ b/docs/src/tutorial/writing-a-rust-webassembly-library.md @@ -0,0 +1 @@ +# Writing a Rust-WebAssembly Library