Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What can Rust do for my Node.js

rvidal
September 27, 2018

What can Rust do for my Node.js

An introduction to Rust catered to Node.js programmers, with a tasting menu of different avenues into the language.

rvidal

September 27, 2018
Tweet

More Decks by rvidal

Other Decks in Programming

Transcript

  1. Rust is... 1. Typed fn my_middleware(req: Request) -> Response; 2.

    Compiled, and... $ rustc hello_world.rs && ./hello_world Hello, world! 3. ... compiled natively $ rustc hello_world.rs --target=aarch64-apple-ios && ./hello_world # good luck
  2. const http = require("http"); const hostname = "127.0.0.1"; const port

    = 8000; const server = http.createServer((req, res) => { res.statusCode = 200; res.end("Hello World\n"); }); server.listen(port, hostname, () => { console.log( `Listening at http://${hostname}:${port}/` ); }); Node.js — Getting Started
  3. extern crate tiny_http; use tiny_http::{Server, Response}; fn main() { let

    addr = "127.0.0.1:8000"; let server = Server::http(&addr) .unwrap(); println!("Listening at {}", addr); for request in server.incoming_requests() { let response = Response::from_string("Hello World\n"); request.respond(response); } }
  4. We want it all Memory safety without Garbage collection Abstraction

    without Overhead Stability without Stagnation Hack without Fear
  5. Memory safety without Garbage collection and Speed fn main() {

    let some_number : &u32 = get_me_a_number(); println!("The number is {}", some_number); } fn get_me_a_number() -> &u32 { let numbers = vec![1, 2, 3]; &numbers[2] }
  6. Memory safety without Garbage collection and Speed fn main() {

    let some_number : &u32 = get_me_a_number(); println!("The number is {}", some_number); } fn get_me_a_number() -> &u32 { let numbers = vec![1, 2, 3]; // ⚠ ERROR &numbers[2] //^^^^^^^ borrowed value // does not live long enough }
  7. Server::new(|req| { let user_id = req.params.user_id; user_collection .find(|u| u.id ==

    user_id) .map(|u| Response::from(u)) .or_else(|| Response::not_found()) }) .listen(&addr); Abstraction without Overhead and Speed
  8. Stability without Stagnation $ cargo new nodejsmad Created binary (application)

    `nodejsmad` project $ cd nodejsmad $ cargo add num_cpus Adding num_cpus v1.8.0 to dependencies $ cargo run Updating registry `https://github.com/rust-lang/crates.io-index` Compiling libc v0.2.43 Compiling num_cpus v1.8.0 Compiling nodejsmad v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 8.54s Running `target/debug/nodejsmad` Hello, world!
  9. Native Extensions [...] the method for implementing Addons is rather

    complicated, involving knowledge of several components [...] Node.js docs/api/addons.html
  10. Native Extensions [...] the method for implementing Addons is rather

    complicated, involving knowledge of several components [...] Node.js docs/api/addons.html npm install -g neon-cli
  11. Getting started with Neon #[macro_use] extern crate neon; use neon::prelude::*;

    fn hello(mut cx: FunctionContext) -> JsResult<JsString> { Ok(cx.string("hello node")) } register_module!(mut cx, { cx.export_function("hello", hello) }); ~ ~ ~ ~ ~ ~ ~ ~ ~ "native/src/lib.rs" 12L, 219C 00:00
  12. Advanced: native BigInts Watch for: num = "0.2" is all

    the required "business logic". JS classes are defined through macros: declare_types!( class JsBigInt for BigInt { init(cx) { /* ... */ } method toIntString(cx) { /* ... */ } } ) See: BigInts with Neon and num
  13. const binary = fs.readFileSync("./program.wasm"); const { instance } = await

    WebAssembly.instantiate(binary); instance.exports.expensiveComputation(); (module (export "expensiveComputation" (func $f)) (func $f (result i32) i32.const 1)) WebAssembly
  14. Getting started with wasm-pack extern crate cfg_if; extern crate wasm_bindgen;

    mod utils; use wasm_bindgen::prelude::*; #[wasm_bindgen] extern { #[wasm_bindgen(js_namespace=console)] fn log(s: &str); } #[wasm_bindgen] pub fn greet() { log("Hello, madridwasm!"); } ~ ~ ~ ~ 00:00
  15. Advanced: Exif metadata parser Watch for: Again, business logic contained

    in kamadak-exif = "0.3" More complex types crossing the Rust/Wasm-JS boundary: #[wasm_bindgen] pub fn get_exif(source: &[u8]) -> Vec<JsValue> Throwing from Rust/Wasm to JS: wasm_bindgen::throw_str(&format!("{:?}", error)) > pkg.get_exif([]) Error: InvalidFormat("Broken JPEG file") See: Exif parsing with Rust + Wasm
  16. Mode.js (ModeJsMadrid) /source % cargo run Compiling modejs v0.1.0 (file:///source)

    Finished dev [unoptimized + debuginfo] target(s) in 3.26s Running `target/debug/modejs` > 1 1 > var x = {foo: 2} undefined > x 00:00
  17. Everybody ends up in (callback) hell let ping_4ever = loop_fn(Client::new(),

    |client| { client.send_ping() .and_then(|client| client.receive_pong()) .and_then(|(client, done)| { if done { Ok(Loop::Break(client)) } else { Ok(Loop::Continue(client)) } }) });
  18. #[async] fn fetch( client: Client ) -> IoResult<String> { let

    response = await!(client.get(URL))?; if !response.status().is_success() { return Err( IoError::new(IoErrorKind::Other, FAIL_MSG) ); } let body = await!(response.body().concat())?; let string = String::from_utf8(body)?; Ok(string) }
  19. Where to go from here? https://www.rust-lang.org/documentation.html "The Book" Rust by

    Example https://www.meetup.com/MadRust/ Reddit, users forum WebAssembly: Rust and WebAssembly WG (check the !) wasm-pack (check the !) wasm-bindgen (check the !) Native addons, Neon: neon-bindings Web development, async I/O Are we web yet? Network Services WG We love "newbies"