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

What can Rust do for my Node.js

Avatar for rvidal 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.

Avatar for rvidal

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"