Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

$ cat ~/.profile GIT_AUTHOR_NAME=Florian Gilcher GIT_AUTHOR_EMAIL=florian@asquera.de TWITTER_HANDLE=argorak GITHUB_HANDLE=skade BLOG=skade.me YAKS=yakshav.es

Slide 3

Slide 3 text

• Rust and Elasticsearch Trainer • Event organiser • Ruby Programmer since 2003 • Rust Programmer since 2013 • CEO asquera GmbH

Slide 4

Slide 4 text

• Community person • Rust/Search Meetups • eurucamp/jrubyconf.eu • RustFest • https://isleofruby.org/

Slide 5

Slide 5 text

Part of the global Rust community team

Slide 6

Slide 6 text

As a hobby, I shoot arrows at stuff

Slide 7

Slide 7 text

Rust as a CLI language

Slide 8

Slide 8 text

What is Rust?

Slide 9

Slide 9 text

• new systems programming language • powers and was developed in along with Servo, a new browser engine • by Mozilla and the Community • First stable release May 15th, 2015

Slide 10

Slide 10 text

https://www.rust-lang.org/friends.html

Slide 11

Slide 11 text

Providing an alternative to C/C++, but also higher-level languages.

Slide 12

Slide 12 text

• Safe • Concurrent • Fast

Slide 13

Slide 13 text

It’s generally perceived that safety, especially memory-safety comes at a runtime cost.

Slide 14

Slide 14 text

• Safe • Concurrent • Fast

Slide 15

Slide 15 text

Pick Three

Slide 16

Slide 16 text

Core features

Slide 17

Slide 17 text

• Static type system with local type inference • Explicit mutability • Zero-cost abstractions • Runtime-independent concurrency safety

Slide 18

Slide 18 text

• Errors are values • No null • Static automatic memory manage- ment • No garbage collection

Slide 19

Slide 19 text

A short introduction

Slide 20

Slide 20 text

