# 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() {
}
```