#![allow(unused)]
fn main() {
//! Your task is to define the variants of the enumeration. Do not edit `main`.
#[derive(Debug)] // This makes printing the instances with {:?} (debug format) possible
enum Message {
Quit,
Echo,
Move,
ChangeColor,
}
#[test]
fn _main() {
println!("{:?}", Message::Quit);
println!("{:?}", Message::Echo);
println!("{:?}", Message::Move);
println!("{:?}", Message::ChangeColor);
}
}
#![allow(unused)]
fn main() {
//! Your task is to create the missing structs and fill in the missing parts of
//! the tests. Read the chapter about structs (whether you need help or not)
//! https://doc.rust-lang.org/book/
#[derive(Debug)]
struct ColorClassicStruct {
name: String,
hex: String,
}
#[derive(Debug)]
struct ColorTupleStruct<'a>(&'a str, &'a str);
#[derive(Debug)]
struct UnitStruct;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classic_structs() {
let green = ColorClassicStruct {
name: "green".to_string(),
hex: "#00FF00".to_string(),
};
assert_eq!(green.name, "green");
assert_eq!(green.hex, "#00FF00");
}
#[test]
fn tuple_structs() {
let green = ColorTupleStruct("green", "#00FF00");
assert_eq!(green.0, "green");
assert_eq!(green.1, "#00FF00");
}
#[test]
fn unit_structs() {
let unit_struct = UnitStruct;
let message = format!("{:?}s are fun!", unit_struct);
assert_eq!(message, "UnitStructs are fun!");
}
}
}
#![allow(unused)]
fn main() {
//! Your task is to fix the `is_quit` function. Make good use of your favorite
//! feature of Rust: `match`. Bonus points if you can do it with `matches!`.
#[derive(Debug)]
enum Message {
Quit,
Echo,
Move,
ChangeColor,
}
fn is_quit(msg: Message) -> bool {
match msg {
Message::Quit => true,
_ => false,
}
}
#[test]
fn _main() {
assert!(is_quit(Message::Quit));
assert!(!is_quit(Message::Echo));
}
}
#![allow(unused)]
fn main() {
//! Your task is to implement `to_miles` for `Kilometers` and fill in the blank
//! in `main`.
// These structs are called newtype structs. Read more about the newtype design
// pattern:
// https://rust-unofficial.github.io/patterns/patterns/behavioural/newtype.html
struct Miles(f64);
struct Kilometers(f64);
impl Miles {
fn to_kilometers(self) -> Kilometers {
Kilometers(1.6 * self.0)
}
}
impl Kilometers {
fn to_miles(self) -> Miles {
Miles(self.0 / 1.6)
}
}
fn travel(distance: Miles) -> String {
format!("Travelled {} miles", distance.0)
}
fn travel_kilometers(distance: Kilometers) -> String {
travel(distance.to_miles())
}
#[test]
fn _main() {
let msg = travel_kilometers(Kilometers(10.0));
assert_eq!(&msg, "Travelled 6.25 miles");
}
}
#![allow(unused)]
fn main() {
//! Your task is to derive required traits for `Foo`. You might find *the book*
//! helpful: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html
#[derive(Default, Debug, Clone, PartialEq)]
struct Foo {
numbers: Vec<i32>,
}
#[test]
fn _main() {
let foo = Foo::default();
dbg!(foo.clone());
assert_eq!(foo, Foo { numbers: vec![] })
}
}
#![allow(unused)]
fn main() {
//! Your task is convert `delete_filesystem` to use DryRun instead of a boolean.
//! Read more about type safety guidelines here
//! https://rust-lang.github.io/api-guidelines/type-safety.html
#[derive(Debug)]
enum DryRun {
/// Does not commit any changes
Yes,
/// Danger: everything will be lost
No,
}
fn delete_filesystem(dry_run: DryRun) -> bool {
match dry_run
{
DryRun::No => {
println!("Deleting all files...");
true
},
DryRun::Yes => {
println!("Not deleting files...");
false
}
}
}
#[test]
fn _main() {
let deleted = delete_filesystem(DryRun::No);
assert_eq!(deleted, true);
}
}
#![allow(unused)]
fn main() {
//! Your task is to implement the match
//!
//! Part 1: Write the match statement in `send_message` to "do the correct
//! stuff".
//!
//! Part 2: You may need to add more messages to the array `messages`.
/// A position in 2D space
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
/// State of the abstract high-level frobnicator
#[derive(Debug)]
struct State {
location: Point,
running: bool,
}
/// Messages sent to the [`State`] frobnicator
#[derive(Debug)]
enum Message {
/// Stops the frobnicator
Quit,
/// Moves the frobnicator
Move { x: i32, y: i32 },
}
impl State {
fn new() -> Self {
Self {
location: Point { x: 0, y: 0 },
running: true,
}
}
fn send_message(&mut self, msg: Message) {
match msg {
Message::Quit => self.running = false,
Message::Move { x, y } => {
let x = self.location.x + x;
let y = self.location.y + y;
self.location = Point { x, y }
},
}
}
}
#[test]
fn _main() {
let messages = [
Message::Move { x: 1, y: 3 },
Message::Move { x: -2, y: -1 },
Message::Quit,
];
let mut state = State::new();
for msg in messages {
state.send_message(msg);
}
assert_eq!(state.location, Point { x: -1, y: 2 });
assert!(!state.running);
}
}
#![allow(unused)]
fn main() {
//! Your task is to fill in the blanks. Don't change anything outside the `if
//! let`. Check https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html
//! around "Destructuring Structs" for the answer.
enum Message {
Quit,
Move { x: i32, y: i32 },
}
#[test]
fn _main() {
let msg = Message::Move { x: 1, y: 2 };
let mut x = 2;
let mut y = 3;
if let Message::Move { x: a, y: b } = msg {
x += a;
y += b;
}
assert_eq!(x, 3);
assert_eq!(y, 5);
}
}
#![allow(unused)]
fn main() {
//! Your task is to fill in the match in `execute`.
#[derive(Debug, PartialEq)]
enum Cli {
Run(Option<String>),
Rename(String, Option<String>),
}
impl Cli {
pub fn execute(&self) -> Option<String> {
use Cli::*; // Makes all variants visible without Cli prefix
match self {
Run(None) | Rename(_, None) => None,
Run(Some(file)) => Some(format!("running {file}").to_string()),
Rename(a, Some(b)) => Some(format!("renaming {a} to {b}").to_string()),
}
}
}
#[test]
fn _main() {
assert_eq!(
Cli::Run(Some("ferris.rs".to_string())).execute().unwrap(),
"running ferris.rs"
);
assert_eq!(
Cli::Rename("ferris.rs".to_string(), Some("corro.c".to_string()))
.execute()
.unwrap(),
"renaming ferris.rs to corro.c"
);
assert_eq!(Cli::Rename("/etc/shadow".to_string(), None).execute(), None);
assert_eq!(Cli::Run(None).execute(), None);
}
}
#![allow(unused)]
fn main() {
//! Your task is to fix the type errors and initialize the `numbers` array.
//!
//! Read more about Options in the book chapter 6.1
//! https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
// Do not change this function
fn print_number(maybe_number: Option<u16>) {
println!("maybe {:?}", maybe_number);
}
#[test]
fn _main() {
print_number(Some(13));
print_number(Some(99));
let mut numbers = [None; 5];
for iter in 0..5 {
let number_to_add: u16 = ((iter * 1235) + 2) / (4 * 16);
numbers[iter as usize] = Some(number_to_add);
}
assert_eq!(numbers, [Some(0), Some(19), Some(38), Some(57), Some(77)]);
}
}
#![allow(unused)]
fn main() {
//! Your task is to fill in all the blanks. Nothing else should need fixing.
//! Read more about iterators and their adaptors in
//! https://doc.rust-lang.org/book/ch13-02-iterators.html If too hard, try
//! harder.
/// Divides `dividend` by `divisor` safely, i.e. never divides by zero. A divide
/// by zero is represented with `None`
fn safe_div(dividend: i32, divisor: i32) -> Option<f32> {
if divisor == 0 {
None
} else {
Some(dividend as f32 / divisor as f32)
}
}
/// Returns a list of `Some`s with all integers from -5 to 4 inside
fn list_of_options() -> Vec<i32> {
(-5..5).into_iter().collect()
}
#[test]
fn _main() {
let list = list_of_options();
let pair_fractions: Vec<Option<f32>> = list
.windows(2)
.map(|iter| if iter[1] == 0 { None } else { Some(iter[0] as f32 / iter[1] as f32)} )
.collect();
use std::convert::identity; // Super helpful morphism, right?
let sum: f32 = pair_fractions.into_iter().filter_map(identity).sum();
assert_eq!(sum, 8.0);
}
}
#![allow(unused)]
fn main() {
//! Your task is to fill in the generic parameters to `Person` and fix the
//! dangling reference issue however you wish.
//!
//! Note that a `String` can never be static as it includes an allocation (the
//! crate lazy_static solves that issue, but is not needed here).
#[derive(Debug)]
struct Person<'a> {
pub name: &'a str,
pub age: i32,
}
fn make_person() -> Person<'static> {
let name = "Michael Stevens";
Person {
name: &name,
age: 36,
}
}
#[test]
fn _main() {
let michael = make_person();
assert_eq!(michael.age, 36)
}
}
//! Your task is to add missing fields to `Config` which are present in
//! `config.toml` at `exercises/week4/BX-config-parser/config.toml`. You also
//! need to add new structs to accommodate the data.
//!
//! You should start by reading what serde is about: https://serde.rs/.
#![allow(dead_code)] // In this example we don't use the parsed data
use std::{collections::HashMap, fs::read_to_string, net::Ipv4Addr, path::Path};
use serde::Deserialize;
use toml::{from_str, value::Datetime, Value};
#[derive(Debug, Deserialize)]
struct Config {
title: String,
owner: Owner,
database: Database,
servers: HashMap<String, Server>,
}
#[derive(Debug, Deserialize)]
struct Owner {
name: String,
dob: Datetime,
}
#[derive(Debug, Deserialize)]
struct Database {
enabled: bool,
ports: Vec<u16>,
/// A vector of arbitrary toml values, can be heterogeneous
data: Vec<Value>,
temp_targets: HashMap<String, f32>,
}
#[derive(Debug, Deserialize)]
struct Server {
ip: Ipv4Addr,
role: String,
}
impl Config {
pub fn parse(path: impl AsRef<Path>) -> anyhow::Result<Self> {
let path = path.as_ref();
toml::from_str(&read_to_string(path)?).map_err(anyhow::Error::from)
}
}
fn main() -> anyhow::Result<()> {
let config: Config = from_str(&read_to_string("config.toml")?)?;
println!("the parsed config is: {:#?}", config);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn name_is_tom() {
let config = Config::parse("config.toml").unwrap();
assert!(config.owner.name.starts_with("Tom"));
}
#[test]
fn open_ports() {
let config = Config::parse("config.toml").unwrap();
assert_eq!(config.database.ports.len(), 3);
}
#[test]
fn reasonable_temp_targets() {
let config = Config::parse("config.toml").unwrap();
assert!(config
.database
.temp_targets
.iter()
.all(|(_key, &target)| target < 100.0));
}
#[test]
fn server_ips_different() {
let config = Config::parse("config.toml").unwrap();
let alpha = config.servers.get("alpha").unwrap();
let beta = config.servers.get("beta").unwrap();
assert_ne!(alpha.ip, beta.ip);
}
}
#![allow(unused)]
fn main() {
//! Your task is to implement the three required methods for `Rocket<Launched>`
//! to make the tests pass. Consult the tests for guidance.
//!
//! Bonus bonus task: Add documentation comments to all Rocket's methods.
use std::marker::PhantomData;
const ESCAPE_VELOCITY: u32 = 11_186;
/// A rocket sitting on the ground with at least one cat
#[derive(Debug)]
struct Grounded;
/// A rocket flying in outer space with some velocity
#[derive(Debug)]
struct Launched;
/// A rocket crashed due to undefined behavior with no cat videos left
#[derive(Debug)]
struct Crashed;
#[derive(Debug)]
struct Rocket<Stage = Grounded> {
stage: PhantomData<Stage>,
velocity: u32,
crew: u32,
}
impl Rocket<Grounded> {
pub fn new() -> Self {
Self {
stage: PhantomData,
velocity: 0, // Not moving
crew: 1, // One captain
}
}
pub fn add_crew(&mut self, more_cats: u32) {
self.crew += more_cats;
}
pub fn launch(self) -> Rocket<Launched> {
assert_eq!(self.velocity, 0); // This is harder to make invariant using types
Rocket::<Launched> {
stage: PhantomData,
velocity: ESCAPE_VELOCITY,
crew: self.crew,
}
}
}
impl Rocket<Launched> {
pub fn accelerate(&mut self, v: u32) {
self.velocity += v;
}
pub fn decelerate(&mut self, v: u32) {
self.velocity -= v;
}
pub fn try_land(self) -> Result<Rocket::<Grounded>, Rocket::<Crashed>> {
if self.velocity == 0 {
Ok(Rocket::<Grounded>
{
stage: PhantomData,
velocity: self.velocity,
crew: self.crew,
})
} else {
Err(Rocket::<Crashed> {
stage: PhantomData,
velocity: self.velocity,
crew: 0,
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn grounded_rocket() {
let mut rocket = Rocket::new();
rocket.add_crew(5);
assert!(matches!(
rocket,
Rocket::<Grounded> {
crew: 6,
velocity: 0,
..
}
))
}
/// Rocket<Launched> should be able to change its velocity with `accelerate`
#[test]
fn launched_rocket() {
let mut rocket = Rocket::new();
rocket.add_crew(5);
let mut rocket = rocket.launch();
rocket.accelerate(100);
assert!(matches!(
rocket,
Rocket::<Launched> {
crew: 6,
velocity: 11_286,
..
}
))
}
/// Rocket<Launched> should be able to `try_land`, which will be successful
/// if its velocity is zero, otherwise it will crash with no cat videos left
#[test]
fn houston_we_have_had_a_problem() {
let mut rocket = Rocket::new();
let rocket = rocket.launch();
let crashed: Result<Rocket, Rocket<Crashed>> = rocket.try_land();
assert_eq!(crashed.unwrap_err().crew, 0)
}
/// Rocket<Launched> should be able to change its velocity with `decelerate`
#[test]
fn landing_successful() {
let mut rocket = Rocket::new();
rocket.add_crew(5);
let mut rocket = rocket.launch();
rocket.decelerate(11_186);
let landed = rocket.try_land();
assert!(matches!(
landed,
Ok(Rocket::<Grounded> {
crew: 6,
velocity: 0,
..
})
))
}
}
}
fn _main() {
let url = "https://fablab.rip";
println!("Fetching {:?}...", url);
let res = reqwest::blocking::get(url).unwrap();
println!("Response: {:?}", res.text().unwrap());
}
#![allow(unused)]
fn main() {
//! Your task is to fix the returned closure from `is_garbage`.
fn is_garbage() -> impl Fn(&str) -> bool {
let no_garbage = vec!["C", "C++", "Rust"];
move |lang: &str| -> bool { !no_garbage.contains(&lang) }
}
#[test]
fn _main() {
let is_garbage = is_garbage();
assert!(is_garbage("Java"));
assert!(is_garbage("Python"));
assert!(is_garbage("TypeScript"));
}
}
#![allow(unused)]
fn main() {
//! Your task is to implement `evaluate` for `Map`, and define the `square`
//! closure.
struct Map<F>
where
F: Fn(i32) -> i32,
{
data: Vec<i32>,
mapper: F,
}
impl<F> Map<F>
where
F: Fn(i32) -> i32,
{
fn new(data: Vec<i32>, mapper: F) -> Self {
Self { data, mapper }
}
/// Maps each element in `data` using `mapper` in-place
fn evaluate(&mut self) {
for num in self.data.iter_mut() {
*num = (self.mapper)(*num);
}
}
fn into_vec(self) -> Vec<i32> {
self.data
}
}
#[test]
fn _main() {
let square = |x| x * x;
let mut map = Map::new(vec![1, 2, 3, 4], square);
map.evaluate();
map.evaluate();
assert_eq!(map.into_vec(), [1, 16, 81, 256]);
}
}