extern crate tempdir; use tempdir::*; use std::fs::File; fn main() { let tempdir = TempDir::new("goto-berlin"); let mut tempfile = match tempdir { Ok(dir) => { File::create( dir.path().join("tmpfile") ) } Err(_) => { panic!("Couldn’t open tempdir") } } do_something(&mut tempfile); // look, no close necessary! }

Slide 21

Slide 21 text

Base concept: Mutability

Slide 22

Slide 22 text

struct InnerData { val: i32 } struct Data { inner: InnerData } fn main() { let d = Data { inner: InnerData { val: 41 }}; d.inner.val = 42; // error: cannot assign to immutable field `d.inner.val` }

Slide 23

Slide 23 text

struct InnerData { val: i32 } struct Data { inner: InnerData } fn main() { let mut d = Data { inner: InnerData { val: 41 }}; d.inner.val = 42; }

Slide 24

Slide 24 text

Base concept: Ownership & Borrowing

Slide 25

Slide 25 text

• Every piece of data is uniquely owned • Ownership can be passed • When owned data reaches the end of a scope, it is destructed

Slide 26

Slide 26 text

use std::fs::File; use std::io::Write; fn main() { let file = File::open("test") .expect("Unable to open file, bailing!"); take_and_write_to_file(file); // take_and_write_to_file(file); // ^^ Illegal } fn take_and_write_to_file(mut file: File) { writeln!(file, "{}", "Hello #gotober!"); }

Slide 27

Slide 27 text

• Access can be borrowed (mutable and immutable) • You can borrow mutably once • Or multiple times immutably • Exclusive: mutable or immutable, never both

Slide 28

Slide 28 text

Shared mutable state is an issue even single-threaded applications!

Slide 29

Slide 29 text

use std::fs::File; use std::io::Write; fn main() { let mut file = File::open("test") .expect("Unable to open file, bailing!"); write_to_file(&mut file); write_to_file(&mut file); } fn write_to_file(file: &mut File) { writeln!(file, "{}", "Hello #gotober!"); }

Slide 30

Slide 30 text

fn main() { let mut vector = vec![1,2,3]; let elem = &vector[1]; vector[2] = 4; }

Slide 31

Slide 31 text

error[E0502]: cannot borrow `vector` as mutable –> src/main.rs:4:5 | 3 | let elem = &vector[1]; | —— immutable borrow occurs h 4 | vector[2] = 4; | ^^^^^^ mutable borrow occurs here 5 | } | - immutable borrow ends here

Slide 32

Slide 32 text

Rust checks validity of all references at compile-time.

Slide 33

Slide 33 text

struct Data<’a> { inner: &’a i32 } fn return_reference<’a>() -> Data<’a> { let number = 4; Data { inner: &number } }

Slide 34

Slide 34 text

–> src/main.rs:8:20 | 8 | Data { inner: &number } | ^^^^^^ does not live long 9 | } | - borrowed value only lives until here |

Slide 35

Slide 35 text

All Rust function signatures not only signal data types, but also mutability, ownership and interconnections between input and output types.

Slide 36

Slide 36 text

100, 1000, 10.000 lines of called code, Rust keeps these properties!

Slide 37

Slide 37 text

Abstractions Rust provides higher-level abstractions through Generics and Traits, similar to C++ Templates or Java Generics.

Slide 38

Slide 38 text

Low-level control & safety!

Slide 39

Slide 39 text

• Borrows boil down to pointers at runtime • Values are plain values just like in e.g. C • Optional unsafe sub-language

Slide 40

Slide 40 text

“ Safe code means you can take better risks.” – @QEDunham

Slide 41

Slide 41 text

"I stopped writing Python or Ruby, I write my small tools in Rust now."

Slide 42

Slide 42 text

rustup http://rustup.rs or your package manager

Slide 43

Slide 43 text

rustup rustup allows full management of a Rust development toolchain, including cross-compilation.

Slide 44

Slide 44 text

rustup In general, it is recommendable to target a rustc that is shipped with your target system.

Slide 45

Slide 45 text

rustup $ rustup install stable

Slide 46

Slide 46 text

Minimum version The minimum version for the following example is Rust 1.15.

Slide 47

Slide 47 text

Writing a small CLI program

Slide 48

Slide 48 text

We’re currently collecting community blogposts and I lost count. Luckily, a kind soul offers a JSON feed on readrust.net.

Slide 49

Slide 49 text

{ "version": "https://jsonfeed.org/version/1", "title": "#Rust2018", "home_page_url": "http://readrust.net/", "feed_url": "http://readrust.net/rust2018/feed "description": "Posts from the Rust 2018 initi "author": { "name": "Wesley Moore", "url": "http://www.wezm.net/" }, "items": [ {

Slide 50

Slide 50 text

Errors enum Result { Ok(T), Err(E) }

Slide 51

Slide 51 text

Quick error handling in CLI let file = File::open("foo").unwrap(); // This will quit if the File cannot be opened

Slide 52

Slide 52 text

Strings Rust has 2 types of strings: &str and String. The first is harder to use then the second. They are compatible.

Slide 53

Slide 53 text

Quickly handling Strings At the beginning, whenever you encounter &str and are confused, use this: let heap_allocated_string = "normal_string".to_string();

Slide 54

Slide 54 text

Task A proper CLI tool that gets the feed, parses it, prints it in a nice, readable fashion.

Slide 55

Slide 55 text

readrust 0.1 Florian G. Reads readrust.net USAGE: readrust [FLAGS] [OPTIONS] FLAGS: -c, –count Show the count of posts -h, –help Prints help information -V, –version Prints version information OPTIONS: -n, –number Only print the NUMBE

Slide 56

Slide 56 text

We need: • Argument parser • HTTP client • JSON parser • A pretty-printer

Slide 57

Slide 57 text

cargo $ cargo init readrust-cli $ cargo build [–release]

Slide 58

Slide 58 text

Feel free to clone https://github.com/skade/readrust-cli

Slide 59

Slide 59 text

cargo manifest [package] name = "readrust" version = "0.1.0" authors = ["Florian Gilcher

Slide 60

Slide 60 text

CLAP Command Line Argument Parser https://clap.rs

Slide 61

Slide 61 text

• Flexible argument parser • Automatic USAGE generation • Well documented

Slide 62

Slide 62 text

extern crate clap; use clap::App; fn main() { let app = App::new("readrust") .version("0.1") .author("Florian G. ") .about("Reads readrust.net") .args_from_usage("-n, –number=[NUMBER] ’Only print the NUMBER most recent posts’ -c, –count ’Show the count of posts’"); let matches = app.get_matches(); }

Slide 63

Slide 63 text

$ cargo run – –help readrust 0.1 Florian G. Reads readrust.net USAGE: readrust [FLAGS] [OPTIONS] FLAGS: -c, –count Show the count of posts -h, –help Prints help information -V, –version Prints version information OPTIONS: -n, –number Only print the NUMBER most recent posts

Slide 64

Slide 64 text

Well, that was quick.

Slide 65

Slide 65 text

HTTP reqwest, the high-level http client

Slide 66

Slide 66 text

• Easy to use • synchronous and asynchrous modes • Documented

Slide 67

Slide 67 text

fn get_feed() -> String { //? }

Slide 68

Slide 68 text

extern crate reqwest; pub static URL: &’static str = "http://readrust.net/rust2018/fee fn get_feed() -> String { let client = reqwest::Client::new(); let request = client.get(URL); let mut resp = request.send().unwrap(); assert!(resp.status().is_success()); resp.text().unwrap() }

Slide 69

Slide 69 text

JSON parsing: SERDE

Slide 70

Slide 70 text

SERDE: Serialization, Deserialization

Slide 71

Slide 71 text

• Generic framework • Generic and strict parse modes • JSON parser one of the fastest around • good documentation

Slide 72

Slide 72 text

fn get_feed -> Feed { //? }

Slide 73

Slide 73 text

#[derive(Debug, Deserialize, Serialize)] pub struct Author { name: String, url: String, }

Slide 74

Slide 74 text

#[derive(Debug, Deserialize, Serialize)] pub struct Item { id: String, title: String, content_text: String, url: String, date_published: String, author: Author, }

Slide 75

Slide 75 text

#[derive(Debug, Deserialize, Serialize)] struct Feed { version: String, title: String, home_page_url: String, feed_url: String, description: String, author: Author, items: Vec, }

Slide 76

Slide 76 text

fn get_feed() -> Feed { let client = reqwest::Client::new(); let mut request = client.get(URL); let mut resp = request.send().unwrap(); assert!(resp.status().is_success()); let data = resp.text().unwrap(); serde_json::from_str::(&data).unwrap() }

Slide 77

Slide 77 text

Simply printing fn print_count(feed: &Feed) { println!("Number of posts: {}", feed.items.len()); }

Slide 78

Slide 78 text

Using that let feed = get_feed(); if matches.is_present("count") { print_count(&feed); }

Slide 79

Slide 79 text

Showing blog posts Let’s use prettytable-rs. It prints out data easily as a table.

Slide 80

Slide 80 text

prettytable-rs • Easy to use • Supports subtables and colours • Documented

Slide 81

Slide 81 text

fn fn print_feed_table>(items: I) { let mut table = prettytable::Table::new(); table.add_row(row!["Title", "Author", "Link"]); for item in items { let title = if item.title.len() >= 50 { &item.title[0..50] } else { &item.title }; table.add_row(row![title, item.author.name, item.url]); } table.printstd(); }

Slide 82

Slide 82 text

Using it if matches.is_present("count") { print_count(&feed); } else { let iter = feed.items.into_iter(); if let Some(string) = matches.value_of("number") { let number = string.parse().unwrap(); print_feed_table(iter.take(number)) } else { print_feed_table(iter) } }

Slide 83

Slide 83 text

We’re done

Slide 84

Slide 84 text

• A 79-line program • With full build and dependency tooling • No typing ceremony except the Feed definition

Slide 85

Slide 85 text

Advantages

Slide 86

Slide 86 text

• Easily shippable as a binary • Full error handling (even if we just bail!) • Fully documented dependencies

Slide 87

Slide 87 text

When and why to pick up Rust • You want to learn something new • You want that extra bit of perfor- mance • You want the control of C, but the safety of Python • You want to parallelise things

Slide 88

Slide 88 text

Learning experience Rust takes around three weeks to click in full.

Slide 89

Slide 89 text

Continuing • Do proper error passing and central handling • Add logging (using... log!) • Filter the items • Make statistics over the items

Slide 90

Slide 90 text

Rust is a surprisingly productive language with great compiler diagnostics that scales from lowlevel to "just quick" programs.

Slide 91

Slide 91 text

https://rust-lang.org https://www.meetup.com/Rust- London-User-Group/ https://www.meetup.com/Cambridge- Rust-Meetup/

Slide 92

Slide 92 text

https://this-week-in-rust.org

Slide 93

Slide 93 text

Have a question? community-team@rust-lang.org

Slide 94

Slide 94 text

No content

Slide 95

Slide 95 text

Concurrency without fear

Slide 96

Slide 96 text

let counter = Counter { count: 0 }; for _ in 1..3 { std::thread::spawn(move || { increment(&mut counter); // capture of moved value: `counter` }); }

Slide 97

Slide 97 text

use std::rc::Rc; let rc = Rc::new(Counter { count: 0 }); for _ in 1..3 { let handle = rc.clone(); std::thread::spawn(move || { // `std::rc::Rc` cannot be sent between threads safely increment(&mut handle); }); }

Slide 98

Slide 98 text

use std::sync::{Arc,Mutex}; let rc = Arc::new(Mutex::new(Counter { count: 0 })); for _ in 1..3 { let handle = rc.clone(); std::thread::spawn(move || { increment(&mut handle); }); }

Slide 99

Slide 99 text

This example could be a concurrency bug in many languages, or even a double-free!

Slide 100

Slide 100 text

This analysis is purely static and independent of concurrency primitive! Rusts type system allows no data races.