# Safe and Concurrent Programming in Rust This Page: https://hackmd.io/@gandro/Sku8wRq5L Material: https://gandro.github.io/rust-academy-2020-05-15/ ## Current Exercise - Until 16:05 ⚙️ [**Source Code**](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=27b476a6ace845132671378b9e601669) 1. Avoid panics in `parse` and have it return `Result<Point, ParseError>` instead. 2. Extend `ParseError` with an `IoError` variant and change the return type of `parse_from_reader` to return a `Result<Vec<Point>, ParseError>`. 3. Bonus: Implement `std::error::Error` for ParseError. To test it, you can change the signature of `main` to return a `Result<(), Box<dyn Error>>` and propagate the result of `parse_from_reader`. ### Questions / Comments *Please write down any questions or comments here.* ### Tentative Schedule - Start: 9:00 - Lunch: 12:00 - 13:00 - End: 17:00 Breaks: Every 30-45min. Between chapters and exercises. ### Useful Links Rust Standard Lib: https://doc.rust-lang.org/std/ Rust Ecosystem: https://docs.rs Installation: https://www.rust-lang.org/tools/install ## Lösung Methods II ```rust #![allow(dead_code)] #[derive(Debug)] struct Book { title: String, price: f64, } #[derive(Debug)] struct Bookstore { available: Vec<Book>, } impl Bookstore { fn new() -> Bookstore { Bookstore { available: Vec::new(), } } fn add_book(&mut self, b: Book) { self.available.push(b); } fn price(&self, title: &str) -> Option<f64> { for book in &self.available { if book.title == title { return Some(book.price); } } None } // Exercise 1: Implement `total_price`. It should return the sum of the // the price of all requested books. // If any of the books are not found, it should return None. fn total_price(&self, wishlist: &[&str]) -> Option<f64> { let mut total_price = 0.0; for title in wishlist { match self.price(title) { Some(price_of_book) => total_price += price_of_book, None => return None, } } Some(total_price) } // Exercise 2: Implement `buy_book`. It should return the book // If there is no book with the title, it should return None. // Hint: Vec::remove or Vec::swap_remove fn buy_book(&mut self, title: &str) -> Option<Book> { let mut pos: Option<usize> = None; for (i, b) in self.available.iter().enumerate() { if b.title == title { pos = Some(i); break; } } match pos { Some(p) => Some(self.available.swap_remove(p)), None => None, } } // Bonus Exercise: Implement `buy_cheap_books`. It should return a vector // of all books whose price is less or equal than `max_price`. // The book should be moved out of the bookstore if it is bought. fn buy_cheap_books(&mut self, _max_price: f64) -> Vec<Book> { Vec::new() } } fn make_store() -> Bookstore { let mut store = Bookstore::new(); store.add_book(Book { title: format!("Adventures of Huckleberry Finn"), price: 10.0, }); store.add_book(Book { title: format!("Pride and Prejudice"), price: 8.50, }); store.add_book(Book { title: format!("The Adventures of Sherlock Holmes"), price: 6.50, }); store.add_book(Book { title: format!("Les Misérables"), price: 9.60, }); store } #[test] fn test_exercise1() { let store = make_store(); assert_eq!(store.total_price(&[]), Some(0.0)); assert_eq!( store.total_price(&["The Adventures of Sherlock Holmes"]), Some(6.5) ); assert_eq!( store.total_price(&["Les Misérables", "Pride and Prejudice"]), Some(18.10) ); assert_eq!( store.total_price(&["Les Misérables", "Lord of the Rings"]), None ); } #[test] fn test_exercise2() { let mut store = make_store(); let holmes = "The Adventures of Sherlock Holmes"; match store.buy_book(holmes) { Some(b) => { // check that it is the correct book assert_eq!(b.title, holmes); // check that we cannot buy it twice assert!(store.buy_book(holmes).is_none()); } None => panic!("Could not buy {:?}", holmes), } } fn main() { } ```