But how do I make a website?
If you've never heard of Rust…
I'll tell you what Rust is
How I got to know Rust
And some problems that the language helped me to solve
But if you've already heard of it…
I'll show you some steps to keep learning
I started to get involved with the deployment of some projects.
NPM + Python + Java + Closure Compiler + SCons + RVM…
I wanted a simple way to execute applications
1 single-file cross-platform binary
"Do I have to code in C to produce binaries?"
Rust was one of the options in my search for alternatives.
"But what is Rust?"
Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.
TL;DR;
It's a very modern language
with low-level focus
A language with several
functional-paradigm features:
What kept me interested on the language:
All of these traits create an ideal environment to proceed with confidence
How many bugs may happen in a low-level program?
Rust has a type system that prevents several kinds of memory management errors at compile-time
Memory management without a
garbage collector
Let's see a little Rust
fn main() { let data = vec!(); println!("Data", data); }
error: argument never used --> src/main.rs:3:22 | 3 | println!("Data", data); | ^^^^ error: aborting due to previous error
fn main() { let data = vec!(); println!("Data {}", data); }
error[E0277]: the trait bound `std::vec::Vec<_>: std::fmt::Display` is not satisfied --> src/main.rs:3:25 | |println!("Data {}", data); | ^^^^ `std::vec::Vec<_>` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string | = help: the trait `std::fmt::Display` is not implemented for `std::vec::Vec<_>` = note: required by `std::fmt::Display::fmt` error: aborting due to previous error
^^^^ `std::vec::Vec<_>` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
fn main() { let data = vec!(); println!("Data {:?}", data); }
error[E0282]: type annotations needed --> src/main.rs:2:16 | 2 | let data = vec!(); | ---- ^^^^^^ cannot infer type for `T` | | | consider giving `data` a type | error: aborting due to previous error
error[E0282]: type annotations needed
$ rustc --explain E0282
fn main() { let data : Vec<char> = vec!(); println!("Data {:?}", data); }
Data []
In short, imagine how complex a browser is under the hood.
Are there any problems in this code?
use std::thread; use std::time::Duration; fn main() { let data = vec!(); thread::spawn(|| { data.push('a'); }); thread::spawn(|| { data.push('b'); }); thread::sleep(Duration::from_millis(50)); println!("Data {:?}", data); }
After several compilation feedback cycles:
Our binary won't have these problems!
use std::thread; use std::sync::{Arc, Mutex}; use std::time::Duration; fn main() { let data = Arc::new(Mutex::new(vec!())); let writer = data.clone(); thread::spawn(move || { let lock_result = writer.lock(); match lock_result { Ok(mut locked_writer) => locked_writer.push('a'), Err(_) => panic!("Could not acquire lock a"), } }); let writer = data.clone(); thread::spawn(move || { let mut locked_writer = writer.lock().expect("Could not acquire lock b"); locked_writer.push('b'); }); thread::sleep(Duration::from_millis(50)); println!("Data {:?}", data); }
Which we can't express in other popular languages
#[derive(Debug)] struct Order { id: i32 } fn new_order() -> Order { Order { id: 1 } } fn send_order(order: Order) { // Code to send a order } fn main() { let order = new_order(); send_order(order); println!("Order data: {:?}", order); }
error[E0382]: use of moved value: `order` --> src/main.rs:18:39 | 16 | send_order(order); | ------- value moved here 17 | 18 | println!("Order data: {:?}", order); | ^^^^^ value used here after move
We can only access the order data before we send it in this scenario.
And this is enforced by the compiler.
#[derive(Debug)] struct Order { id: i32 } fn new_order() -> Order { Order { id: 1 } } fn send_order(order: Order) { // Code to send a order } fn main() { let order = new_order(); println!("Order data: {:?}", order); send_order(order); }
Order data: Order { id: 1 }
Types can't verify all logic
pub fn super_calculation(x: i32, y: i32) -> i32 { x + y } #[test] fn test_super_calculation() { assert_eq!(3, super_calculation(1, 2)); }
$ cargo test running 1 test test test_super_calculation ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Trying to avoid out-of-date examples
/// Runs a grand calculation that will leave you surprised /// # Examples /// /// ``` /// use my_lib::*; /// /// assert_eq!(5, surprise_calculation(1, 2)); /// ``` pub fn surprise_calculation(x: i32, y: i32, z: i32) -> i32 { x + y + z }
Examples in documentation are executed
during testing
$ cargo test [...] running 1 test test src/lib.rs - surprise_calculation (line 4) ... FAILED failures: ---- src/lib.rs - surprise_calculation (line 4) stdout ---- error[E0061]: this function takes 3 parameters but 2 parameters were supplied --> src/lib.rs:5:32 | 5 | assert_eq!(5, surprise_calculation(1, 2)); | ^^^^ | expected 3 parameters
Generating project documentation is simple
$ cargo doc --open
It's a great evolution for the whole low-level ecosystem
And a great option to
build high-level platforms
These were examples of the
potential of the language
You can learn bit by bit, at your own speed
And start with what you're already familiar with in other languages
Ah, and this is the mascot, Ferris
(And you can sew your own)
Now, how do I make a website?
Follow the instructions on Rustup's website
This is the version manager for Rust
Which helps to install the needed dependencies and tooling
When we're done, we'll have:
$ cargo new --bin my-site-in-rust
$ cargo run Compiling my-site-in-rust v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 1.54 secs Running `target/debug/my-site-in-rust` Hello, world!
Let's create a file at src/index.html
with the following content
<!doctype html> <html> <head> <meta charset=utf-8> <title>Hello World</title> </head> <body> <h1>Hello, world</h1> <marquee>Hello everyone!</marquee> </body> </html>
Let's use the Nickel framework to help us
Add the dependency in the Cargo.toml
file
[dependencies] nickel = "0.10.0"
Now let's see a little of Rust, bit by bit.
Let's open the src/main.rs
file.
First, we import and include some references to the web framework.
#[macro_use] extern crate nickel; use nickel::{Nickel, HttpRouter};
We include all of our HTML file content in a constant.
const INDEX: &str = include_str!("index.html");
We create a new Nickel server.
let mut server = Nickel::new(); server.get("/", middleware!(INDEX));
We configure the port with the PORT
environment variable.
Let's use port 3000 for fallback.
let port = std::env::var("PORT").unwrap_or("3000".into()); let url = format!("0.0.0.0:{port}", port = port);
We start our server, with a message in case there are errors.
println!("On {}", url); server.listen(url) .expect("Unable to start the server");
In the end we'll have this:
#[macro_use] extern crate nickel; use nickel::{Nickel, HttpRouter}; const INDEX: &str = include_str!("index.html"); fn main() { let mut server = Nickel::new(); server.get("/", middleware!(INDEX)); let port = std::env::var("PORT").unwrap_or("3000".into()); let url = format!("0.0.0.0:{port}", port = port); println!("On {}", url); server.listen(url) .expect("Unable to start the server"); }
$ cargo build --release
And execute it:
$ ./target/release/my-site-in-rust
On 0.0.0.0:3000
Listening on http://0.0.0.0:3000
Ctrl-C to shutdown server
You have a site in Rust.
And it's all in just one single-file binary!
And there's a demo on Heroku!
It's as easy as in other languages,
even though it's a systems language
I'm going to follow a recipe available
on the Rust Cookbook
$ cargo new --bin my-web-request-in-rust
$ cargo run Compiling my-web-request-in-rust v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 1.54 secs Running `target/debug/my-web-request-in-rust` Hello, world!
There are already several libraries available
> on Crates.io
Let's use Reqwest for this project
Add a dependency in the Cargo.toml
file
[dependencies] reqwest = "0.8.0"
Let's import our library and some I/O functions
extern crate reqwest; use std::io::Read;
And create our function
fn main() { let mut response = reqwest::get("https://httpbin.org/get") .expect("Could not connect"); println!("Response: {:?}", response); let mut content = String::new(); response.read_to_string(&mut content); println!("Site content: {}", content); }
Let's execute!
$ cargo run
Now you have code to make web requests!
Does it look far too diferent from
other languages?
I spent weeks banging my head against some concepts that were new to me.
lifetimes
and borrowing
took a while to get into my headRust brought new concepts to my toolbox.
And I've been having a lot of fun!
The community is very open and
helped me a lot, and has a lot of interest in
welcoming new people.
Many people are willing to help on #rust-beginners, on #rust, and on the forum.
There's a big push to make an inclusive ecosystem, as much for community participation as for learning material for all programing levels.
An initiative to teach Rust to those that aren't well-represented in the area of technology
With interest in turning the language into a good first programming language
All proposals for changes in the language follow an RFC process
Which requires new change proposals to have documentation and a clear way to
teach the proposed change
I used this buildpack.
There are several frameworks, but it's an ecosystem in development.
A good list can be found at Are We Web Yet?
Have a look at Rocket, which uses a more succinct syntax…
But it depends on compiler functionalities that are still in development.
It's the most recommended method by the community
Rust is also available through distro package managers, but it can take a while for updates to come.
Diesel can help with this.
Yes. Your Firefox installation already has components written in Rust.
Some companies: Dropbox, Chef, Tilde, Sentry, CoreOS, Mozilla and there are more on the website list.
No, you can use it for many other things!
(If I tried to list all the examples, this would be another presentation entirely)
Two strong* spaces to apply the language:
Language extensions (Gems, npm, python extensions, FFI)
*IMHOMachine Learning, Ruby, Python, Haskell, Node.js, WebAssembly, Container, Network Platform, Embedded, Operating Systems123, Games, cross-compilation, CI…
If you got interested in Rust, you may get in touch with me as well, I want to help you with your next steps into the ecosystem.
Bruno Tavares - @bltavares
Thank you for translating the original presentation from Portuguese to English