H6XH45OPVRRAAP2N4AK3DCHVVSMVQ6B3MQZYKU7YVCN4O2IJGQUQC
use assert_cmd::prelude::*;
use glob::glob;
use predicates::boolean::PredicateBooleanExt;
use std::fs::File;
use std::io::Read;
use std::process::Command;
#[test]
fn runs_without_arguments() {
let mut cmd = Command::cargo_bin("rustlings").unwrap();
cmd.assert().success();
}
#[test]
fn fails_when_in_wrong_dir() {
Command::cargo_bin("rustlings")
.unwrap()
.current_dir("tests/")
.assert()
.code(1);
}
#[test]
fn verify_all_success() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("verify")
.current_dir("tests/fixture/success")
.assert()
.success();
}
#[test]
fn verify_fails_if_some_fails() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("verify")
.current_dir("tests/fixture/failure")
.assert()
.code(1);
}
#[test]
fn run_single_compile_success() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "compSuccess"])
.current_dir("tests/fixture/success/")
.assert()
.success();
}
#[test]
fn run_single_compile_failure() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "compFailure"])
.current_dir("tests/fixture/failure/")
.assert()
.code(1);
}
#[test]
fn run_single_test_success() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "testSuccess"])
.current_dir("tests/fixture/success/")
.assert()
.success();
}
#[test]
fn run_single_test_failure() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "testFailure"])
.current_dir("tests/fixture/failure/")
.assert()
.code(1);
}
#[test]
fn run_single_test_not_passed() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "testNotPassed.rs"])
.current_dir("tests/fixture/failure/")
.assert()
.code(1);
}
#[test]
fn run_single_test_no_filename() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("run")
.current_dir("tests/fixture/")
.assert()
.code(1);
}
#[test]
fn run_single_test_no_exercise() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "compNoExercise.rs"])
.current_dir("tests/fixture/failure")
.assert()
.code(1);
}
#[test]
fn get_hint_for_single_test() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["hint", "testFailure"])
.current_dir("tests/fixture/failure")
.assert()
.code(0)
.stdout("Hello!\n");
}
#[test]
fn all_exercises_require_confirmation() {
for exercise in glob("exercises/**/*.rs").unwrap() {
let path = exercise.unwrap();
let source = {
let mut file = File::open(&path).unwrap();
let mut s = String::new();
file.read_to_string(&mut s).unwrap();
s
};
source
.matches("// I AM NOT DONE")
.next()
.unwrap_or_else(|| {
panic!(
"There should be an `I AM NOT DONE` annotation in {:?}",
path
)
});
}
}
#[test]
fn run_compile_exercise_does_not_prompt() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "pending_exercise"])
.current_dir("tests/fixture/state")
.assert()
.code(0)
.stdout(predicates::str::contains("I AM NOT DONE").not());
}
#[test]
fn run_test_exercise_does_not_prompt() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "pending_test_exercise"])
.current_dir("tests/fixture/state")
.assert()
.code(0)
.stdout(predicates::str::contains("I AM NOT DONE").not());
}
#[test]
fn run_single_test_success_with_output() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["--nocapture", "run", "testSuccess"])
.current_dir("tests/fixture/success/")
.assert()
.code(0)
.stdout(predicates::str::contains("THIS TEST TOO SHALL PAS"));
}
#[test]
fn run_single_test_success_without_output() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["run", "testSuccess"])
.current_dir("tests/fixture/success/")
.assert()
.code(0)
.stdout(predicates::str::contains("THIS TEST TOO SHALL PAS").not());
}
#[test]
fn run_rustlings_list() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["list"])
.current_dir("tests/fixture/success")
.assert()
.success();
}
#[test]
fn run_rustlings_list_no_pending() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["list"])
.current_dir("tests/fixture/success")
.assert()
.success()
.stdout(predicates::str::contains("Pending").not());
}
#[test]
fn run_rustlings_list_both_done_and_pending() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["list"])
.current_dir("tests/fixture/state")
.assert()
.success()
.stdout(predicates::str::contains("Done").and(predicates::str::contains("Pending")));
}
#[test]
fn run_rustlings_list_without_pending() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["list", "--solved"])
.current_dir("tests/fixture/state")
.assert()
.success()
.stdout(predicates::str::contains("Pending").not());
}
#[test]
fn run_rustlings_list_without_done() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["list", "--unsolved"])
.current_dir("tests/fixture/state")
.assert()
.success()
.stdout(predicates::str::contains("Done").not());
}
#[test]
fn passing() {
println!("THIS TEST TOO SHALL PASS");
assert!(true);
}
[[exercises]]
name = "compSuccess"
path = "compSuccess.rs"
mode = "compile"
hint = """"""
[[exercises]]
name = "testSuccess"
path = "testSuccess.rs"
mode = "test"
hint = """"""
fn main() {
}
// I AM NOT DONE
#[test]
fn it_works() {}
// fake_exercise
// I AM NOT DONE
fn main() {
}
[[exercises]]
name = "pending_exercise"
path = "pending_exercise.rs"
mode = "compile"
hint = """"""
[[exercises]]
name = "pending_test_exercise"
path = "pending_test_exercise.rs"
mode = "test"
hint = """"""
[[exercises]]
name = "finished_exercise"
path = "finished_exercise.rs"
mode = "compile"
hint = """"""
// fake_exercise
fn main() {
}
#[test]
fn not_passing() {
assert!(false);
}
#[test]
fn passing() {
asset!(true);
}
[[exercises]]
name = "compFailure"
path = "compFailure.rs"
mode = "compile"
hint = ""
[[exercises]]
name = "testFailure"
path = "testFailure.rs"
mode = "test"
hint = "Hello!"
fn main() {
}
fn main() {
let
}
use crate::exercise::{CompiledExercise, Exercise, Mode, State};
use console::style;
use indicatif::ProgressBar;
use std::env;
// Verify that the provided container of Exercise objects
// can be compiled and run without any failures.
// Any such failures will be reported to the end user.
// If the Exercise being verified is a test, the verbose boolean
// determines whether or not the test harness outputs are displayed.
pub fn verify<'a>(
start_at: impl IntoIterator<Item = &'a Exercise>,
verbose: bool,
) -> Result<(), &'a Exercise> {
for exercise in start_at {
let compile_result = match exercise.mode {
Mode::Test => compile_and_test(&exercise, RunMode::Interactive, verbose),
Mode::Compile => compile_and_run_interactively(&exercise),
Mode::Clippy => compile_only(&exercise),
};
if !compile_result.unwrap_or(false) {
return Err(exercise);
}
}
Ok(())
}
enum RunMode {
Interactive,
NonInteractive,
}
// Compile and run the resulting test harness of the given Exercise
pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
compile_and_test(exercise, RunMode::NonInteractive, verbose)?;
Ok(())
}
// Invoke the rust compiler without running the resulting binary
fn compile_only(exercise: &Exercise) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let _ = compile(&exercise, &progress_bar)?;
progress_bar.finish_and_clear();
success!("Successfully compiled {}!", exercise);
Ok(prompt_for_completion(&exercise, None))
}
// Compile the given Exercise and run the resulting binary in an interactive mode
fn compile_and_run_interactively(exercise: &Exercise) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilation = compile(&exercise, &progress_bar)?;
progress_bar.set_message(format!("Running {}...", exercise).as_str());
let result = compilation.run();
progress_bar.finish_and_clear();
let output = match result {
Ok(output) => output,
Err(output) => {
warn!("Ran {} with errors", exercise);
println!("{}", output.stdout);
println!("{}", output.stderr);
return Err(());
}
};
success!("Successfully ran {}!", exercise);
Ok(prompt_for_completion(&exercise, Some(output.stdout)))
}
// Compile the given Exercise as a test harness and display
// the output if verbose is set to true
fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilation = compile(exercise, &progress_bar)?;
let result = compilation.run();
progress_bar.finish_and_clear();
match result {
Ok(output) => {
if verbose {
println!("{}", output.stdout);
}
success!("Successfully tested {}", &exercise);
if let RunMode::Interactive = run_mode {
Ok(prompt_for_completion(&exercise, None))
} else {
Ok(true)
}
}
Err(output) => {
warn!(
"Testing of {} failed! Please try again. Here's the output:",
exercise
);
println!("{}", output.stdout);
Err(())
}
}
}
// Compile the given Exercise and return an object with information
// about the state of the compilation
fn compile<'a, 'b>(
exercise: &'a Exercise,
progress_bar: &'b ProgressBar,
) -> Result<CompiledExercise<'a>, ()> {
let compilation_result = exercise.compile();
match compilation_result {
Ok(compilation) => Ok(compilation),
Err(output) => {
progress_bar.finish_and_clear();
warn!(
"Compiling of {} failed! Please try again. Here's the output:",
exercise
);
println!("{}", output.stderr);
Err(())
}
}
}
fn prompt_for_completion(exercise: &Exercise, prompt_output: Option<String>) -> bool {
let context = match exercise.state() {
State::Done => return true,
State::Pending(context) => context,
};
let no_emoji = env::var("NO_EMOJI").is_ok();
let clippy_success_msg = if no_emoji {
"The code is compiling, and Clippy is happy!"
} else {
"The code is compiling, and 📎 Clippy 📎 is happy!"
};
let success_msg = match exercise.mode {
Mode::Compile => "The code is compiling!",
Mode::Test => "The code is compiling, and the tests pass!",
Mode::Clippy => clippy_success_msg,
};
println!();
if no_emoji {
println!("~*~ {} ~*~", success_msg)
} else {
println!("🎉 🎉 {} 🎉 🎉", success_msg)
}
println!();
if let Some(output) = prompt_output {
println!("Output:");
println!("{}", separator());
println!("{}", output);
println!("{}", separator());
println!();
}
println!("You can keep working on this exercise,");
println!(
"or jump into the next one by removing the {} comment:",
style("`I AM NOT DONE`").bold()
);
println!();
for context_line in context {
let formatted_line = if context_line.important {
format!("{}", style(context_line.line).bold())
} else {
context_line.line.to_string()
};
println!(
"{:>2} {} {}",
style(context_line.number).blue().bold(),
style("|").blue(),
formatted_line
);
}
false
}
fn separator() -> console::StyledObject<&'static str> {
style("====================").bold()
}
macro_rules! warn {
($fmt:literal, $ex:expr) => {{
use console::{style, Emoji};
use std::env;
let formatstr = format!($fmt, $ex);
if env::var("NO_EMOJI").is_ok() {
println!("{} {}", style("!").red(), style(formatstr).red());
} else {
println!(
"{} {}",
style(Emoji("⚠️ ", "!")).red(),
style(formatstr).red()
);
}
}};
}
macro_rules! success {
($fmt:literal, $ex:expr) => {{
use console::{style, Emoji};
use std::env;
let formatstr = format!($fmt, $ex);
if env::var("NO_EMOJI").is_ok() {
println!("{} {}", style("✓").green(), style(formatstr).green());
} else {
println!(
"{} {}",
style(Emoji("✅", "✓")).green(),
style(formatstr).green()
);
}
}};
}
use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use indicatif::ProgressBar;
// Invoke the rust compiler on the path of the given exercise,
// and run the ensuing binary.
// The verbose argument helps determine whether or not to show
// the output from the test harnesses (if the mode of the exercise is test)
pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
match exercise.mode {
Mode::Test => test(exercise, verbose)?,
Mode::Compile => compile_and_run(exercise)?,
Mode::Clippy => compile_and_run(exercise)?,
}
Ok(())
}
// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilation_result = exercise.compile();
let compilation = match compilation_result {
Ok(compilation) => compilation,
Err(output) => {
progress_bar.finish_and_clear();
warn!(
"Compilation of {} failed!, Compiler error message:\n",
exercise
);
println!("{}", output.stderr);
return Err(());
}
};
progress_bar.set_message(format!("Running {}...", exercise).as_str());
let result = compilation.run();
progress_bar.finish_and_clear();
match result {
Ok(output) => {
println!("{}", output.stdout);
success!("Successfully ran {}", exercise);
Ok(())
}
Err(output) => {
println!("{}", output.stdout);
println!("{}", output.stderr);
warn!("Ran {} with errors", exercise);
Err(())
}
}
}
use crate::exercise::{Exercise, ExerciseList};
use crate::run::run;
use crate::verify::verify;
use argh::FromArgs;
use console::Emoji;
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::fs;
use std::io::{self, prelude::*};
use std::path::Path;
use std::process::{Command, Stdio};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
#[macro_use]
mod ui;
mod exercise;
mod run;
mod verify;
// In sync with crate version
const VERSION: &str = "4.5.0";
#[derive(FromArgs, PartialEq, Debug)]
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
struct Args {
/// show outputs from the test exercises
#[argh(switch)]
nocapture: bool,
/// show the executable version
#[argh(switch, short = 'v')]
version: bool,
#[argh(subcommand)]
nested: Option<Subcommands>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum Subcommands {
Verify(VerifyArgs),
Watch(WatchArgs),
Run(RunArgs),
Hint(HintArgs),
List(ListArgs),
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "verify")]
/// Verifies all exercises according to the recommended order
struct VerifyArgs {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "watch")]
/// Reruns `verify` when files were edited
struct WatchArgs {}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "run")]
/// Runs/Tests a single exercise
struct RunArgs {
#[argh(positional)]
/// the name of the exercise
name: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "hint")]
/// Returns a hint for the given exercise
struct HintArgs {
#[argh(positional)]
/// the name of the exercise
name: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "list")]
/// Lists the exercises available in Rustlings
struct ListArgs {
#[argh(switch, short = 'p')]
/// show only the paths of the exercises
paths: bool,
#[argh(switch, short = 'n')]
/// show only the names of the exercises
names: bool,
#[argh(option, short = 'f')]
/// provide a string to match exercise names
/// comma separated patterns are acceptable
filter: Option<String>,
#[argh(switch, short = 'u')]
/// display only exercises not yet solved
unsolved: bool,
#[argh(switch, short = 's')]
/// display only exercises that have been solved
solved: bool,
}
fn main() {
let args: Args = argh::from_env();
if args.version {
println!("v{}", VERSION);
std::process::exit(0);
}
if args.nested.is_none() {
println!();
println!(r#" welcome to... "#);
println!(r#" _ _ _ "#);
println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
println!(r#" |___/ "#);
println!();
}
if !Path::new("info.toml").exists() {
println!(
"{} must be run from the rustlings directory",
std::env::current_exe().unwrap().to_str().unwrap()
);
println!("Try `cd rustlings/`!");
std::process::exit(1);
}
if !rustc_exists() {
println!("We cannot find `rustc`.");
println!("Try running `rustc --version` to diagnose your problem.");
println!("For instructions on how to install Rust, check the README.");
std::process::exit(1);
}
let toml_str = &fs::read_to_string("info.toml").unwrap();
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
let verbose = args.nocapture;
let command = args.nested.unwrap_or_else(|| {
let text = fs::read_to_string("default_out.txt").unwrap();
println!("{}", text);
std::process::exit(0);
});
match command {
Subcommands::List(subargs) => {
if !subargs.paths && !subargs.names {
println!("{:<17}\t{:<46}\t{:<7}", "Name", "Path", "Status");
}
let mut exercises_done: u16 = 0;
let filters = subargs.filter.clone().unwrap_or_default().to_lowercase();
exercises.iter().for_each(|e| {
let fname = format!("{}", e.path.display());
let filter_cond = filters
.split(',')
.filter(|f| !f.trim().is_empty())
.any(|f| e.name.contains(&f) || fname.contains(&f));
let status = if e.looks_done() {
exercises_done += 1;
"Done"
} else {
"Pending"
};
let solve_cond = {
(e.looks_done() && subargs.solved)
|| (!e.looks_done() && subargs.unsolved)
|| (!subargs.solved && !subargs.unsolved)
};
if solve_cond && (filter_cond || subargs.filter.is_none()) {
let line = if subargs.paths {
format!("{}\n", fname)
} else if subargs.names {
format!("{}\n", e.name)
} else {
format!("{:<17}\t{:<46}\t{:<7}\n", e.name, fname, status)
};
// Somehow using println! leads to the binary panicking
// when its output is piped.
// So, we're handling a Broken Pipe error and exiting with 0 anyway
let stdout = std::io::stdout();
{
let mut handle = stdout.lock();
handle.write_all(line.as_bytes()).unwrap_or_else(|e| {
match e.kind() {
std::io::ErrorKind::BrokenPipe => std::process::exit(0),
_ => std::process::exit(1),
};
});
}
}
});
let percentage_progress = exercises_done as f32 / exercises.len() as f32 * 100.0;
println!(
"Progress: You completed {} / {} exercises ({:.2} %).",
exercises_done,
exercises.len(),
percentage_progress
);
std::process::exit(0);
}
Subcommands::Run(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);
run(&exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
}
Subcommands::Hint(subargs) => {
let exercise = find_exercise(&subargs.name, &exercises);
println!("{}", exercise.hint);
}
Subcommands::Verify(_subargs) => {
verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1));
}
Subcommands::Watch(_subargs) => {
if let Err(e) = watch(&exercises, verbose) {
println!(
"Error: Could not watch your progress. Error message was {:?}.",
e
);
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
std::process::exit(1);
}
println!(
"{emoji} All exercises completed! {emoji}",
emoji = Emoji("🎉", "★")
);
println!();
println!("+----------------------------------------------------+");
println!("| You made it to the Fe-nish line! |");
println!("+-------------------------- ------------------------+");
println!(" \\/ ");
println!(" ▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ");
println!(" ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ ");
println!(" ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ ");
println!(" ░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒ ");
println!(" ▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓ ");
println!(" ▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒ ");
println!(" ▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒ ");
println!(" ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒ ");
println!(" ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ");
println!(" ▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒ ");
println!(" ▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒ ");
println!(" ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ");
println!(" ▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ");
println!(" ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ");
println!(" ▒▒ ▒▒ ▒▒ ▒▒ ");
println!();
println!("We hope you enjoyed learning about the various aspects of Rust!");
println!(
"If you noticed any issues, please don't hesitate to report them to our repo."
);
println!("You can also contribute your own exercises to help the greater community!");
println!();
println!("Before reporting an issue or contributing, please read our guidelines:");
println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md");
}
}
}
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>) {
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
println!("Type 'hint' or open the corresponding README.md file to get help or type 'clear' to clear the screen.");
thread::spawn(move || loop {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => {
let input = input.trim();
if input.eq("hint") {
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
println!("{}", hint);
}
} else if input.eq("clear") {
println!("\x1B[2J\x1B[1;1H");
} else {
println!("unknown command: {}", input);
}
}
Err(error) => println!("error reading command: {}", error),
}
});
}
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
if name.eq("next") {
exercises
.iter()
.find(|e| !e.looks_done())
.unwrap_or_else(|| {
println!("🎉 Congratulations! You have done all the exercises!");
println!("🔚 There are no more exercises to do next!");
std::process::exit(1)
})
} else {
exercises
.iter()
.find(|e| e.name == name)
.unwrap_or_else(|| {
println!("No exercise found for '{}'!", name);
std::process::exit(1)
})
}
}
fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
/* Clears the terminal with an ANSI escape code.
Works in UNIX and newer Windows terminals. */
fn clear_screen() {
println!("\x1Bc");
}
let (tx, rx) = channel();
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
clear_screen();
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
let failed_exercise_hint = match verify(exercises.iter(), verbose) {
Ok(_) => return Ok(()),
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
};
spawn_watch_shell(&failed_exercise_hint);
loop {
match rx.recv() {
Ok(event) => match event {
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
if b.extension() == Some(OsStr::new("rs")) && b.exists() {
let filepath = b.as_path().canonicalize().unwrap();
let pending_exercises = exercises
.iter()
.skip_while(|e| !filepath.ends_with(&e.path))
// .filter(|e| filepath.ends_with(&e.path))
.chain(
exercises
.iter()
.filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
);
clear_screen();
match verify(pending_exercises, verbose) {
Ok(_) => return Ok(()),
Err(exercise) => {
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
*failed_exercise_hint = Some(to_owned_hint(exercise));
}
}
}
}
_ => {}
},
Err(e) => println!("watch error: {:?}", e),
}
}
}
fn rustc_exists() -> bool {
Command::new("rustc")
.args(&["--version"])
.stdout(Stdio::null())
.spawn()
.and_then(|mut child| child.wait())
.map(|status| status.success())
.unwrap_or(false)
}
use regex::Regex;
use serde::Deserialize;
use std::env;
use std::fmt::{self, Display, Formatter};
use std::fs::{self, remove_file, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::{self, Command};
const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE";
const CONTEXT: usize = 2;
const CLIPPY_CARGO_TOML_PATH: &str = "./exercises/clippy/Cargo.toml";
// Get a temporary file name that is hopefully unique
#[inline]
fn temp_file() -> String {
let thread_id: String = format!("{:?}", std::thread::current().id())
.chars()
.filter(|c| c.is_alphanumeric())
.collect();
format!("./temp_{}_{}", process::id(), thread_id)
}
// The mode of the exercise.
#[derive(Deserialize, Copy, Clone, Debug)]
#[serde(rename_all = "lowercase")]
pub enum Mode {
// Indicates that the exercise should be compiled as a binary
Compile,
// Indicates that the exercise should be compiled as a test harness
Test,
// Indicates that the exercise should be linted with clippy
Clippy,
}
#[derive(Deserialize)]
pub struct ExerciseList {
pub exercises: Vec<Exercise>,
}
// A representation of a rustlings exercise.
// This is deserialized from the accompanying info.toml file
#[derive(Deserialize, Debug)]
pub struct Exercise {
// Name of the exercise
pub name: String,
// The path to the file containing the exercise's source code
pub path: PathBuf,
// The mode of the exercise (Test, Compile, or Clippy)
pub mode: Mode,
// The hint text associated with the exercise
pub hint: String,
}
// An enum to track of the state of an Exercise.
// An Exercise can be either Done or Pending
#[derive(PartialEq, Debug)]
pub enum State {
// The state of the exercise once it's been completed
Done,
// The state of the exercise while it's not completed yet
Pending(Vec<ContextLine>),
}
// The context information of a pending exercise
#[derive(PartialEq, Debug)]
pub struct ContextLine {
// The source code that is still pending completion
pub line: String,
// The line number of the source code still pending completion
pub number: usize,
// Whether or not this is important
pub important: bool,
}
// The result of compiling an exercise
pub struct CompiledExercise<'a> {
exercise: &'a Exercise,
_handle: FileHandle,
}
impl<'a> CompiledExercise<'a> {
// Run the compiled exercise
pub fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
self.exercise.run()
}
}
// A representation of an already executed binary
#[derive(Debug)]
pub struct ExerciseOutput {
// The textual contents of the standard output of the binary
pub stdout: String,
// The textual contents of the standard error of the binary
pub stderr: String,
}
struct FileHandle;
impl Drop for FileHandle {
fn drop(&mut self) {
clean();
}
}
impl Exercise {
pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> {
let cmd = match self.mode {
Mode::Compile => Command::new("rustc")
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output(),
Mode::Test => Command::new("rustc")
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output(),
Mode::Clippy => {
let cargo_toml = format!(
r#"[package]
name = "{}"
version = "0.0.1"
edition = "2018"
[[bin]]
name = "{}"
path = "{}.rs""#,
self.name, self.name, self.name
);
let cargo_toml_error_msg = if env::var("NO_EMOJI").is_ok() {
"Failed to write Clippy Cargo.toml file."
} else {
"Failed to write 📎 Clippy 📎 Cargo.toml file."
};
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml).expect(cargo_toml_error_msg);
// To support the ability to run the clipy exercises, build
// an executable, in addition to running clippy. With a
// compilation failure, this would silently fail. But we expect
// clippy to reflect the same failure while compiling later.
Command::new("rustc")
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output()
.expect("Failed to compile!");
// Due to an issue with Clippy, a cargo clean is required to catch all lints.
// See https://github.com/rust-lang/rust-clippy/issues/2604
// This is already fixed on Clippy's master branch. See this issue to track merging into Cargo:
// https://github.com/rust-lang/rust-clippy/issues/3837
Command::new("cargo")
.args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
.output()
.expect("Failed to run 'cargo clean'");
Command::new("cargo")
.args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
.args(&["--", "-D", "warnings"])
.output()
}
}
.expect("Failed to run 'compile' command.");
if cmd.status.success() {
Ok(CompiledExercise {
exercise: &self,
_handle: FileHandle,
})
} else {
clean();
Err(ExerciseOutput {
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
})
}
}
fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
let arg = match self.mode {
Mode::Test => "--show-output",
_ => "",
};
let cmd = Command::new(&temp_file())
.arg(arg)
.output()
.expect("Failed to run 'run' command");
let output = ExerciseOutput {
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
};
if cmd.status.success() {
Ok(output)
} else {
Err(output)
}
}
pub fn state(&self) -> State {
let mut source_file =
File::open(&self.path).expect("We were unable to open the exercise file!");
let source = {
let mut s = String::new();
source_file
.read_to_string(&mut s)
.expect("We were unable to read the exercise file!");
s
};
let re = Regex::new(I_AM_DONE_REGEX).unwrap();
if !re.is_match(&source) {
return State::Done;
}
let matched_line_index = source
.lines()
.enumerate()
.filter_map(|(i, line)| if re.is_match(line) { Some(i) } else { None })
.next()
.expect("This should not happen at all");
let min_line = ((matched_line_index as i32) - (CONTEXT as i32)).max(0) as usize;
let max_line = matched_line_index + CONTEXT;
let context = source
.lines()
.enumerate()
.filter(|&(i, _)| i >= min_line && i <= max_line)
.map(|(i, line)| ContextLine {
line: line.to_string(),
number: i + 1,
important: i == matched_line_index,
})
.collect();
State::Pending(context)
}
// Check that the exercise looks to be solved using self.state()
// This is not the best way to check since
// the user can just remove the "I AM NOT DONE" string from the file
// without actually having solved anything.
// The only other way to truly check this would to compile and run
// the exercise; which would be both costly and counterintuitive
pub fn looks_done(&self) -> bool {
self.state() == State::Done
}
}
impl Display for Exercise {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.path.to_str().unwrap())
}
}
#[inline]
fn clean() {
let _ignored = remove_file(&temp_file());
}
#[cfg(test)]
mod test {
use super::*;
use std::path::Path;
#[test]
fn test_clean() {
File::create(&temp_file()).unwrap();
let exercise = Exercise {
name: String::from("example"),
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
mode: Mode::Compile,
hint: String::from(""),
};
let compiled = exercise.compile().unwrap();
drop(compiled);
assert!(!Path::new(&temp_file()).exists());
}
#[test]
fn test_pending_state() {
let exercise = Exercise {
name: "pending_exercise".into(),
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
mode: Mode::Compile,
hint: String::new(),
};
let state = exercise.state();
let expected = vec![
ContextLine {
line: "// fake_exercise".to_string(),
number: 1,
important: false,
},
ContextLine {
line: "".to_string(),
number: 2,
important: false,
},
ContextLine {
line: "// I AM NOT DONE".to_string(),
number: 3,
important: true,
},
ContextLine {
line: "".to_string(),
number: 4,
important: false,
},
ContextLine {
line: "fn main() {".to_string(),
number: 5,
important: false,
},
];
assert_eq!(state, State::Pending(expected));
}
#[test]
fn test_finished_exercise() {
let exercise = Exercise {
name: "finished_exercise".into(),
path: PathBuf::from("tests/fixture/state/finished_exercise.rs"),
mode: Mode::Compile,
hint: String::new(),
};
assert_eq!(exercise.state(), State::Done);
}
#[test]
fn test_exercise_with_output() {
let exercise = Exercise {
name: "exercise_with_output".into(),
path: PathBuf::from("tests/fixture/success/testSuccess.rs"),
mode: Mode::Test,
hint: String::new(),
};
let out = exercise.compile().unwrap().run().unwrap();
assert!(out.stdout.contains("THIS TEST TOO SHALL PASS"));
}
}
#!/usr/bin/env bash
echo "Let's get you set up with Rustlings!"
echo "Checking requirements..."
if [ -x "$(command -v git)" ]
then
echo "SUCCESS: Git is installed"
else
echo "ERROR: Git does not seem to be installed."
echo "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
fi
if [ -x "$(command -v rustc)" ]
then
echo "SUCCESS: Rust is installed"
else
echo "ERROR: Rust does not seem to be installed."
echo "Please download Rust using https://rustup.rs!"
exit 1
fi
if [ -x "$(command -v cargo)" ]
then
echo "SUCCESS: Cargo is installed"
else
echo "ERROR: Cargo does not seem to be installed."
echo "Please download Rust and Cargo using https://rustup.rs!"
exit 1
fi
# Look up python installations, starting with 3 with a fallback of 2
if [ -x "$(command -v python3)" ]
then
PY="$(command -v python3)"
elif [ -x "$(command -v python)" ]
then
PY="$(command -v python)"
elif [ -x "$(command -v python2)" ]
then
PY="$(command -v python2)"
else
echo "ERROR: No working python installation was found"
echo "Please install python and add it to the PATH variable"
exit 1
fi
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
function vercomp() {
if [[ $1 == $2 ]]
then
return 0
fi
v1=( ${1//./ } )
v2=( ${2//./ } )
len1=${#v1[@]}
len2=${#v2[@]}
max_len=$len1
if [[ $max_len -lt $len2 ]]
then
max_len=$len2
fi
for i in `seq 0 $max_len`
do
# Fill empty fields with zeros in v1
if [ -z "${v1[$i]}" ]
then
v1[$i]=0
fi
# And in v2
if [ -z "${v2[$i]}" ]
then
v2[$i]=0
fi
if [ ${v1[$i]} -gt ${v2[$i]} ]
then
return 1
fi
if [ ${v1[$i]} -lt ${v2[$i]} ]
then
return 2
fi
done
return 0
}
RustVersion=$(rustc --version | cut -d " " -f 2)
MinRustVersion=1.39
vercomp $RustVersion $MinRustVersion
if [ $? -eq 2 ]
then
echo "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "Please update Rust with 'rustup update'"
exit 1
else
echo "SUCCESS: Rust is up to date"
fi
Path=${1:-rustlings/}
echo "Cloning Rustlings at $Path..."
git clone -q https://github.com/rust-lang/rustlings $Path
cd $Path
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | ${PY} -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin"
if [[ -z ${Version} ]]
then
echo "The latest tag version could not be fetched remotely."
echo "Using the local git repository..."
Version=$(ls -tr .git/refs/tags/ | tail -1)
if [[ -z ${Version} ]]
then
echo "No valid tag version found"
echo "Rustlings will be installed using the main branch"
Version="main"
else
Version="tags/${Version}"
fi
else
Version="tags/${Version}"
fi
echo "Checking out version $Version..."
git checkout -q ${Version}
echo "Installing the 'rustlings' executable..."
cargo install --force --path .
if ! [ -x "$(command -v rustlings)" ]
then
echo "WARNING: Please check that you have '$CargoBin' in your PATH environment variable!"
fi
# Checking whether Clippy is installed.
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
Clippy=$(rustup component list | grep "clippy" | grep "installed")
if [ -z "$Clippy" ]
then
echo "Installing the 'cargo-clippy' executable..."
rustup component add clippy
fi
echo "All done! Run 'rustlings' to get started."
#!/usr/bin/env pwsh
#Requires -Version 5
param($path = "$pwd/rustlings")
Write-Host "Let's get you set up with Rustlings!"
Write-Host "Checking requirements..."
if (Get-Command git -ErrorAction SilentlyContinue) {
Write-Host "SUCCESS: Git is installed"
} else {
Write-Host "WARNING: Git does not seem to be installed."
Write-Host "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
}
if (Get-Command rustc -ErrorAction SilentlyContinue) {
Write-Host "SUCCESS: Rust is installed"
} else {
Write-Host "WARNING: Rust does not seem to be installed."
Write-Host "Please download Rust using https://rustup.rs!"
exit 1
}
if (Get-Command cargo -ErrorAction SilentlyContinue) {
Write-Host "SUCCESS: Cargo is installed"
} else {
Write-Host "WARNING: Cargo does not seem to be installed."
Write-Host "Please download Rust and Cargo using https://rustup.rs!"
exit 1
}
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
function vercomp($v1, $v2) {
if ($v1 -eq $v2) {
return 0
}
$v1 = $v1.Replace(".", "0")
$v2 = $v2.Replace(".", "0")
if ($v1.Length -gt $v2.Length) {
$v2 = $v2.PadRight($v1.Length, "0")
} else {
$v1 = $v1.PadRight($v2.Length, "0")
}
if ($v1 -gt $v2) {
return 1
} else {
return 2
}
}
$rustVersion = $(rustc --version).Split(" ")[1]
$minRustVersion = "1.39"
if ((vercomp $rustVersion $minRustVersion) -eq 2) {
Write-Host "WARNING: Rust version is too old: $rustVersion - needs at least $minRustVersion"
Write-Host "Please update Rust with 'rustup update'"
exit 1
} else {
Write-Host "SUCCESS: Rust is up to date"
}
Write-Host "Cloning Rustlings at $path"
git clone -q https://github.com/rust-lang/rustlings $path
if (!($LASTEXITCODE -eq 0)) {
exit 1
}
# UseBasicParsing is deprecated, pwsh 6 or above will automatically use it,
# but anyone running pwsh 5 will have to pass the argument.
$version = Invoke-WebRequest -UseBasicParsing https://api.github.com/repos/rust-lang/rustlings/releases/latest `
| ConvertFrom-Json | Select-Object -ExpandProperty tag_name
Write-Host "Checking out version $version..."
Set-Location $path
git checkout -q tags/$version
Write-Host "Installing the 'rustlings' executable..."
cargo install --force --path .
if (!(Get-Command rustlings -ErrorAction SilentlyContinue)) {
Write-Host "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
}
# Checking whether Clippy is installed.
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
$clippy = (rustup component list | Select-String "clippy" | Select-String "installed") | Out-String
if (!$clippy) {
Write-Host "Installing the 'cargo-clippy' executable..."
rustup component add clippy
}
Write-Host "All done! Run 'rustlings' to get started."
# VARIABLES
[[exercises]]
name = "variables1"
path = "exercises/variables/variables1.rs"
mode = "compile"
hint = """
Hint: The declaration on line 12 is missing a keyword that is needed in Rust
to create a new variable binding."""
[[exercises]]
name = "variables2"
path = "exercises/variables/variables2.rs"
mode = "compile"
hint = """
The compiler message is saying that Rust cannot infer the type that the
variable binding `x` has with what is given here.
What happens if you annotate line 7 with a type annotation?
What if you give x a value?
What if you do both?
What type should x be, anyway?
What if x is the same type as 10? What if it's a different type?"""
[[exercises]]
name = "variables3"
path = "exercises/variables/variables3.rs"
mode = "compile"
hint = """
In Rust, variable bindings are immutable by default. But here we're trying
to reassign a different value to x! There's a keyword we can use to make
a variable binding mutable instead."""
[[exercises]]
name = "variables4"
path = "exercises/variables/variables4.rs"
mode = "compile"
hint = """
Oops! In this exercise, we have a variable binding that we've created on
line 7, and we're trying to use it on line 8, but we haven't given it a
value. We can't print out something that isn't there; try giving x a value!
This is an error that can cause bugs that's very easy to make in any
programming language -- thankfully the Rust compiler has caught this for us!"""
[[exercises]]
name = "variables5"
path = "exercises/variables/variables5.rs"
mode = "compile"
hint = """
In variables3 we already learned how to make an immutable variable mutable
using a special keyword. Unfortunately this doesn't help us much in this exercise
because we want to assign a different typed value to an existing variable. Sometimes
you may also like to reuse existing variable names because you are just converting
values to different types like in this exercise.
Fortunately Rust has a powerful solution to this problem: 'Shadowing'!
You can read more about 'Shadowing' in the book's section 'Variables and Mutability':
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
Try to solve this exercise afterwards using this technique."""
[[exercises]]
name = "variables6"
path = "exercises/variables/variables6.rs"
mode = "compile"
hint = """
We know about variables and mutability, but there is another important type of
variable available; constants.
Constants are always immutable and they are declared with keyword 'const' rather
than keyword 'let'.
Constants types must also always be annotated.
Read more about constants under 'Differences Between Variables and Constants' in the book's section 'Variables and Mutability':
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
"""
# FUNCTIONS
[[exercises]]
name = "functions1"
path = "exercises/functions/functions1.rs"
mode = "compile"
hint = """
This main function is calling a function that it expects to exist, but the
function doesn't exist. It expects this function to have the name `call_me`.
It expects this function to not take any arguments and not return a value.
Sounds a lot like `main`, doesn't it?"""
[[exercises]]
name = "functions2"
path = "exercises/functions/functions2.rs"
mode = "compile"
hint = """
Rust requires that all parts of a function's signature have type annotations,
but `call_me` is missing the type annotation of `num`."""
[[exercises]]
name = "functions3"
path = "exercises/functions/functions3.rs"
mode = "compile"
hint = """
This time, the function *declaration* is okay, but there's something wrong
with the place where we're calling the function."""
[[exercises]]
name = "functions4"
path = "exercises/functions/functions4.rs"
mode = "compile"
hint = """
The error message points to line 14 and says it expects a type after the
`->`. This is where the function's return type should be-- take a look at
the `is_even` function for an example!"""
[[exercises]]
name = "functions5"
path = "exercises/functions/functions5.rs"
mode = "compile"
hint = """
This is a really common error that can be fixed by removing one character.
It happens because Rust distinguishes between expressions and statements: expressions return
a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language.
We want to return a value of `i32` type from the `square` function, but it is returning a `()` type...
They are not the same. There are two solutions:
1. Add a `return` ahead of `num * num;`
2. remove `;`, make it to be `num * num`"""
# IF
[[exercises]]
name = "if1"
path = "exercises/if/if1.rs"
mode = "test"
hint = """
It's possible to do this in one line if you would like!
Some similar examples from other languages:
- In C(++) this would be: `a > b ? a : b`
- In Python this would be: `a if a > b else b`
Remember in Rust that:
- the `if` condition does not need to be surrounded by parentheses
- `if`/`else` conditionals are expressions
- Each condition is followed by a `{}` block."""
[[exercises]]
name = "if2"
path = "exercises/if/if2.rs"
mode = "test"
hint = """
For that first compiler error, it's important in Rust that each conditional
block return the same type! To get the tests passing, you will need a couple
conditions checking different input values."""
# TEST 1
[[exercises]]
name = "quiz1"
path = "exercises/quiz1.rs"
mode = "test"
hint = "No hints this time ;)"
# MOVE SEMANTICS
[[exercises]]
name = "move_semantics1"
path = "exercises/move_semantics/move_semantics1.rs"
mode = "compile"
hint = """
So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 13,
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 13
where the error is."""
[[exercises]]
name = "move_semantics2"
path = "exercises/move_semantics/move_semantics2.rs"
mode = "compile"
hint = """
So `vec0` is being *moved* into the function `fill_vec` when we call it on
line 10, which means it gets dropped at the end of `fill_vec`, which means we
can't use `vec0` again on line 13 (or anywhere else in `main` after the
`fill_vec` call for that matter). We could fix this in a few ways, try them
all!
1. Make another, separate version of the data that's in `vec0` and pass that
to `fill_vec` instead.
2. Make `fill_vec` borrow its argument instead of taking ownership of it,
and then copy the data within the function in order to return an owned
`Vec<i32>`
3. Make `fill_vec` *mutably* borrow its argument (which will need to be
mutable), modify it directly, then not return anything. Then you can get rid
of `vec1` entirely -- note that this will change what gets printed by the
first `println!`"""
[[exercises]]
name = "move_semantics3"
path = "exercises/move_semantics/move_semantics3.rs"
mode = "compile"
hint = """
The difference between this one and the previous ones is that the first line
of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can,
instead of adding that line back, add `mut` in one place that will change
an existing binding to be a mutable binding instead of an immutable one :)"""
[[exercises]]
name = "move_semantics4"
path = "exercises/move_semantics/move_semantics4.rs"
mode = "compile"
hint = """
Stop reading whenever you feel like you have enough direction :) Or try
doing one step and then fixing the compiler errors that result!
So the end goal is to:
- get rid of the first line in main that creates the new vector
- so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
- we don't want to pass anything to `fill_vec`, so its signature should
reflect that it does not take any arguments
- since we're not creating a new vec in `main` anymore, we need to create
a new vec in `fill_vec`, similarly to the way we did in `main`"""
[[exercises]]
name = "move_semantics5"
path = "exercises/move_semantics/move_semantics5.rs"
mode = "compile"
hint = """
Carefully reason about the range in which each mutable reference is in
vogue. Does it help to update the value of referent (x) immediately after
the mutable reference is taken? Read more about 'Mutable References'
in the book's section References and Borrowing':
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references.
Additional hint:
If you can't add, change, or remove any statements in `main()`, can you
reorder them in a way that lets the program compile?"""
# PRIMITIVE TYPES
[[exercises]]
name = "primitive_types1"
path = "exercises/primitive_types/primitive_types1.rs"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "primitive_types2"
path = "exercises/primitive_types/primitive_types2.rs"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "primitive_types3"
path = "exercises/primitive_types/primitive_types3.rs"
mode = "compile"
hint = """
There's a shorthand to initialize Arrays with a certain size that does not
require you to type in 100 items (but you certainly can if you want!).
For example, you can do:
let array = ["Are we there yet?"; 10];
Bonus: what are some other things you could have that would return true
for `a.len() >= 100`?"""
[[exercises]]
name = "primitive_types4"
path = "exercises/primitive_types/primitive_types4.rs"
mode = "test"
hint = """
Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
https://doc.rust-lang.org/book/ch04-03-slices.html
and use the starting and ending indices of the items in the Array
that you want to end up in the slice.
If you're curious why the first argument of `assert_eq!` does not
have an ampersand for a reference since the second argument is a
reference, take a look at the Deref coercions section of the book:
https://doc.rust-lang.org/book/ch15-02-deref.html"""
[[exercises]]
name = "primitive_types5"
path = "exercises/primitive_types/primitive_types5.rs"
mode = "compile"
hint = """
Take a look at the Data Types -> The Tuple Type section of the book:
https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
Particularly the part about destructuring (second to last example in the section).
You'll need to make a pattern to bind `name` and `age` to the appropriate parts
of the tuple. You can do it!!"""
[[exercises]]
name = "primitive_types6"
path = "exercises/primitive_types/primitive_types6.rs"
mode = "test"
hint = """
While you could use a destructuring `let` for the tuple here, try
indexing into it instead, as explained in the last example of the
Data Types -> The Tuple Type section of the book:
https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
Now you have another tool in your toolbox!"""
# STRUCTS
[[exercises]]
name = "structs1"
path = "exercises/structs/structs1.rs"
mode = "test"
hint = """
Rust has more than one type of struct. Three actually, all variants are used to package related data together.
There are normal (or classic) structs. These are named collections of related data stored in fields.
Tuple structs are basically just named tuples.
Finally, Unit structs. These don't have any fields and are useful for generics.
In this exercise you need to complete and implement one of each kind.
Read more about structs in The Book: https://doc.rust-lang.org/book/ch05-01-defining-structs.html"""
[[exercises]]
name = "structs2"
path = "exercises/structs/structs2.rs"
mode = "test"
hint = """
Creating instances of structs is easy, all you need to do is assign some values to its fields.
There are however some shortcuts that can be taken when instantiating structs.
Have a look in The Book, to find out more: https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax"""
[[exercises]]
name = "structs3"
path = "exercises/structs/structs3.rs"
mode = "test"
hint = """
The new method needs to panic if the weight is physically impossible :), how do we do that in Rust?
For is_international: What makes a package international? Seems related to the places it goes through right?
For calculate_transport_fees: Bigger is more expensive usually, we don't have size, but something may fit the bill here :)
Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
# ENUMS
[[exercises]]
name = "enums1"
path = "exercises/enums/enums1.rs"
mode = "compile"
hint = """
Hint: The declaration of the enumeration type has not been defined yet."""
[[exercises]]
name = "enums2"
path = "exercises/enums/enums2.rs"
mode = "compile"
hint = """
Hint: you can create enumerations that have different variants with different types
such as no data, anonymous structs, a single string, tuples, ...etc"""
[[exercises]]
name = "enums3"
path = "exercises/enums/enums3.rs"
mode = "test"
hint = "No hints this time ;)"
# MODULES
[[exercises]]
name = "modules1"
path = "exercises/modules/modules1.rs"
mode = "compile"
hint = """
Everything is private in Rust by default-- but there's a keyword we can use
to make something public! The compiler error should point to the thing that
needs to be public."""
[[exercises]]
name = "modules2"
path = "exercises/modules/modules2.rs"
mode = "compile"
hint = """
The delicious_snacks module is trying to present an external
interface (the `fruit` and `veggie` constants) that is different than
its internal structure (the `fruits` and `veggies` modules and
associated constants). It's almost there except for one keyword missing for
each constant."""
# COLLECTIONS
[[exercises]]
name = "vec1"
path = "exercises/collections/vec1.rs"
mode = "test"
hint = """
In Rust, there are two ways to define a Vector.
1. One way is to use the `Vec::new()` function to create a new vector
and fill it with the `push()` method.
2. The second way, which is simpler is to use the `vec![]` macro and
define your elements inside the square brackets.
Check this chapter: https://doc.rust-lang.org/stable/book/ch08-01-vectors.html
of the Rust book to learn more.
"""
[[exercises]]
name = "vec2"
path = "exercises/collections/vec2.rs"
mode = "test"
hint = """
Hint 1: `i` is each element from the Vec as they are being iterated.
Can you try multiplying this?
Hint 2: Check the suggestion from the compiler error ;)
"""
[[exercises]]
name = "hashmap1"
path = "exercises/collections/hashmap1.rs"
mode = "test"
hint = """
Hint 1: Take a look at the return type of the function to figure out
the type for the `basket`.
Hint 2: Number of fruits should be at least 5. And you have to put
at least three different types of fruits.
"""
[[exercises]]
name = "hashmap2"
path = "exercises/collections/hashmap2.rs"
mode = "test"
hint = """
Use the `entry()` and `or_insert()` methods of `HashMap` to achieve this.
Learn more at https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value
"""
# STRINGS
[[exercises]]
name = "strings1"
path = "exercises/strings/strings1.rs"
mode = "compile"
hint = """
The `current_favorite_color` function is currently returning a string slice with the `'static`
lifetime. We know this because the data of the string lives in our code itself -- it doesn't
come from a file or user input or another program -- so it will live as long as our program
lives. But it is still a string slice. There's one way to create a `String` by converting a
string slice covered in the Strings chapter of the book, and another way that uses the `From`
trait."""
[[exercises]]
name = "strings2"
path = "exercises/strings/strings2.rs"
mode = "compile"
hint = """
Yes, it would be really easy to fix this by just changing the value bound to `word` to be a
string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
9, though, that will coerce the `String` into a string slice."""
# TEST 2
[[exercises]]
name = "quiz2"
path = "exercises/quiz2.rs"
mode = "compile"
hint = "No hints this time ;)"
# ERROR HANDLING
[[exercises]]
name = "errors1"
path = "exercises/error_handling/errors1.rs"
mode = "test"
hint = """
`Err` is one of the variants of `Result`, so what the 2nd test is saying
is that `generate_nametag_text` should return a `Result` instead of an
`Option`.
To make this change, you'll need to:
- update the return type in the function signature to be a Result<String, String> that
could be the variants `Ok(String)` and `Err(String)`
- change the body of the function to return `Ok(stuff)` where it currently
returns `Some(stuff)`
- change the body of the function to return `Err(error message)` where it
currently returns `None`
- change the first test to expect `Ok(stuff)` where it currently expects
`Some(stuff)`."""
[[exercises]]
name = "errors2"
path = "exercises/error_handling/errors2.rs"
mode = "test"
hint = """
One way to handle this is using a `match` statement on
`item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
`Err(something)`. This pattern is very common in Rust, though, so there's
a `?` operator that does pretty much what you would make that match statement
do for you! Take a look at this section of the Error Handling chapter:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
and give it a try!"""
[[exercises]]
name = "errors3"
path = "exercises/error_handling/errors3.rs"
mode = "compile"
hint = """
If other functions can return a `Result`, why shouldn't `main`?"""
[[exercises]]
name = "errors4"
path = "exercises/error_handling/errors4.rs"
mode = "test"
hint = """
`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
It should be doing some checking, returning an `Err` result if those checks fail, and only
returning an `Ok` result if those checks determine that everything is... okay :)"""
[[exercises]]
name = "errors5"
path = "exercises/error_handling/errors5.rs"
mode = "compile"
hint = """
Hint: There are two different possible `Result` types produced within
`main()`, which are propagated using `?` operators. How do we declare a
return type from `main()` that allows both?
Another hint: under the hood, the `?` operator calls `From::from`
on the error value to convert it to a boxed trait object, a
`Box<dyn error::Error>`, which is polymorphic-- that means that lots of
different kinds of errors can be returned from the same function because
all errors act the same since they all implement the `error::Error` trait.
Check out this section of the book:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
This exercise uses some concepts that we won't get to until later in the
course, like `Box` and the `From` trait. It's not important to understand
them in detail right now, but you can read ahead if you like.
Read more about boxing errors:
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html
Read more about using the `?` operator with boxed errors:
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html
"""
[[exercises]]
name = "errors6"
path = "exercises/error_handling/errors6.rs"
mode = "test"
hint = """
This exercise uses a completed version of `PositiveNonzeroInteger` from
errors4.
Below the line that TODO asks you to change, there is an example of using
the `map_err()` method on a `Result` to transform one type of error into
another. Try using something similar on the `Result` from `parse()`. You
might use the `?` operator to return early from the function, or you might
use a `match` expression, or maybe there's another way!
You can create another function inside `impl ParsePosNonzeroError` to use
with `map_err()`.
Read more about `map_err()` in the `std::result` documentation:
https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err"""
# Generics
[[exercises]]
name = "generics1"
path = "exercises/generics/generics1.rs"
mode = "compile"
hint = """
Vectors in rust make use of generics to create dynamically sized arrays of any type.
You need to tell the compiler what type we are pushing onto this vector."""
[[exercises]]
name = "generics2"
path = "exercises/generics/generics2.rs"
mode = "test"
hint = """
Currently we are wrapping only values of type 'u32'.
Maybe we could update the explicit references to this data type somehow?
If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions
"""
[[exercises]]
name = "generics3"
path = "exercises/generics/generics3.rs"
mode = "test"
hint = """
To find the best solution to this challenge you're going to need to think back to your
knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"
This is definitely harder than the last two exercises! You need to think about not only making the
ReportCard struct generic, but also the correct property - you will need to change the implementation
of the struct slightly too...you can do it!
"""
# OPTIONS
[[exercises]]
name = "option1"
path = "exercises/option/option1.rs"
mode = "compile"
hint = """
Hint 1: Check out some functions of Option:
is_some
is_none
unwrap
and:
pattern matching
Hint 2: There are no sensible defaults for the value of an Array; the values need to be filled before use.
"""
[[exercises]]
name = "option2"
path = "exercises/option/option2.rs"
mode = "compile"
hint = """
check out:
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html
Remember that Options can be stacked in if let and while let.
For example: Some(Some(variable)) = variable2
Also see Option::flatten
"""
[[exercises]]
name = "option3"
path = "exercises/option/option3.rs"
mode = "compile"
hint = """
The compiler says a partial move happened in the `match`
statement. How can this be avoided? The compiler shows the correction
needed. After making the correction as suggested by the compiler, do
read: https://doc.rust-lang.org/std/keyword.ref.html"""
# TRAITS
[[exercises]]
name = "traits1"
path = "exercises/traits/traits1.rs"
mode = "test"
hint = """
A discussion about Traits in Rust can be found at:
https://doc.rust-lang.org/book/ch10-02-traits.html
"""
[[exercises]]
name = "traits2"
path = "exercises/traits/traits2.rs"
mode = "test"
hint = """
Notice how the trait takes ownership of 'self',and returns `Self'.
Try mutating the incoming string vector.
Vectors provide suitable methods for adding an element at the end. See
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
# TESTS
[[exercises]]
name = "tests1"
path = "exercises/tests/tests1.rs"
mode = "test"
hint = """
You don't even need to write any code to test -- you can just test values and run that, even
though you wouldn't do that in real life :) `assert!` is a macro that needs an argument.
Depending on the value of the argument, `assert!` will do nothing (in which case the test will
pass) or `assert!` will panic (in which case the test will fail). So try giving different values
to `assert!` and see which ones compile, which ones pass, and which ones fail :)"""
[[exercises]]
name = "tests2"
path = "exercises/tests/tests2.rs"
mode = "test"
hint = """
Like the previous exercise, you don't need to write any code to get this test to compile and
run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two
values that are equal! Try giving it two arguments that are different! Try giving it two values
that are of different types! Try switching which argument comes first and which comes second!"""
[[exercises]]
name = "tests3"
path = "exercises/tests/tests3.rs"
mode = "test"
hint = """
You can call a function right where you're passing arguments to `assert!` -- so you could do
something like `assert!(having_fun())`. If you want to check that you indeed get false, you
can negate the result of what you're doing using `!`, like `assert!(!having_fun())`."""
# TEST 3
[[exercises]]
name = "quiz3"
path = "exercises/quiz3.rs"
mode = "test"
hint = "No hints this time ;)"
# STANDARD LIBRARY TYPES
[[exercises]]
name = "box1"
path = "exercises/standard_library_types/box1.rs"
mode = "test"
hint = """
Step 1
The compiler's message should help: since we cannot store the value of the actual type
when working with recursive types, we need to store a reference (pointer) to its value.
We should, therefore, place our `List` inside a `Box`. More details in the book here:
https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes
Step 2
Creating an empty list should be fairly straightforward (hint: peek at the assertions).
For a non-empty list keep in mind that we want to use our Cons "list builder".
Although the current list is one of integers (i32), feel free to change the definition
and try other types!
"""
[[exercises]]
name = "arc1"
path = "exercises/standard_library_types/arc1.rs"
mode = "compile"
hint = """
Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order
to avoid creating a copy of `numbers`, you'll need to create `child_numbers`
inside the loop but still in the main thread.
`child_numbers` should be a clone of the Arc of the numbers instead of a
thread-local copy of the numbers.
This is a simple exercise if you understand the underlying concepts, but if this
is too much of a struggle, consider reading through all of Chapter 16 in the book:
https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html
"""
[[exercises]]
name = "iterators1"
path = "exercises/standard_library_types/iterators1.rs"
mode = "compile"
hint = """
Step 1:
We need to apply something to the collection `my_fav_fruits` before we start to go through
it. What could that be? Take a look at the struct definition for a vector for inspiration:
https://doc.rust-lang.org/std/vec/struct.Vec.html.
Step 2 & step 2.1:
Very similar to the lines above and below. You've got this!
Step 3:
An iterator goes through all elements in a collection, but what if we've run out of
elements? What should we expect here? If you're stuck, take a look at
https://doc.rust-lang.org/std/iter/trait.Iterator.html for some ideas.
"""
[[exercises]]
name = "iterators2"
path = "exercises/standard_library_types/iterators2.rs"
mode = "test"
hint = """
Step 1
The variable `first` is a `char`. It needs to be capitalized and added to the
remaining characters in `c` in order to return the correct `String`.
The remaining characters in `c` can be viewed as a string slice using the
`as_str` method.
The documentation for `char` contains many useful methods.
https://doc.rust-lang.org/std/primitive.char.html
Step 2
Create an iterator from the slice. Transform the iterated values by applying
the `capitalize_first` function. Remember to collect the iterator.
Step 3.
This is surprising similar to the previous solution. Collect is very powerful
and very general. Rust just needs to know the desired type."""
[[exercises]]
name = "iterators3"
path = "exercises/standard_library_types/iterators3.rs"
mode = "test"
hint = """
The divide function needs to return the correct error when even division is not
possible.
The division_results variable needs to be collected into a collection type.
The result_with_list function needs to return a single Result where the success
case is a vector of integers and the failure case is a DivisionError.
The list_of_results function needs to return a vector of results.
See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how
the `FromIterator` trait is used in `collect()`."""
[[exercises]]
name = "iterators4"
path = "exercises/standard_library_types/iterators4.rs"
mode = "test"
hint = """
In an imperative language, you might write a for loop that updates
a mutable variable. Or, you might write code utilizing recursion
and a match clause. In Rust you can take another functional
approach, computing the factorial elegantly with ranges and iterators."""
[[exercises]]
name = "iterators5"
path = "exercises/standard_library_types/iterators5.rs"
mode = "test"
hint = """
The documentation for the std::iter::Iterator trait contains numerous methods
that would be helpful here.
Return 0 from count_collection_iterator to make the code compile in order to
test count_iterator.
The collection variable in count_collection_iterator is a slice of HashMaps. It
needs to be converted into an iterator in order to use the iterator methods.
The fold method can be useful in the count_collection_iterator function.
For a further challenge, consult the documentation for Iterator to find
a different method that could make your code more compact than using fold."""
# THREADS
[[exercises]]
name = "threads1"
path = "exercises/threads/threads1.rs"
mode = "compile"
hint = """
`Arc` is an Atomic Reference Counted pointer that allows safe, shared access
to **immutable** data. But we want to *change* the number of `jobs_completed`
so we'll need to also use another type that will only allow one thread to
mutate the data at a time. Take a look at this section of the book:
https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
and keep reading if you'd like more hints :)
Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like:
`let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));`
Similar to the code in the example in the book that happens after the text
that says "We can use Arc<T> to fix this.". If not, give that a try! If you
do and would like more hints, keep reading!!
Make sure neither of your threads are holding onto the lock of the mutex
while they are sleeping, since this will prevent the other thread from
being allowed to get the lock. Locks are automatically released when
they go out of scope.
Ok, so, real talk, this was actually tricky for *me* to do too. And
I could see a lot of different problems you might run into, so at this
point I'm not sure which one you've hit :)
Please open an issue if you're still running into a problem that
these hints are not helping you with, or if you've looked at the sample
answers and don't understand why they work and yours doesn't.
If you've learned from the sample solutions, I encourage you to come
back to this exercise and try it again in a few days to reinforce
what you've learned :)"""
# MACROS
[[exercises]]
name = "macros1"
path = "exercises/macros/macros1.rs"
mode = "compile"
hint = """
When you call a macro, you need to add something special compared to a
regular function call. If you're stuck, take a look at what's inside
`my_macro`."""
[[exercises]]
name = "macros2"
path = "exercises/macros/macros2.rs"
mode = "compile"
hint = """
Macros don't quite play by the same rules as the rest of Rust, in terms of
what's available where.
Unlike other things in Rust, the order of "where you define a macro" versus
"where you use it" actually matters."""
[[exercises]]
name = "macros3"
path = "exercises/macros/macros3.rs"
mode = "compile"
hint = """
In order to use a macro outside of its module, you need to do something
special to the module to lift the macro out into its parent.
The same trick also works on "extern crate" statements for crates that have
exported macros, if you've seen any of those around."""
[[exercises]]
name = "macros4"
path = "exercises/macros/macros4.rs"
mode = "compile"
hint = """
You only need to add a single character to make this compile.
The way macros are written, it wants to see something between each
"macro arm", so it can separate them."""
# TEST 4
[[exercises]]
name = "quiz4"
path = "exercises/quiz4.rs"
mode = "test"
hint = "No hints this time ;)"
# CLIPPY
[[exercises]]
name = "clippy1"
path = "exercises/clippy/clippy1.rs"
mode = "clippy"
hint = """
Not every floating point value can be represented exactly in binary values in
memory. Take a look at the description of
https://doc.rust-lang.org/stable/std/primitive.f32.html
When using the binary compare operators with floating points you won't compare
the floating point values but the binary representation in memory. This is
usually not what you would like to do.
See the suggestions of the clippy warning in compile output and use the
machine epsilon value...
https://doc.rust-lang.org/stable/std/primitive.f32.html#associatedconstant.EPSILON"""
[[exercises]]
name = "clippy2"
path = "exercises/clippy/clippy2.rs"
mode = "clippy"
hint = """
`for` loops over Option values are more clearly expressed as an `if let`"""
# TYPE CONVERSIONS
[[exercises]]
name = "using_as"
path = "exercises/conversions/using_as.rs"
mode = "test"
hint = """
Use the `as` operator to cast one of the operands in the last line of the
`average` function into the expected return type."""
[[exercises]]
name = "from_into"
path = "exercises/conversions/from_into.rs"
mode = "test"
hint = """
Follow the steps provided right before the `From` implementation"""
[[exercises]]
name = "try_from_into"
path = "exercises/conversions/try_from_into.rs"
mode = "test"
hint = """
Follow the steps provided right before the `TryFrom` implementation.
You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
You might want to look back at the exercise errors5 (or its hints) to remind
yourself about how `Box<dyn Error>` works.
If you're trying to return a string as an error, note that neither `str`
nor `String` implements `error::Error`. However, there is an implementation
of `From<&str>` for `Box<dyn Error>`. This means you can use `.into()` or
the `?` operator to convert your string into the correct error type.
If you're having trouble with using the `?` operator to convert an error string,
recall that `?` works to convert `Err(something)` into the appropriate error
type for returning from the function."""
[[exercises]]
name = "as_ref_mut"
path = "exercises/conversions/as_ref_mut.rs"
mode = "test"
hint = """
Add AsRef<str> as a trait bound to the functions."""
[[exercises]]
name = "from_str"
path = "exercises/conversions/from_str.rs"
mode = "test"
hint = """
The implementation of FromStr should return an Ok with a Person object,
or an Err with an error if the string is not valid.
This is almost like the `try_from_into` exercise.
If you're having trouble with returning the correct error type, see the
hints for try_from_into."""
// variables6.rs
// Make me compile! Execute the command `rustlings hint variables6` if you want a hint :)
// I AM NOT DONE
const NUMBER = 3;
fn main() {
println!("Number {}", NUMBER);
}
// variables5.rs
// Make me compile! Execute the command `rustlings hint variables5` if you want a hint :)
// I AM NOT DONE
fn main() {
let number = "T-H-R-E-E"; // don't change this line
println!("Spell a Number : {}", number);
number = 3;
println!("Number plus two is : {}", number + 2);
}
// variables4.rs
// Make me compile! Execute the command `rustlings hint variables4` if you want a hint :)
// I AM NOT DONE
fn main() {
let x: i32;
println!("Number {}", x);
}
// variables3.rs
// Make me compile! Execute the command `rustlings hint variables3` if you want a hint :)
// I AM NOT DONE
fn main() {
let x = 3;
println!("Number {}", x);
x = 5; // don't change this line
println!("Number {}", x);
}
// variables2.rs
// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
// I AM NOT DONE
fn main() {
let x;
if x == 10 {
println!("Ten!");
} else {
println!("Not ten!");
}
}
// variables1.rs
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)
// About this `I AM NOT DONE` thing:
// We sometimes encourage you to keep trying things on a given exercise,
// even after you already figured it out. If you got everything working and
// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
// I AM NOT DONE
fn main() {
x = 5;
println!("x has the value {}", x);
}
# Variables
In Rust, variables are immutable by default.
When a variable is immutable, once a value is bound to a name, you can’t change that value.
You can make them mutable by adding mut in front of the variable name.
## Further information
- [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html)
// traits2.rs
//
// Your task is to implement the trait
// `AppendBar' for a vector of strings.
//
// To implement this trait, consider for
// a moment what it means to 'append "Bar"'
// to a vector of strings.
//
// No boiler plate code this time,
// you can do this!
// I AM NOT DONE
trait AppendBar {
fn append_bar(self) -> Self;
}
//TODO: Add your code here
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
}
}
// traits1.rs
// Time to implement some traits!
//
// Your task is to implement the trait
// `AppendBar' for the type `String'.
//
// The trait AppendBar has only one function,
// which appends "Bar" to any object
// implementing this trait.
// I AM NOT DONE
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
//Add your code here
}
fn main() {
let s = String::from("Foo");
let s = s.append_bar();
println!("s: {}", s);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_FooBar() {
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
}
#[test]
fn is_BarBar() {
assert_eq!(
String::from("").append_bar().append_bar(),
String::from("BarBar")
);
}
}
# Traits
A trait is a collection of methods.
Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`.
In this way, traits are somewhat similar to Java interfaces and C++ abstract classes.
Some additional common Rust traits include:
- `Clone` (the `clone` method)
- `Display` (which allows formatted display via `{}`)
- `Debug` (which allows formatted display via `{:?}`)
Because traits indicate shared behavior between data types, they are useful when writing generics.
## Further information
- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)
// threads1.rs
// Make this compile! Execute `rustlings hint threads1` for hints :)
// The idea is the thread spawned on line 22 is completing jobs while the main thread is
// monitoring progress until 10 jobs are completed. Because of the difference between the
// spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines
// of "waiting..." and the program ends without timing out when running,
// you've got it :)
// I AM NOT DONE
use std::sync::Arc;
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(JobStatus { jobs_completed: 0 });
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
status_shared.jobs_completed += 1;
}
});
while status.jobs_completed < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
# Threads
In most current operating systems, an executed program’s code is run in a process, and the operating system manages multiple processes at once.
Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads.
## Further information
- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html)
- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html)
// tests3.rs
// This test isn't testing our function -- make it do that in such a way that
// the test passes. Then write a second test that tests whether we get the result
// we expect to get when we call `is_even(5)`.
// Execute `rustlings hint tests3` for hints :)
// I AM NOT DONE
pub fn is_even(num: i32) -> bool {
num % 2 == 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_true_when_even() {
assert!();
}
#[test]
fn is_false_when_odd() {
assert!();
}
}
// tests2.rs
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Execute `rustlings hint tests2` for hints :)
// I AM NOT DONE
#[cfg(test)]
mod tests {
#[test]
fn you_can_assert_eq() {
assert_eq!();
}
}
// tests1.rs
// Tests are important to ensure that your code does what you think it should do.
// Tests can be run on this file with the following command:
// rustlings run tests1
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)
// I AM NOT DONE
#[cfg(test)]
mod tests {
#[test]
fn you_can_assert() {
assert!();
}
}
# Tests
Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass!
## Further information
- [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html)
// structs3.rs
// Structs contain data, but can also have logic. In this exercise we have
// defined the Package struct and we want to test some logic attached to it.
// Make the code compile and the tests pass!
// If you have issues execute `rustlings hint structs3`
// I AM NOT DONE
#[derive(Debug)]
struct Package {
sender_country: String,
recipient_country: String,
weight_in_grams: i32,
}
impl Package {
fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
if weight_in_grams <= 0 {
// Something goes here...
} else {
return Package {
sender_country,
recipient_country,
weight_in_grams,
};
}
}
fn is_international(&self) -> ??? {
// Something goes here...
}
fn get_fees(&self, cents_per_gram: i32) -> ??? {
// Something goes here...
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn fail_creating_weightless_package() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Austria");
Package::new(sender_country, recipient_country, -2210);
}
#[test]
fn create_international_package() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Russia");
let package = Package::new(sender_country, recipient_country, 1200);
assert!(package.is_international());
}
#[test]
fn create_local_package() {
let sender_country = String::from("Canada");
let recipient_country = sender_country.clone();
let package = Package::new(sender_country, recipient_country, 1200);
assert!(!package.is_international());
}
#[test]
fn calculate_transport_fees() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Spain");
let cents_per_gram = ???;
let package = Package::new(sender_country, recipient_country, 1500);
assert_eq!(package.get_fees(cents_per_gram), 4500);
}
}
// structs2.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
#[derive(Debug)]
struct Order {
name: String,
year: u32,
made_by_phone: bool,
made_by_mobile: bool,
made_by_email: bool,
item_number: u32,
count: u32,
}
fn create_order_template() -> Order {
Order {
name: String::from("Bob"),
year: 2019,
made_by_phone: false,
made_by_mobile: false,
made_by_email: true,
item_number: 123,
count: 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn your_order() {
let order_template = create_order_template();
// TODO: Create your own order using the update syntax and template above!
// let your_order =
assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year);
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
assert_eq!(your_order.made_by_email, order_template.made_by_email);
assert_eq!(your_order.item_number, order_template.item_number);
assert_eq!(your_order.count, 1);
}
}
// structs1.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
struct ColorClassicStruct {
// TODO: Something goes here
}
struct ColorTupleStruct(/* TODO: Something goes here */);
#[derive(Debug)]
struct UnitStruct;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classic_c_structs() {
// TODO: Instantiate a classic c struct!
// let green =
assert_eq!(green.name, "green");
assert_eq!(green.hex, "#00FF00");
}
#[test]
fn tuple_structs() {
// TODO: Instantiate a tuple struct!
// let green =
assert_eq!(green.0, "green");
assert_eq!(green.1, "#00FF00");
}
#[test]
fn unit_structs() {
// TODO: Instantiate a unit struct!
// let unit_struct =
let message = format!("{:?}s are fun!", unit_struct);
assert_eq!(message, "UnitStructs are fun!");
}
}
# Structs
Rust has three struct types: a classic C struct, a tuple struct, and a unit struct.
## Further information
- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
// strings2.rs
// Make me compile without changing the function signature!
// Execute `rustlings hint strings2` for hints :)
// I AM NOT DONE
fn main() {
let word = String::from("green"); // Try not changing this line :)
if is_a_color_word(word) {
println!("That is a color word I know!");
} else {
println!("That is not a color word I know.");
}
}
fn is_a_color_word(attempt: &str) -> bool {
attempt == "green" || attempt == "blue" || attempt == "red"
}
// strings1.rs
// Make me compile without changing the function signature!
// Execute `rustlings hint strings1` for hints ;)
// I AM NOT DONE
fn main() {
let answer = current_favorite_color();
println!("My current favorite color is {}", answer);
}
fn current_favorite_color() -> String {
"blue"
}
# Strings
Rust has two string types, a string slice (`&str`) and an owned string (`String`).
We're not going to dictate when you should use which one, but we'll show you how
to identify and create them, as well as use them.
## Further information
- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)
// iterators5.rs
// Let's define a simple model to track Rustlings exercise progress. Progress
// will be modelled using a hash map. The name of the exercise is the key and
// the progress is the value. Two counting functions were created to count the
// number of exercises with a given progress. These counting functions use
// imperative style for loops. Recreate this counting functionality using
// iterators. Only the two iterator methods (count_iterator and
// count_collection_iterator) need to be modified.
// Execute `rustlings hint iterators5` for hints.
//
// Make the code compile and the tests pass.
// I AM NOT DONE
use std::collections::HashMap;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Progress {
None,
Some,
Complete,
}
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
let mut count = 0;
for val in map.values() {
if val == &value {
count += 1;
}
}
count
}
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
// map is a hashmap with String keys and Progress values.
// map = { "variables1": Complete, "from_str": None, ... }
}
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
let mut count = 0;
for map in collection {
for val in map.values() {
if val == &value {
count += 1;
}
}
}
count
}
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
// collection is a slice of hashmaps.
// collection = [{ "variables1": Complete, "from_str": None, ... },
// { "variables2": Complete, ... }, ... ]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn count_complete() {
let map = get_map();
assert_eq!(3, count_iterator(&map, Progress::Complete));
}
#[test]
fn count_equals_for() {
let map = get_map();
assert_eq!(
count_for(&map, Progress::Complete),
count_iterator(&map, Progress::Complete)
);
}
#[test]
fn count_collection_complete() {
let collection = get_vec_map();
assert_eq!(
6,
count_collection_iterator(&collection, Progress::Complete)
);
}
#[test]
fn count_collection_equals_for() {
let collection = get_vec_map();
assert_eq!(
count_collection_for(&collection, Progress::Complete),
count_collection_iterator(&collection, Progress::Complete)
);
}
fn get_map() -> HashMap<String, Progress> {
use Progress::*;
let mut map = HashMap::new();
map.insert(String::from("variables1"), Complete);
map.insert(String::from("functions1"), Complete);
map.insert(String::from("hashmap1"), Complete);
map.insert(String::from("arc1"), Some);
map.insert(String::from("as_ref_mut"), None);
map.insert(String::from("from_str"), None);
map
}
fn get_vec_map() -> Vec<HashMap<String, Progress>> {
use Progress::*;
let map = get_map();
let mut other = HashMap::new();
other.insert(String::from("variables2"), Complete);
other.insert(String::from("functions2"), Complete);
other.insert(String::from("if1"), Complete);
other.insert(String::from("from_into"), None);
other.insert(String::from("try_from_into"), None);
vec![map, other]
}
}
// iterators4.rs
// I AM NOT DONE
pub fn factorial(num: u64) -> u64 {
// Complete this function to return the factorial of num
// Do not use:
// - return
// Try not to use:
// - imperative style loops (for, while)
// - additional variables
// For an extra challenge, don't use:
// - recursion
// Execute `rustlings hint iterators4` for hints.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn factorial_of_1() {
assert_eq!(1, factorial(1));
}
#[test]
fn factorial_of_2() {
assert_eq!(2, factorial(2));
}
#[test]
fn factorial_of_4() {
assert_eq!(24, factorial(4));
}
}
// iterators3.rs
// This is a bigger exercise than most of the others! You can do it!
// Here is your mission, should you choose to accept it:
// 1. Complete the divide function to get the first four tests to pass.
// 2. Get the remaining tests to pass by completing the result_with_list and
// list_of_results functions.
// Execute `rustlings hint iterators3` to get some hints!
// I AM NOT DONE
#[derive(Debug, PartialEq, Eq)]
pub enum DivisionError {
NotDivisible(NotDivisibleError),
DivideByZero,
}
#[derive(Debug, PartialEq, Eq)]
pub struct NotDivisibleError {
dividend: i32,
divisor: i32,
}
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
// Otherwise, return a suitable error.
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {}
// Complete the function and return a value of the correct type so the test passes.
// Desired output: Ok([1, 11, 1426, 3])
fn result_with_list() -> () {
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
}
// Complete the function and return a value of the correct type so the test passes.
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
fn list_of_results() -> () {
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_success() {
assert_eq!(divide(81, 9), Ok(9));
}
#[test]
fn test_not_divisible() {
assert_eq!(
divide(81, 6),
Err(DivisionError::NotDivisible(NotDivisibleError {
dividend: 81,
divisor: 6
}))
);
}
#[test]
fn test_divide_by_0() {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
}
#[test]
fn test_divide_0_by_something() {
assert_eq!(divide(0, 81), Ok(0));
}
#[test]
fn test_result_with_list() {
assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");
}
#[test]
fn test_list_of_results() {
assert_eq!(
format!("{:?}", list_of_results()),
"[Ok(1), Ok(11), Ok(1426), Ok(3)]"
);
}
}
// iterators2.rs
// In this exercise, you'll learn some of the unique advantages that iterators
// can offer. Follow the steps to complete the exercise.
// As always, there are hints if you execute `rustlings hint iterators2`!
// I AM NOT DONE
// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => ???,
}
}
// Step 2.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
vec![]
}
// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String {
String::new()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_success() {
assert_eq!(capitalize_first("hello"), "Hello");
}
#[test]
fn test_empty() {
assert_eq!(capitalize_first(""), "");
}
#[test]
fn test_iterate_string_vec() {
let words = vec!["hello", "world"];
assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
}
#[test]
fn test_iterate_into_string() {
let words = vec!["hello", " ", "world"];
assert_eq!(capitalize_words_string(&words), "Hello World");
}
}
// iterators1.rs
//
// Make me compile by filling in the `???`s
//
// When performing operations on elements within a collection, iterators are essential.
// This module helps you get familiar with the structure of using an iterator and
// how to go through elements within an iterable collection.
//
// Execute `rustlings hint iterators1` for hints :D
// I AM NOT DONE
fn main () {
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];
let mut my_iterable_fav_fruits = ???; // TODO: Step 1
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
}
// box1.rs
//
// At compile time, Rust needs to know how much space a type takes up. This becomes problematic
// for recursive types, where a value can have as part of itself another value of the same type.
// To get around the issue, we can use a `Box` - a smart pointer used to store data on the heap,
// which also allows us to wrap a recursive type.
//
// The recursive type we're implementing in this exercise is the `cons list` - a data structure
// frequently found in functional programming languages. Each item in a cons list contains two
// elements: the value of the current item and the next item. The last item is a value called `Nil`.
//
// Step 1: use a `Box` in the enum definition to make the code compile
// Step 2: create both empty and non-empty cons lists by replacing `unimplemented!()`
//
// Note: the tests should not be changed
//
// Execute `rustlings hint box1` for hints :)
// I AM NOT DONE
#[derive(PartialEq, Debug)]
pub enum List {
Cons(i32, List),
Nil,
}
fn main() {
println!("This is an empty cons list: {:?}", create_empty_list());
println!(
"This is a non-empty cons list: {:?}",
create_non_empty_list()
);
}
pub fn create_empty_list() -> List {
unimplemented!()
}
pub fn create_non_empty_list() -> List {
unimplemented!()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_empty_list() {
assert_eq!(List::Nil, create_empty_list())
}
#[test]
fn test_create_non_empty_list() {
assert_ne!(create_empty_list(), create_non_empty_list())
}
}
// arc1.rs
// In this exercise, we are given a Vec of u32 called "numbers" with values ranging
// from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ]
// We would like to use this set of numbers within 8 different threads simultaneously.
// Each thread is going to get the sum of every eighth value, with an offset.
// The first thread (offset 0), will sum 0, 8, 16, ...
// The second thread (offset 1), will sum 1, 9, 17, ...
// The third thread (offset 2), will sum 2, 10, 18, ...
// ...
// The eighth thread (offset 7), will sum 7, 15, 23, ...
// Because we are using threads, our values need to be thread-safe. Therefore,
// we are using Arc. We need to make a change in each of the two TODOs.
// Make this code compile by filling in a value for `shared_numbers` where the
// first TODO comment is, and create an initial binding for `child_numbers`
// where the second TODO comment is. Try not to create any copies of the `numbers` Vec!
// Execute `rustlings hint arc1` for hints :)
// I AM NOT DONE
#![forbid(unused_imports)] // Do not change this, (or the next) line.
use std::sync::Arc;
use std::thread;
fn main() {
let numbers: Vec<_> = (0..100u32).collect();
let shared_numbers = // TODO
let mut joinhandles = Vec::new();
for offset in 0..8 {
let child_numbers = // TODO
joinhandles.push(thread::spawn(move || {
let mut i = offset;
let mut sum = 0;
while i < child_numbers.len() {
sum += child_numbers[i];
i += 8;
}
println!("Sum of offset {} is {}", offset, sum);
}));
}
for handle in joinhandles.into_iter() {
handle.join().unwrap();
}
}
# Standard library types
This section will teach you about Box, Shared-State Concurrency and Iterators.
## Further information
- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html)
- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html)
- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/)
// quiz4.rs
// This quiz covers the sections:
// - Modules
// - Macros
// Write a macro that passes the quiz! No hints this time, you can do it!
// I AM NOT DONE
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_my_macro_world() {
assert_eq!(my_macro!("world!"), "Hello world!");
}
#[test]
fn test_my_macro_goodbye() {
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
}
}
// quiz3.rs
// This is a quiz for the following sections:
// - Tests
// This quiz isn't testing our function -- make it do that in such a way that
// the test passes. Then write a second test that tests that we get the result
// we expect to get when we call `times_two` with a negative number.
// No hints, you can do this :)
// I AM NOT DONE
pub fn times_two(num: i32) -> i32 {
num * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_twice_of_positive_numbers() {
assert_eq!(times_two(4), ???);
}
#[test]
fn returns_twice_of_negative_numbers() {
// TODO replace unimplemented!() with an assert for `times_two(-4)`
unimplemented!()
}
}
// quiz2.rs
// This is a quiz for the following sections:
// - Strings
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!
// I AM NOT DONE
fn string_slice(arg: &str) {
println!("{}", arg);
}
fn string(arg: String) {
println!("{}", arg);
}
fn main() {
???("blue");
???("red".to_string());
???(String::from("hi"));
???("rust is fun!".to_owned());
???("nice weather".into());
???(format!("Interpolation {}", "Station"));
???(&String::from("abc")[0..1]);
???(" hello there ".trim());
???("Happy Monday!".to_string().replace("Mon", "Tues"));
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
// quiz1.rs
// This is a quiz for the following sections:
// - Variables
// - Functions
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
// more than 40 at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the quantity bought. No hints this time!
// I AM NOT DONE
// Put your function here!
// fn ..... {
// Don't modify this function!
#[test]
fn verify_test() {
let price1 = calculate_apple_price(35);
let price2 = calculate_apple_price(40);
let price3 = calculate_apple_price(65);
assert_eq!(70, price1);
assert_eq!(80, price2);
assert_eq!(65, price3);
}
// primitive_types6.rs
// Use a tuple index to access the second element of `numbers`.
// You can put the expression for the second element where ??? is so that the test passes.
// Execute `rustlings hint primitive_types6` for hints!
// I AM NOT DONE
#[test]
fn indexing_tuple() {
let numbers = (1, 2, 3);
// Replace below ??? with the tuple indexing syntax.
let second = ???;
assert_eq!(2, second,
"This is not the 2nd number in the tuple!")
}
// primitive_types5.rs
// Destructure the `cat` tuple so that the println will work.
// Execute `rustlings hint primitive_types5` for hints!
// I AM NOT DONE
fn main() {
let cat = ("Furry McFurson", 3.5);
let /* your pattern here */ = cat;
println!("{} is {} years old.", name, age);
}
// primitive_types4.rs
// Get a slice out of Array a where the ??? is so that the test passes.
// Execute `rustlings hint primitive_types4` for hints!!
// I AM NOT DONE
#[test]
fn slice_out_of_array() {
let a = [1, 2, 3, 4, 5];
let nice_slice = ???
assert_eq!([2, 3, 4], nice_slice)
}
// primitive_types3.rs
// Create an array with at least 100 elements in it where the ??? is.
// Execute `rustlings hint primitive_types3` for hints!
// I AM NOT DONE
fn main() {
let a = ???
if a.len() >= 100 {
println!("Wow, that's a big array!");
} else {
println!("Meh, I eat arrays like that for breakfast.");
}
}
// primitive_types2.rs
// Fill in the rest of the line that has code missing!
// No hints, there's no tricks, just get used to typing these :)
// I AM NOT DONE
fn main() {
// Characters (`char`)
let my_first_initial = 'C';
if my_first_initial.is_alphabetic() {
println!("Alphabetical!");
} else if my_first_initial.is_numeric() {
println!("Numerical!");
} else {
println!("Neither alphabetic nor numeric!");
}
let // Finish this line like the example! What's your favorite character?
// Try a letter, try a number, try a special character, try a character
// from a different language than your own, try an emoji!
if your_character.is_alphabetic() {
println!("Alphabetical!");
} else if your_character.is_numeric() {
println!("Numerical!");
} else {
println!("Neither alphabetic nor numeric!");
}
}
// primitive_types1.rs
// Fill in the rest of the line that has code missing!
// No hints, there's no tricks, just get used to typing these :)
// I AM NOT DONE
fn main() {
// Booleans (`bool`)
let is_morning = true;
if is_morning {
println!("Good morning!");
}
let // Finish the rest of this line like the example! Or make it be false!
if is_evening {
println!("Good evening!");
}
}
# Primitive Types
Rust has a couple of basic types that are directly implemented into the
compiler. In this section, we'll go through the most important ones.
## Further information
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html)
- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html)
// option3.rs
// Make me compile! Execute `rustlings hint option3` for hints
// I AM NOT DONE
struct Point {
x: i32,
y: i32,
}
fn main() {
let y: Option<Point> = Some(Point { x: 100, y: 200 });
match y {
Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y),
_ => println!("no match"),
}
y; // Fix without deleting this line.
}
// option2.rs
// Make me compile! Execute `rustlings hint option2` for hints
// I AM NOT DONE
fn main() {
let optional_word = Some(String::from("rustlings"));
// TODO: Make this an if let statement whose value is "Some" type
word = optional_word {
println!("The word is: {}", word);
} else {
println!("The optional word doesn't contain anything");
}
let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
for x in 1..10 {
optional_integers_vec.push(Some(x));
}
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
// You can stack `Option<T>`'s into while let and if let
integer = optional_integers_vec.pop() {
println!("current value: {}", integer);
}
}
// option1.rs
// Make me compile! Execute `rustlings hint option1` for hints
// I AM NOT DONE
// you can modify anything EXCEPT for this function's sig
fn print_number(maybe_number: Option<u16>) {
println!("printing: {}", maybe_number.unwrap());
}
fn main() {
print_number(13);
print_number(99);
let mut numbers: [Option<u16>; 5];
for iter in 0..5 {
let number_to_add: u16 = {
((iter * 1235) + 2) / (4 * 16)
};
numbers[iter as usize] = number_to_add;
}
}
# Option
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
Option types are very common in Rust code, as they have a number of uses:
- Initial values
- Return values for functions that are not defined over their entire input range (partial functions)
- Return value for otherwise reporting simple errors, where None is returned on error
- Optional struct fields
- Struct fields that can be loaned or "taken"
- Optional function arguments
- Nullable pointers
- Swapping things out of difficult situations
## Further Information
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
// move_semantics5.rs
// Make me compile without adding, removing, or changing any of the
// lines in `main()`.
// Execute `rustlings hint move_semantics5` for hints :)
// I AM NOT DONE
fn main() {
let mut x = 100;
let y = &mut x;
let z = &mut *y;
*y += 100;
*z += 1000;
assert_eq!(x, 1200);
}
// move_semantics4.rs
// Refactor this code so that instead of having `vec0` and creating the vector
// in `fn main`, we create it within `fn fill_vec` and transfer the
// freshly created vector from fill_vec to its caller.
// Execute `rustlings hint move_semantics4` for hints!
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument
fn fill_vec() -> Vec<i32> {
let mut vec = vec;
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
// move_semantics3.rs
// Make me compile without adding new lines-- just changing existing lines!
// (no lines with multiple semicolons necessary!)
// Execute `rustlings hint move_semantics3` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
// move_semantics2.rs
// Make me compile without changing line 13!
// Execute `rustlings hint move_semantics2` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
// Do not change the following line!
println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec;
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
// move_semantics1.rs
// Make me compile! Execute `rustlings hint move_semantics1` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
let vec1 = fill_vec(vec0);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec;
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
# Move Semantics
These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!
## Further information
For this section, the book links are especially important.
- [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
- [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)
// modules2.rs
// Make me compile! Execute `rustlings hint modules2` for hints :)
// I AM NOT DONE
mod delicious_snacks {
use self::fruits::PEAR as fruit;
use self::veggies::CUCUMBER as veggie;
mod fruits {
pub const PEAR: &'static str = "Pear";
pub const APPLE: &'static str = "Apple";
}
mod veggies {
pub const CUCUMBER: &'static str = "Cucumber";
pub const CARROT: &'static str = "Carrot";
}
}
fn main() {
println!(
"favorite snacks: {} and {}",
delicious_snacks::fruit,
delicious_snacks::veggie
);
}
// modules1.rs
// Make me compile! Execute `rustlings hint modules1` for hints :)
// I AM NOT DONE
mod sausage_factory {
fn make_sausage() {
println!("sausage!");
}
}
fn main() {
sausage_factory::make_sausage();
}
# Modules
In this section we'll give you an introduction to Rust's module system.
## Further information
- [The Module System](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html)
// macros4.rs
// Make me compile! Execute `rustlings hint macros4` for hints :)
// I AM NOT DONE
macro_rules! my_macro {
() => {
println!("Check out my macro!");
}
($val:expr) => {
println!("Look at this other macro: {}", $val);
}
}
fn main() {
my_macro!();
my_macro!(7777);
}
// macros3.rs
// Make me compile, without taking the macro out of the module!
// Execute `rustlings hint macros3` for hints :)
// I AM NOT DONE
mod macros {
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
}
fn main() {
my_macro!();
}
// macros2.rs
// Make me compile! Execute `rustlings hint macros2` for hints :)
// I AM NOT DONE
fn main() {
my_macro!();
}
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
// macros1.rs
// Make me compile! Execute `rustlings hint macros1` for hints :)
// I AM NOT DONE
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
fn main() {
my_macro();
}
# Macros
Rust's macro system is very powerful, but also kind of difficult to wrap your
head around. We're not going to teach you how to write your own fully-featured
macros. Instead, we'll show you how to use and create them.
## Further information
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)
// if2.rs
// Step 1: Make me compile!
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
// Execute the command `rustlings hint if2` if you want a hint :)
// I AM NOT DONE
pub fn fizz_if_foo(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else {
1
}
}
// No test changes needed!
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn foo_for_fizz() {
assert_eq!(fizz_if_foo("fizz"), "foo")
}
#[test]
fn bar_for_fuzz() {
assert_eq!(fizz_if_foo("fuzz"), "bar")
}
#[test]
fn default_to_baz() {
assert_eq!(fizz_if_foo("literally anything"), "baz")
}
}
// if1.rs
// I AM NOT DONE
pub fn bigger(a: i32, b: i32) -> i32 {
// Complete this function to return the bigger number!
// Do not use:
// - another function call
// - additional variables
// Execute `rustlings hint if1` for hints
}
// Don't mind this for now :)
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ten_is_bigger_than_eight() {
assert_eq!(10, bigger(10, 8));
}
#[test]
fn fortytwo_is_bigger_than_thirtytwo() {
assert_eq!(42, bigger(32, 42));
}
}
# If
`if`, the most basic type of control flow, is what you'll learn here.
## Further information
- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions)
// An imaginary magical school has a new report card generation system written in Rust!
// Currently the system only supports creating report cards where the student's grade
// is represented numerically (e.g. 1.0 -> 5.5).
// However, the school also issues alphabetical grades (A+ -> F-) and needs
// to be able to print both types of report card!
// Make the necessary code changes in the struct ReportCard and the impl block
// to support alphabetical report cards. Change the Grade in the second test to "A+"
// to show that your changes allow alphabetical grades.
// Execute 'rustlings hint generics3' for hints!
// I AM NOT DONE
pub struct ReportCard {
pub grade: f32,
pub student_name: String,
pub student_age: u8,
}
impl ReportCard {
pub fn print(&self) -> String {
format!("{} ({}) - achieved a grade of {}",
&self.student_name, &self.student_age, &self.grade)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_numeric_report_card() {
let report_card = ReportCard {
grade: 2.1,
student_name: "Tom Wriggle".to_string(),
student_age: 12,
};
assert_eq!(
report_card.print(),
"Tom Wriggle (12) - achieved a grade of 2.1"
);
}
#[test]
fn generate_alphabetic_report_card() {
// TODO: Make sure to change the grade here after you finish the exercise.
let report_card = ReportCard {
grade: 2.1,
student_name: "Gary Plotter".to_string(),
student_age: 11,
};
assert_eq!(
report_card.print(),
"Gary Plotter (11) - achieved a grade of A+"
);
}
}
// This powerful wrapper provides the ability to store a positive integer value.
// Rewrite it using generics so that it supports wrapping ANY type.
// Execute `rustlings hint generics2` for hints!
// I AM NOT DONE
struct Wrapper {
value: u32,
}
impl Wrapper {
pub fn new(value: u32) -> Self {
Wrapper { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn store_u32_in_wrapper() {
assert_eq!(Wrapper::new(42).value, 42);
}
#[test]
fn store_str_in_wrapper() {
assert_eq!(Wrapper::new("Foo").value, "Foo");
}
}
// This shopping list program isn't compiling!
// Use your knowledge of generics to fix it.
// Execute `rustlings hint generics1` for hints!
// I AM NOT DONE
fn main() {
let mut shopping_list: Vec<?> = Vec::new();
shopping_list.push("milk");
}
# Generics
Generics is the topic of generalizing types and functionalities to broader cases.
This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax.
Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid.
The simplest and most common use of generics is for type parameters.
## Further information
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)
- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html)
// functions5.rs
// Make me compile! Execute `rustlings hint functions5` for hints :)
// I AM NOT DONE
fn main() {
let answer = square(3);
println!("The answer is {}", answer);
}
fn square(num: i32) -> i32 {
num * num;
}
// functions4.rs
// Make me compile! Execute `rustlings hint functions4` for hints :)
// This store is having a sale where if the price is an even number, you get
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
// I AM NOT DONE
fn main() {
let original_price = 51;
println!("Your sale price is {}", sale_price(original_price));
}
fn sale_price(price: i32) -> {
if is_even(price) {
price - 10
} else {
price - 3
}
}
fn is_even(num: i32) -> bool {
num % 2 == 0
}
// functions3.rs
// Make me compile! Execute `rustlings hint functions3` for hints :)
// I AM NOT DONE
fn main() {
call_me();
}
fn call_me(num: u32) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
// functions2.rs
// Make me compile! Execute `rustlings hint functions2` for hints :)
// I AM NOT DONE
fn main() {
call_me(3);
}
fn call_me(num:) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
// functions1.rs
// Make me compile! Execute `rustlings hint functions1` for hints :)
// I AM NOT DONE
fn main() {
call_me();
}
# Functions
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
## Further information
- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
// errors6.rs
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
// for library code, where callers might want to make decisions based on the
// error content, instead of printing it out or propagating it further. Here,
// we define a custom error type to make it possible for callers to decide
// what to do next when our function returns an error.
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
// I AM NOT DONE
use std::num::ParseIntError;
// This is a custom error type that we will be using in `parse_pos_nonzero()`.
#[derive(PartialEq, Debug)]
enum ParsePosNonzeroError {
Creation(CreationError),
ParseInt(ParseIntError)
}
impl ParsePosNonzeroError {
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
ParsePosNonzeroError::Creation(err)
}
// TODO: add another error conversion function here.
}
fn parse_pos_nonzero(s: &str)
-> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
{
// TODO: change this to return an appropriate error instead of panicking
// when `parse()` returns an error.
let x: i64 = s.parse().unwrap();
PositiveNonzeroInteger::new(x)
.map_err(ParsePosNonzeroError::from_creation)
}
// Don't change anything below this line.
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
#[derive(PartialEq, Debug)]
enum CreationError {
Negative,
Zero,
}
impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
match value {
x if x < 0 => Err(CreationError::Negative),
x if x == 0 => Err(CreationError::Zero),
x => Ok(PositiveNonzeroInteger(x as u64))
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_parse_error() {
// We can't construct a ParseIntError, so we have to pattern match.
assert!(matches!(
parse_pos_nonzero("not a number"),
Err(ParsePosNonzeroError::ParseInt(_))
));
}
#[test]
fn test_negative() {
assert_eq!(
parse_pos_nonzero("-555"),
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
);
}
#[test]
fn test_zero() {
assert_eq!(
parse_pos_nonzero("0"),
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
);
}
#[test]
fn test_positive() {
let x = PositiveNonzeroInteger::new(42);
assert!(x.is_ok());
assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));
}
}
// errors5.rs
// This program uses a completed version of the code from errors4.
// It won't compile right now! Why?
// Execute `rustlings hint errors5` for hints!
// I AM NOT DONE
use std::error;
use std::fmt;
use std::num::ParseIntError;
// TODO: update the return type of `main()` to make this compile.
fn main() -> Result<(), ParseIntError> {
let pretend_user_input = "42";
let x: i64 = pretend_user_input.parse()?;
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
Ok(())
}
// Don't change anything below this line.
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
#[derive(PartialEq, Debug)]
enum CreationError {
Negative,
Zero,
}
impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
match value {
x if x < 0 => Err(CreationError::Negative),
x if x == 0 => Err(CreationError::Zero),
x => Ok(PositiveNonzeroInteger(x as u64))
}
}
}
// This is required so that `CreationError` can implement `error::Error`.
impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let description = match *self {
CreationError::Negative => "number is negative",
CreationError::Zero => "number is zero",
};
f.write_str(description)
}
}
impl error::Error for CreationError {}
// errors4.rs
// Make this test pass! Execute `rustlings hint errors4` for hints :)
// I AM NOT DONE
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
#[derive(PartialEq, Debug)]
enum CreationError {
Negative,
Zero,
}
impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
Ok(PositiveNonzeroInteger(value as u64))
}
}
#[test]
fn test_creation() {
assert!(PositiveNonzeroInteger::new(10).is_ok());
assert_eq!(
Err(CreationError::Negative),
PositiveNonzeroInteger::new(-10)
);
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
}
// errors3.rs
// This is a program that is trying to use a completed version of the
// `total_cost` function from the previous exercise. It's not working though!
// Why not? What should we do to fix it?
// Execute `rustlings hint errors3` for hints!
// I AM NOT DONE
use std::num::ParseIntError;
fn main() {
let mut tokens = 100;
let pretend_user_input = "8";
let cost = total_cost(pretend_user_input)?;
if cost > tokens {
println!("You can't afford that many!");
} else {
tokens -= cost;
println!("You now have {} tokens.", tokens);
}
}
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let processing_fee = 1;
let cost_per_item = 5;
let qty = item_quantity.parse::<i32>()?;
Ok(qty * cost_per_item + processing_fee)
}
// errors2.rs
// Say we're writing a game where you can buy items with tokens. All items cost
// 5 tokens, and whenever you purchase items there is a processing fee of 1
// token. A player of the game will type in how many items they want to buy,
// and the `total_cost` function will calculate the total number of tokens.
// Since the player typed in the quantity, though, we get it as a string-- and
// they might have typed anything, not just numbers!
// Right now, this function isn't handling the error case at all (and isn't
// handling the success case properly either). What we want to do is:
// if we call the `parse` function on a string that is not a number, that
// function will return a `ParseIntError`, and in that case, we want to
// immediately return that error from our function and not try to multiply
// and add.
// There are at least two ways to implement this that are both correct-- but
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
// I AM NOT DONE
use std::num::ParseIntError;
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let processing_fee = 1;
let cost_per_item = 5;
let qty = item_quantity.parse::<i32>();
Ok(qty * cost_per_item + processing_fee)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn item_quantity_is_a_valid_number() {
assert_eq!(total_cost("34"), Ok(171));
}
#[test]
fn item_quantity_is_an_invalid_number() {
assert_eq!(
total_cost("beep boop").unwrap_err().to_string(),
"invalid digit found in string"
);
}
}
// errors1.rs
// This function refuses to generate text to be printed on a nametag if
// you pass it an empty string. It'd be nicer if it explained what the problem
// was, instead of just sometimes returning `None`. The 2nd test currently
// does not compile or pass, but it illustrates the behavior we would like
// this function to have.
// Execute `rustlings hint errors1` for hints!
// I AM NOT DONE
pub fn generate_nametag_text(name: String) -> Option<String> {
if name.len() > 0 {
Some(format!("Hi! My name is {}", name))
} else {
// Empty names aren't allowed.
None
}
}
#[cfg(test)]
mod tests {
use super::*;
// This test passes initially if you comment out the 2nd test.
// You'll need to update what this test expects when you change
// the function under test!
#[test]
fn generates_nametag_text_for_a_nonempty_name() {
assert_eq!(
generate_nametag_text("Beyoncé".into()),
Some("Hi! My name is Beyoncé".into())
);
}
#[test]
fn explains_why_generating_nametag_text_fails() {
assert_eq!(
generate_nametag_text("".into()),
Err("`name` was empty; it must be nonempty.".into())
);
}
}
# Error handling
Most errors aren’t serious enough to require the program to stop entirely.
Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to.
For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process.
## Further information
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html)
- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html)
// enums3.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
enum Message {
// TODO: implement the message variant types based on their usage below
}
struct Point {
x: u8,
y: u8,
}
struct State {
color: (u8, u8, u8),
position: Point,
quit: bool,
}
impl State {
fn change_color(&mut self, color: (u8, u8, u8)) {
self.color = color;
}
fn quit(&mut self) {
self.quit = true;
}
fn echo(&self, s: String) {
println!("{}", s);
}
fn move_position(&mut self, p: Point) {
self.position = p;
}
fn process(&mut self, message: Message) {
// TODO: create a match expression to process the different message variants
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_message_call() {
let mut state = State {
quit: false,
position: Point { x: 0, y: 0 },
color: (0, 0, 0),
};
state.process(Message::ChangeColor((255, 0, 255)));
state.process(Message::Echo(String::from("hello world")));
state.process(Message::Move(Point { x: 10, y: 15 }));
state.process(Message::Quit);
assert_eq!(state.color, (255, 0, 255));
assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15);
assert_eq!(state.quit, true);
}
}
// enums2.rs
// Make me compile! Execute `rustlings hint enums2` for hints!
// I AM NOT DONE
#[derive(Debug)]
enum Message {
// TODO: define the different variants used below
}
impl Message {
fn call(&self) {
println!("{:?}", &self);
}
}
fn main() {
let messages = [
Message::Move { x: 10, y: 30 },
Message::Echo(String::from("hello world")),
Message::ChangeColor(200, 255, 255),
Message::Quit,
];
for message in &messages {
message.call();
}
}
// enums1.rs
// Make me compile! Execute `rustlings hint enums1` for hints!
// I AM NOT DONE
#[derive(Debug)]
enum Message {
// TODO: define a few types of messages as used below
}
fn main() {
println!("{:?}", Message::Quit);
println!("{:?}", Message::Echo);
println!("{:?}", Message::Move);
println!("{:?}", Message::ChangeColor);
}
# Enums
Rust allows you to define types called "enums" which enumerate possible values.
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
## Further information
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
// Type casting in Rust is done via the usage of the `as` operator.
// Please note that the `as` operator is not only used when type casting.
// It also helps with renaming imports.
//
// The goal is to make sure that the division does not fail to compile
// and returns the proper type.
// I AM NOT DONE
fn average(values: &[f64]) -> f64 {
let total = values.iter().fold(0.0, |a, b| a + b);
total / values.len()
}
fn main() {
let values = [3.5, 0.3, 13.0, 11.7];
println!("{}", average(&values));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_proper_type_and_value() {
assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
}
}
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
// Basically, this is the same as From. The main difference is that this should return a Result type
// instead of the target type itself.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
use std::convert::{TryFrom, TryInto};
use std::error;
#[derive(Debug, PartialEq)]
struct Color {
red: u8,
green: u8,
blue: u8,
}
// I AM NOT DONE
// Your task is to complete this implementation
// and return an Ok result of inner type Color.
// You need to create an implementation for a tuple of three integers,
// an array of three integers and a slice of integers.
//
// Note that the implementation for tuple and array will be checked at compile time,
// but the slice implementation needs to check the slice length!
// Also note that correct RGB color values must be integers in the 0..=255 range.
// Tuple implementation
impl TryFrom<(i16, i16, i16)> for Color {
type Error = Box<dyn error::Error>;
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {}
}
// Array implementation
impl TryFrom<[i16; 3]> for Color {
type Error = Box<dyn error::Error>;
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}
}
// Slice implementation
impl TryFrom<&[i16]> for Color {
type Error = Box<dyn error::Error>;
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}
}
fn main() {
// Use the `from` function
let c1 = Color::try_from((183, 65, 14));
println!("{:?}", c1);
// Since From is implemented for Color, we should be able to use Into
let c2: Result<Color, _> = [183, 65, 14].try_into();
println!("{:?}", c2);
let v = vec![183, 65, 14];
// With slice we should use `from` function
let c3 = Color::try_from(&v[..]);
println!("{:?}", c3);
// or take slice within round brackets and use Into
let c4: Result<Color, _> = (&v[..]).try_into();
println!("{:?}", c4);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tuple_out_of_range_positive() {
assert!(Color::try_from((256, 1000, 10000)).is_err());
}
#[test]
fn test_tuple_out_of_range_negative() {
assert!(Color::try_from((-1, -10, -256)).is_err());
}
#[test]
fn test_tuple_sum() {
assert!(Color::try_from((-1, 255, 255)).is_err());
}
#[test]
fn test_tuple_correct() {
let c: Result<Color, _> = (183, 65, 14).try_into();
assert!(c.is_ok());
assert_eq!(
c.unwrap(),
Color {
red: 183,
green: 65,
blue: 14
}
);
}
#[test]
fn test_array_out_of_range_positive() {
let c: Result<Color, _> = [1000, 10000, 256].try_into();
assert!(c.is_err());
}
#[test]
fn test_array_out_of_range_negative() {
let c: Result<Color, _> = [-10, -256, -1].try_into();
assert!(c.is_err());
}
#[test]
fn test_array_sum() {
let c: Result<Color, _> = [-1, 255, 255].try_into();
assert!(c.is_err());
}
#[test]
fn test_array_correct() {
let c: Result<Color, _> = [183, 65, 14].try_into();
assert!(c.is_ok());
assert_eq!(
c.unwrap(),
Color {
red: 183,
green: 65,
blue: 14
}
);
}
#[test]
fn test_slice_out_of_range_positive() {
let arr = [10000, 256, 1000];
assert!(Color::try_from(&arr[..]).is_err());
}
#[test]
fn test_slice_out_of_range_negative() {
let arr = [-256, -1, -10];
assert!(Color::try_from(&arr[..]).is_err());
}
#[test]
fn test_slice_sum() {
let arr = [-1, 255, 255];
assert!(Color::try_from(&arr[..]).is_err());
}
#[test]
fn test_slice_correct() {
let v = vec![183, 65, 14];
let c: Result<Color, _> = Color::try_from(&v[..]);
assert!(c.is_ok());
assert_eq!(
c.unwrap(),
Color {
red: 183,
green: 65,
blue: 14
}
);
}
#[test]
fn test_slice_excess_length() {
let v = vec![0, 0, 0, 0];
assert!(Color::try_from(&v[..]).is_err());
}
#[test]
fn test_slice_insufficient_length() {
let v = vec![0, 0];
assert!(Color::try_from(&v[..]).is_err());
}
}
// This does practically the same thing that TryFrom<&str> does.
// Additionally, upon implementing FromStr, you can use the `parse` method
// on strings to generate an object of the implementor type.
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
use std::error;
use std::str::FromStr;
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// I AM NOT DONE
// Steps:
// 1. If the length of the provided string is 0, an error should be returned
// 2. Split the given string on the commas present in it
// 3. Only 2 elements should be returned from the split, otherwise return an error
// 4. Extract the first element from the split operation and use it as the name
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
// with something like `"4".parse::<usize>()`
// 5. If while extracting the name and the age something goes wrong, an error should be returned
// If everything goes well, then return a Result of a Person object
impl FromStr for Person {
type Err = Box<dyn error::Error>;
fn from_str(s: &str) -> Result<Person, Self::Err> {
}
}
fn main() {
let p = "Mark,20".parse::<Person>().unwrap();
println!("{:?}", p);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_input() {
assert!("".parse::<Person>().is_err());
}
#[test]
fn good_input() {
let p = "John,32".parse::<Person>();
assert!(p.is_ok());
let p = p.unwrap();
assert_eq!(p.name, "John");
assert_eq!(p.age, 32);
}
#[test]
fn missing_age() {
assert!("John,".parse::<Person>().is_err());
}
#[test]
fn invalid_age() {
assert!("John,twenty".parse::<Person>().is_err());
}
#[test]
fn missing_comma_and_age() {
assert!("John".parse::<Person>().is_err());
}
#[test]
fn missing_name() {
assert!(",1".parse::<Person>().is_err());
}
#[test]
fn missing_name_and_age() {
assert!(",".parse::<Person>().is_err());
}
#[test]
fn missing_name_and_invalid_age() {
assert!(",one".parse::<Person>().is_err());
}
#[test]
fn trailing_comma() {
assert!("John,32,".parse::<Person>().is_err());
}
#[test]
fn trailing_comma_and_some_string() {
assert!("John,32,man".parse::<Person>().is_err());
}
}
// The From trait is used for value-to-value conversions.
// If From is implemented correctly for a type, the Into trait should work conversely.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// We implement the Default trait to use it as a fallback
// when the provided string is not convertible into a Person object
impl Default for Person {
fn default() -> Person {
Person {
name: String::from("John"),
age: 30,
}
}
}
// Your task is to complete this implementation
// in order for the line `let p = Person::from("Mark,20")` to compile
// Please note that you'll need to parse the age component into a `usize`
// with something like `"4".parse::<usize>()`. The outcome of this needs to
// be handled appropriately.
//
// Steps:
// 1. If the length of the provided string is 0, then return the default of Person
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. If the name is empty, then return the default of Person
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return the default of Person
// Otherwise, then return an instantiated Person object with the results
// I AM NOT DONE
impl From<&str> for Person {
fn from(s: &str) -> Person {
}
}
fn main() {
// Use the `from` function
let p1 = Person::from("Mark,20");
// Since From is implemented for Person, we should be able to use Into
let p2: Person = "Gerald,70".into();
println!("{:?}", p1);
println!("{:?}", p2);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
// Test that the default person is 30 year old John
let dp = Person::default();
assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30);
}
#[test]
fn test_bad_convert() {
// Test that John is returned when bad string is provided
let p = Person::from("");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_good_convert() {
// Test that "Mark,20" works
let p = Person::from("Mark,20");
assert_eq!(p.name, "Mark");
assert_eq!(p.age, 20);
}
#[test]
fn test_bad_age() {
// Test that "Mark,twenty" will return the default person due to an error in parsing age
let p = Person::from("Mark,twenty");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_comma_and_age() {
let p: Person = Person::from("Mark");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_age() {
let p: Person = Person::from("Mark,");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_name() {
let p: Person = Person::from(",1");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_name_and_age() {
let p: Person = Person::from(",");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_name_and_invalid_age() {
let p: Person = Person::from(",one");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_trailing_comma() {
let p: Person = Person::from("Mike,32,");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_trailing_comma_and_some_string() {
let p: Person = Person::from("Mike,32,man");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
}
// AsRef and AsMut allow for cheap reference-to-reference conversions.
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
// I AM NOT DONE
// Obtain the number of bytes (not characters) in the given argument
// Add the AsRef trait appropriately as a trait bound
fn byte_counter<T>(arg: T) -> usize {
arg.as_ref().as_bytes().len()
}
// Obtain the number of characters (not bytes) in the given argument
// Add the AsRef trait appropriately as a trait bound
fn char_counter<T>(arg: T) -> usize {
arg.as_ref().chars().count()
}
fn main() {
let s = "Café au lait";
println!("{}", char_counter(s));
println!("{}", byte_counter(s));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn different_counts() {
let s = "Café au lait";
assert_ne!(char_counter(s), byte_counter(s));
}
#[test]
fn same_counts() {
let s = "Cafe au lait";
assert_eq!(char_counter(s), byte_counter(s));
}
#[test]
fn different_counts_using_string() {
let s = String::from("Café au lait");
assert_ne!(char_counter(s.clone()), byte_counter(s));
}
#[test]
fn same_counts_using_string() {
let s = String::from("Cafe au lait");
assert_eq!(char_counter(s.clone()), byte_counter(s));
}
}
# Type conversions
Rust offers a multitude of ways to convert a value of a given type into another type.
The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this.
Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
The traits are the following:
- `From` and `Into` covered in [`from_into`](from_into.rs)
- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking.
These should be the main ways ***within the standard library*** to convert data into your desired types.
## Further information
These are not directly covered in the book, but the standard library has a great documentation for it.
- [conversions](https://doc.rust-lang.org/std/convert/index.html)
- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
// vec2.rs
// A Vec of even numbers is given. Your task is to complete the loop
// so that each number in the Vec is multiplied by 2.
//
// Make me pass the test!
//
// Execute the command `rustlings hint vec2` if you need
// hints.
// I AM NOT DONE
fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
for i in v.iter_mut() {
// TODO: Fill this up so that each element in the Vec `v` is
// multiplied by 2.
}
// At this point, `v` should be equal to [4, 8, 12, 16, 20].
v
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vec_loop() {
let v: Vec<i32> = (1..).filter(|x| x % 2 == 0).take(5).collect();
let ans = vec_loop(v.clone());
assert_eq!(ans, v.iter().map(|x| x * 2).collect::<Vec<i32>>());
}
}
// vec1.rs
// Your task is to create a `Vec` which holds the exact same elements
// as in the array `a`.
// Make me compile and pass the test!
// Execute the command `rustlings hint vec1` if you need hints.
// I AM NOT DONE
fn array_and_vec() -> ([i32; 4], Vec<i32>) {
let a = [10, 20, 30, 40]; // a plain array
let v = // TODO: declare your vector here with the macro for vectors
(a, v)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_array_and_vec_similarity() {
let (a, v) = array_and_vec();
assert_eq!(a, v[..]);
}
}
// hashmap2.rs
// A basket of fruits in the form of a hash map is given. The key
// represents the name of the fruit and the value represents how many
// of that particular fruit is in the basket. You have to put *MORE
// THAN 11* fruits in the basket. Three types of fruits - Apple (4),
// Mango (2) and Lychee (5) are already given in the basket. You are
// not allowed to insert any more of these fruits!
//
// Make me pass the tests!
//
// Execute the command `rustlings hint hashmap2` if you need
// hints.
// I AM NOT DONE
use std::collections::HashMap;
#[derive(Hash, PartialEq, Eq)]
enum Fruit {
Apple,
Banana,
Mango,
Lychee,
Pineapple,
}
fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
let fruit_kinds = vec![
Fruit::Apple,
Fruit::Banana,
Fruit::Mango,
Fruit::Lychee,
Fruit::Pineapple,
];
for fruit in fruit_kinds {
// TODO: Put new fruits if not already present. Note that you
// are not allowed to put any type of fruit that's already
// present!
}
}
#[cfg(test)]
mod tests {
use super::*;
fn get_fruit_basket() -> HashMap<Fruit, u32> {
let mut basket = HashMap::<Fruit, u32>::new();
basket.insert(Fruit::Apple, 4);
basket.insert(Fruit::Mango, 2);
basket.insert(Fruit::Lychee, 5);
basket
}
#[test]
fn test_given_fruits_are_not_modified() {
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
}
#[test]
fn at_least_five_types_of_fruits() {
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
let count_fruit_kinds = basket.len();
assert!(count_fruit_kinds >= 5);
}
#[test]
fn greater_than_eleven_fruits() {
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
let count = basket.values().sum::<u32>();
assert!(count > 11);
}
}
// hashmap1.rs
// A basket of fruits in the form of a hash map needs to be defined.
// The key represents the name of the fruit and the value represents
// how many of that particular fruit is in the basket. You have to put
// at least three different types of fruits (e.g apple, banana, mango)
// in the basket and the total count of all the fruits should be at
// least five.
//
// Make me compile and pass the tests!
//
// Execute the command `rustlings hint hashmap1` if you need
// hints.
// I AM NOT DONE
use std::collections::HashMap;
fn fruit_basket() -> HashMap<String, u32> {
let mut basket = // TODO: declare your hash map here.
// Two bananas are already given for you :)
basket.insert(String::from("banana"), 2);
// TODO: Put more fruits in your basket here.
basket
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn at_least_three_types_of_fruits() {
let basket = fruit_basket();
assert!(basket.len() >= 3);
}
#[test]
fn at_least_five_fruits() {
let basket = fruit_basket();
assert!(basket.values().sum::<u32>() >= 5);
}
}
# Collections
Rust’s standard library includes a number of very useful data
structures called collections. Most other data types represent one
specific value, but collections can contain multiple values. Unlike
the built-in array and tuple types, the data these collections point
to is stored on the heap, which means the amount of data does not need
to be known at compile time and can grow or shrink as the program
runs.
This exercise will get you familiar with two fundamental data
structures that are used very often in Rust programs:
* A *vector* allows you to store a variable number of values next to
each other.
* A *hash map* allows you to associate a value with a particular key.
You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
## Further information
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
// clippy2.rs
// Make me compile! Execute `rustlings hint clippy2` for hints :)
// I AM NOT DONE
fn main() {
let mut res = 42;
let option = Some(12);
for x in option {
res += x;
}
println!("{}", res);
}
// clippy1.rs
// The Clippy tool is a collection of lints to analyze your code
// so you can catch common mistakes and improve your Rust code.
//
// For these exercises the code will fail to compile when there are clippy warnings
// check clippy's suggestions from the output to solve the exercise.
// Execute `rustlings hint clippy1` for hints :)
// I AM NOT DONE
fn main() {
let x = 1.2331f64;
let y = 1.2332f64;
if y != x {
println!("Success!");
}
}
# Clippy
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
If you used the installation script for Rustlings, Clippy should be already installed.
If not you can install it manually via `rustup component add clippy`.
## Further information
- [GitHub Repository](https://github.com/rust-lang/rust-clippy).
# Exercise to Book Chapter mapping
| Exercise | Book Chapter |
|------------------------|--------------|
| variables | §3.1 |
| functions | §3.3 |
| if | §3.5 |
| move_semantics | §4.1 |
| primitive_types | §4.3 |
| structs | §5.1 |
| enums | §6 |
| modules | §7.2 |
| collections | §8.1, §8.3 |
| strings | §8.2 |
| error_handling | §9 |
| generics | §10 |
| option | §10.1 |
| traits | §10.2 |
| tests | §11.1 |
| standard_library_types | §13.2 |
| threads | §16.1 |
| macros | §19.6 |
| clippy | n/a |
| conversions | n/a |
Thanks for installing Rustlings!
Is this your first time? Don't worry, Rustlings was made for beginners! We are
going to teach you a lot of things about Rust, but before we can get
started, here's a couple of notes about how Rustlings operates:
1. The central concept behind Rustlings is that you solve exercises. These
exercises usually have some sort of syntax error in them, which will cause
them to fail compilation or testing. Sometimes there's a logic error instead
of a syntax error. No matter what error, it's your job to find it and fix it!
You'll know when you fixed it because then, the exercise will compile and
Rustlings will be able to move on to the next exercise.
2. If you run Rustlings in watch mode (which we recommend), it'll automatically
start with the first exercise. Don't get confused by an error message popping
up as soon as you run Rustlings! This is part of the exercise that you're
supposed to solve, so open the exercise file in an editor and start your
detective work!
3. If you're stuck on an exercise, there is a helpful hint you can view by typing
'hint' (in watch mode), or running `rustlings hint myexercise`.
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
(https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
and sometimes, other learners do too so you can help each other out!
Got all that? Great! To get started, run `rustlings watch` in order to get the first
exercise. Make sure to have your editor open!
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-100-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
# rustlings 🦀❤️
Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages!
_...looking for the old, web-based version of Rustlings? Try [here](https://github.com/rust-lang/rustlings/tree/rustlings-1)_
Alternatively, for a first-time Rust learner, there are several other resources:
- [The Book](https://doc.rust-lang.org/book/index.html) - The most comprehensive resource for learning Rust, but a bit theoretical sometimes. You will be using this along with Rustlings!
- [Rust By Example](https://doc.rust-lang.org/rust-by-example/index.html) - Learn Rust by solving little exercises! It's almost like `rustlings`, but online
## Getting Started
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
## MacOS/Linux
Just run:
```bash
curl -L https://git.io/install-rustlings | bash
# Or if you want it to be installed to a different path:
curl -L https://git.io/install-rustlings | bash -s mypath/
```
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
## Windows
In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:
```ps
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
Then, you can run:
```ps
Start-BitsTransfer -Source https://git.io/JTL5v -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1
```
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
When you get a permission denied message then you have to exclude the directory where you placed the rustlings in your virus-scanner
## Browser:
[Run on Repl.it](https://repl.it/github/rust-lang/rustlings)
[Open in Gitpod](https://gitpod.io/#https://github.com/rust-lang/rustlings)
## Manually
Basically: Clone the repository at the latest tag, run `cargo install`.
```bash
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.5.0)
git clone -b 4.5.0 --depth 1 https://github.com/rust-lang/rustlings
cd rustlings
cargo install --force --path .
```
If there are installation errors, ensure that your toolchain is up to date. For the latest, run:
```bash
rustup update
```
Then, same as above, run `rustlings` to get started.
## Doing exercises
The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/<topic>`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start.
The task is simple. Most exercises contain an error that keeps them from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute:
```bash
rustlings watch
```
This will try to verify the completion of every exercise in a predetermined order (what we think is best for newcomers). It will also rerun automatically every time you change a file in the `exercises/` directory. If you want to only run it once, you can use:
```bash
rustlings verify
```
This will do the same as watch, but it'll quit after running.
In case you want to go by your own order, or want to only verify a single exercise, you can run:
```bash
rustlings run myExercise1
```
Or simply use the following command to run the next unsolved exercise in the course:
```bash
rustlings run next
```
In case you get stuck, you can run the following command to get a hint for your
exercise:
``` bash
rustlings hint myExercise1
```
You can also get the hint for the next unsolved exercise with the following command:
``` bash
rustlings hint next
```
To check your progress, you can run the following command:
```bash
rustlings list
```
## Testing yourself
After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once. These quizzes are found in `exercises/quizN.rs`.
## Continuing On
Once you've completed Rustlings, put your new knowledge to good use! Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.
## Uninstalling Rustlings
If you want to remove Rustlings from your system, there's two steps. First, you'll need to remove the exercises folder that the install script created
for you:
``` bash
rm -rf rustlings # or your custom folder name, if you chose and or renamed it
```
Second, since Rustlings got installed via `cargo install`, it's only reasonable to assume that you can also remove it using Cargo, and
exactly that is the case. Run `cargo uninstall` to remove the `rustlings` binary:
``` bash
cargo uninstall rustlings
```
Now you should be done!
## Completion
Rustlings isn't done; there are a couple of sections that are very experimental and don't have proper documentation. These include:
- Errors (`exercises/errors/`)
- Option (`exercises/option/`)
- Result (`exercises/result/`)
- Move Semantics (could still be improved, `exercises/move_semantics/`)
Additionally, we could use exercises on a couple of topics:
- Structs
- Better ownership stuff
- `impl`
- ??? probably more
If you are interested in improving or adding new ones, please feel free to contribute! Read on for more information :)
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md).
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://carol-nichols.com"><img src="https://avatars2.githubusercontent.com/u/193874?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Carol (Nichols || Goulding)</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=carols10cents" title="Code">💻</a> <a href="#content-carols10cents" title="Content">🖋</a></td>
<td align="center"><a href="https://twitter.com/QuietMisdreavus"><img src="https://avatars2.githubusercontent.com/u/5217170?v=4?s=100" width="100px;" alt=""/><br /><sub><b>QuietMisdreavus</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=QuietMisdreavus" title="Code">💻</a> <a href="#content-QuietMisdreavus" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/robertlugg"><img src="https://avatars0.githubusercontent.com/u/6054540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert M Lugg</b></sub></a><br /><a href="#content-robertlugg" title="Content">🖋</a></td>
<td align="center"><a href="https://hynek.me/about/"><img src="https://avatars3.githubusercontent.com/u/41240?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hynek Schlawack</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=hynek" title="Code">💻</a></td>
<td align="center"><a href="https://spacekookie.de"><img src="https://avatars0.githubusercontent.com/u/7669898?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katharina Fey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=spacekookie" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/lukabavdaz"><img src="https://avatars0.githubusercontent.com/u/9624558?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lukabavdaz</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lukabavdaz" title="Code">💻</a> <a href="#content-lukabavdaz" title="Content">🖋</a></td>
<td align="center"><a href="http://vestera.as"><img src="https://avatars2.githubusercontent.com/u/4187449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Erik Vesteraas</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=evestera" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Delet0r"><img src="https://avatars1.githubusercontent.com/u/23195618?v=4?s=100" width="100px;" alt=""/><br /><sub><b>delet0r</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Delet0r" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="http://phinary.ca"><img src="https://avatars1.githubusercontent.com/u/10522375?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shaun Bennett</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=shaunbennett" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/abagshaw"><img src="https://avatars2.githubusercontent.com/u/8594541?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Bagshaw</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=abagshaw" title="Code">💻</a></td>
<td align="center"><a href="https://ai6ua.net/"><img src="https://avatars2.githubusercontent.com/u/175578?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kyle Isom</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=kisom" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ColinPitrat"><img src="https://avatars3.githubusercontent.com/u/1541863?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Colin Pitrat</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ColinPitrat" title="Code">💻</a></td>
<td align="center"><a href="https://zacanger.com"><img src="https://avatars3.githubusercontent.com/u/12520493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zac Anger</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=zacanger" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/mgeier"><img src="https://avatars1.githubusercontent.com/u/705404?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matthias Geier</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=mgeier" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/cjpearce"><img src="https://avatars1.githubusercontent.com/u/3453268?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Pearce</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cjpearce" title="Code">💻</a></td>
<td align="center"><a href="https://yvan-sraka.github.io"><img src="https://avatars2.githubusercontent.com/u/705213?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yvan Sraka</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=yvan-sraka" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/dendi239"><img src="https://avatars3.githubusercontent.com/u/16478650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Denys Smirnov</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=dendi239" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/eddyp"><img src="https://avatars2.githubusercontent.com/u/123772?v=4?s=100" width="100px;" alt=""/><br /><sub><b>eddyp</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=eddyp" title="Code">💻</a></td>
<td align="center"><a href="http://about.me/BrianKung"><img src="https://avatars1.githubusercontent.com/u/2836167?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brian Kung</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=briankung" title="Code">💻</a> <a href="#content-briankung" title="Content">🖋</a></td>
<td align="center"><a href="https://rcousineau.gitlab.io"><img src="https://avatars3.githubusercontent.com/u/281039?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Russell</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=miller-time" title="Code">💻</a></td>
<td align="center"><a href="http://danwilhelm.com"><img src="https://avatars3.githubusercontent.com/u/6137185?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dan Wilhelm</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=danwilhelm" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Jesse-Cameron"><img src="https://avatars3.githubusercontent.com/u/3723654?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jesse</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Jesse-Cameron" title="Code">💻</a> <a href="#content-Jesse-Cameron" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/MrFroop"><img src="https://avatars3.githubusercontent.com/u/196700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fredrik Jambrén</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=MrFroop" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/petemcfarlane"><img src="https://avatars3.githubusercontent.com/u/3472717?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pete McFarlane</b></sub></a><br /><a href="#content-petemcfarlane" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/nkanderson"><img src="https://avatars0.githubusercontent.com/u/4128825?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nkanderson</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nkanderson" title="Code">💻</a> <a href="#content-nkanderson" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/ajaxm"><img src="https://avatars0.githubusercontent.com/u/13360138?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ajax M</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ajaxm" title="Documentation">📖</a></td>
<td align="center"><a href="https://dylnuge.com"><img src="https://avatars2.githubusercontent.com/u/118624?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dylan Nugent</b></sub></a><br /><a href="#content-Dylnuge" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/vyaslav"><img src="https://avatars0.githubusercontent.com/u/1385427?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vyaslav</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=vyaslav" title="Code">💻</a> <a href="#content-vyaslav" title="Content">🖋</a></td>
<td align="center"><a href="https://join.sfxd.org"><img src="https://avatars1.githubusercontent.com/u/17297466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=gdoenlen" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nyxtom"><img src="https://avatars2.githubusercontent.com/u/222763?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas Holloway</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nyxtom" title="Code">💻</a> <a href="#content-nyxtom" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/workingjubilee"><img src="https://avatars1.githubusercontent.com/u/46493976?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jubilee</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=workingjubilee" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/WofWca"><img src="https://avatars1.githubusercontent.com/u/39462442?v=4?s=100" width="100px;" alt=""/><br /><sub><b>WofWca</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=WofWca" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/jrvidal"><img src="https://avatars0.githubusercontent.com/u/1636604?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Roberto Vidal</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jrvidal" title="Code">💻</a> <a href="https://github.com/rust-lang/rustlings/commits?author=jrvidal" title="Documentation">📖</a> <a href="#ideas-jrvidal" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-jrvidal" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/jensim"><img src="https://avatars0.githubusercontent.com/u/3663856?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jens</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jensim" title="Documentation">📖</a></td>
<td align="center"><a href="http://rahatah.me/d"><img src="https://avatars3.githubusercontent.com/u/3174006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rahat Ahmed</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=rahatarmanahmed" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/AbdouSeck"><img src="https://avatars2.githubusercontent.com/u/6490055?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Abdou Seck</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=AbdouSeck" title="Code">💻</a> <a href="#content-AbdouSeck" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/pulls?q=is%3Apr+reviewed-by%3AAbdouSeck" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://codehearts.com"><img src="https://avatars0.githubusercontent.com/u/2885412?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katie</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=codehearts" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Socratides"><img src="https://avatars3.githubusercontent.com/u/27732983?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Socrates</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Socratides" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/gnodarse"><img src="https://avatars3.githubusercontent.com/u/46761795?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gnodarse</b></sub></a><br /><a href="#content-gnodarse" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/harrisonmetz"><img src="https://avatars1.githubusercontent.com/u/7883408?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harrison Metzger</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=harrisonmetz" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/TorbenJ"><img src="https://avatars2.githubusercontent.com/u/9077102?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Torben Jonas</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=TorbenJ" title="Code">💻</a> <a href="#content-TorbenJ" title="Content">🖋</a></td>
<td align="center"><a href="http://paulbissex.com/"><img src="https://avatars0.githubusercontent.com/u/641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Bissex</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=pbx" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/sjmann"><img src="https://avatars0.githubusercontent.com/u/6589896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Steven Mann</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sjmann" title="Code">💻</a> <a href="#content-sjmann" title="Content">🖋</a></td>
<td align="center"><a href="https://smmdb.net/"><img src="https://avatars2.githubusercontent.com/u/5855071?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mario Reder</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Tarnadas" title="Code">💻</a> <a href="#content-Tarnadas" title="Content">🖋</a></td>
<td align="center"><a href="https://keybase.io/skim"><img src="https://avatars0.githubusercontent.com/u/47347?v=4?s=100" width="100px;" alt=""/><br /><sub><b>skim</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sl4m" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/sanjaykdragon"><img src="https://avatars1.githubusercontent.com/u/10261698?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sanjay K</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sanjaykdragon" title="Code">💻</a> <a href="#content-sanjaykdragon" title="Content">🖋</a></td>
<td align="center"><a href="http://www.rohanjain.in"><img src="https://avatars1.githubusercontent.com/u/343499?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rohan Jain</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=crodjer" title="Code">💻</a></td>
<td align="center"><a href="https://www.saidaspen.se"><img src="https://avatars1.githubusercontent.com/u/7727687?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Said Aspen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=saidaspen" title="Code">💻</a> <a href="#content-saidaspen" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/uce"><img src="https://avatars3.githubusercontent.com/u/1756620?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ufuk Celebi</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=uce" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/lebedevsergey"><img src="https://avatars2.githubusercontent.com/u/7325764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lebedevsergey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lebedevsergey" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/avrong"><img src="https://avatars2.githubusercontent.com/u/6342851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksei Trifonov</b></sub></a><br /><a href="#content-avrong" title="Content">🖋</a></td>
<td align="center"><a href="https://drn.ie"><img src="https://avatars2.githubusercontent.com/u/411136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Darren Meehan</b></sub></a><br /><a href="#content-Darrenmeehan" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/jihchi"><img src="https://avatars1.githubusercontent.com/u/87983?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jihchi Lee</b></sub></a><br /><a href="#content-jihchi" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/bertonha"><img src="https://avatars3.githubusercontent.com/u/1225902?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christofer Bertonha</b></sub></a><br /><a href="#content-bertonha" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/apatniv"><img src="https://avatars2.githubusercontent.com/u/22565917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vivek Bharath Akupatni</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=apatniv" title="Code">💻</a> <a href="https://github.com/rust-lang/rustlings/commits?author=apatniv" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/DiD92"><img src="https://avatars3.githubusercontent.com/u/6002416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dídac Sementé Fernández</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=DiD92" title="Code">💻</a> <a href="#content-DiD92" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/wrobstory"><img src="https://avatars3.githubusercontent.com/u/2601457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rob Story</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=wrobstory" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/siobhanjacobson"><img src="https://avatars2.githubusercontent.com/u/28983835?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Siobhan Jacobson</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=siobhanjacobson" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/evancarroll/"><img src="https://avatars2.githubusercontent.com/u/19922?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evan Carroll</b></sub></a><br /><a href="#content-EvanCarroll" title="Content">🖋</a></td>
<td align="center"><a href="http://www.jawaadmahmood.com"><img src="https://avatars3.githubusercontent.com/u/95606?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jawaad Mahmood</b></sub></a><br /><a href="#content-jmahmood" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/GaurangTandon"><img src="https://avatars1.githubusercontent.com/u/6308683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gaurang Tandon</b></sub></a><br /><a href="#content-GaurangTandon" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/dev-cyprium"><img src="https://avatars1.githubusercontent.com/u/6002628?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Kupresak</b></sub></a><br /><a href="#content-dev-cyprium" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/greg-el"><img src="https://avatars3.githubusercontent.com/u/45019882?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Greg Leonard</b></sub></a><br /><a href="#content-greg-el" title="Content">🖋</a></td>
<td align="center"><a href="https://ryanpcmcquen.org"><img src="https://avatars3.githubusercontent.com/u/772937?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ryan McQuen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ryanpcmcquen" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/AnnikaCodes"><img src="https://avatars3.githubusercontent.com/u/56906084?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Annika</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/pulls?q=is%3Apr+reviewed-by%3AAnnikaCodes" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://darnuria.eu"><img src="https://avatars1.githubusercontent.com/u/2827553?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Axel Viala</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=darnuria" title="Code">💻</a></td>
<td align="center"><a href="https://sazid.github.io"><img src="https://avatars1.githubusercontent.com/u/2370167?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohammed Sazid Al Rashid</b></sub></a><br /><a href="#content-sazid" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=sazid" title="Code">💻</a></td>
<td align="center"><a href="https://codingthemsoftly.com"><img src="https://avatars1.githubusercontent.com/u/17479099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Caleb Webber</b></sub></a><br /><a href="#maintenance-seeplusplus" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/pcn"><img src="https://avatars2.githubusercontent.com/u/1056756?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Peter N</b></sub></a><br /><a href="#maintenance-pcn" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/seancad"><img src="https://avatars1.githubusercontent.com/u/47405611?v=4?s=100" width="100px;" alt=""/><br /><sub><b>seancad</b></sub></a><br /><a href="#maintenance-seancad" title="Maintenance">🚧</a></td>
<td align="center"><a href="http://willhayworth.com"><img src="https://avatars3.githubusercontent.com/u/181174?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Will Hayworth</b></sub></a><br /><a href="#content-wsh" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/chrizel"><img src="https://avatars3.githubusercontent.com/u/20802?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Zeller</b></sub></a><br /><a href="#content-chrizel" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/jfchevrette"><img src="https://avatars.githubusercontent.com/u/3001?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jean-Francois Chevrette</b></sub></a><br /><a href="#content-jfchevrette" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=jfchevrette" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jbaber"><img src="https://avatars.githubusercontent.com/u/1908117?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Baber-Lucero</b></sub></a><br /><a href="#content-jbaber" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/tal-zvon"><img src="https://avatars.githubusercontent.com/u/3195851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tal</b></sub></a><br /><a href="#content-tal-zvon" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/apogeeoak"><img src="https://avatars.githubusercontent.com/u/59737221?v=4?s=100" width="100px;" alt=""/><br /><sub><b>apogeeoak</b></sub></a><br /><a href="#content-apogeeoak" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=apogeeoak" title="Code">💻</a></td>
<td align="center"><a href="http://www.garfieldtech.com/"><img src="https://avatars.githubusercontent.com/u/254863?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Larry Garfield</b></sub></a><br /><a href="#content-Crell" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/circumspect"><img src="https://avatars.githubusercontent.com/u/40770208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>circumspect</b></sub></a><br /><a href="#content-circumspect" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/cjwyett"><img src="https://avatars.githubusercontent.com/u/34195737?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cyrus Wyett</b></sub></a><br /><a href="#content-cjwyett" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/cadolphs"><img src="https://avatars.githubusercontent.com/u/13894820?v=4?s=100" width="100px;" alt=""/><br /><sub><b>cadolphs</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cadolphs" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.haveneer.com"><img src="https://avatars.githubusercontent.com/u/26146722?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pascal H.</b></sub></a><br /><a href="#content-hpwxf" title="Content">🖋</a></td>
<td align="center"><a href="https://twitter.com/chapeupreto"><img src="https://avatars.githubusercontent.com/u/834048?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rod Elias</b></sub></a><br /><a href="#content-chapeupreto" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/blerchy"><img src="https://avatars.githubusercontent.com/u/2555355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Lebl</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=blerchy" title="Code">💻</a></td>
<td align="center"><a href="http://flakolefluk.dev"><img src="https://avatars.githubusercontent.com/u/11986564?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ignacio Le Fluk</b></sub></a><br /><a href="#content-flakolefluk" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/tlyu"><img src="https://avatars.githubusercontent.com/u/431873?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Taylor Yu</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=tlyu" title="Code">💻</a> <a href="#content-tlyu" title="Content">🖋</a></td>
<td align="center"><a href="https://zerotask.github.io"><img src="https://avatars.githubusercontent.com/u/20150243?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Patrick Hintermayer</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Zerotask" title="Code">💻</a></td>
<td align="center"><a href="https://petkopavlovski.com/"><img src="https://avatars.githubusercontent.com/u/32264020?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pete Pavlovski</b></sub></a><br /><a href="#content-arthas168" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/k12ish"><img src="https://avatars.githubusercontent.com/u/45272873?v=4?s=100" width="100px;" alt=""/><br /><sub><b>k12ish</b></sub></a><br /><a href="#content-k12ish" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/hongshaoyang"><img src="https://avatars.githubusercontent.com/u/19281800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shao Yang Hong</b></sub></a><br /><a href="#content-hongshaoyang" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/bmacer"><img src="https://avatars.githubusercontent.com/u/13931806?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brandon Macer</b></sub></a><br /><a href="#content-bmacer" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/stoiandan"><img src="https://avatars.githubusercontent.com/u/10388612?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stoian Dan</b></sub></a><br /><a href="#content-stoiandan" title="Content">🖋</a></td>
<td align="center"><a href="https://about.me/pjdelport"><img src="https://avatars.githubusercontent.com/u/630271?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pi Delport</b></sub></a><br /><a href="#content-PiDelport" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/sateeshkumarb"><img src="https://avatars.githubusercontent.com/u/429263?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sateesh </b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sateeshkumarb" title="Code">💻</a> <a href="#content-sateeshkumarb" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/kayuapi"><img src="https://avatars.githubusercontent.com/u/10304328?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ZC</b></sub></a><br /><a href="#content-kayuapi" title="Content">🖋</a></td>
<td align="center"><a href="https://github.com/hyperparabolic"><img src="https://avatars.githubusercontent.com/u/12348474?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hyperparabolic</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=hyperparabolic" title="Code">💻</a></td>
<td align="center"><a href="https://www.net4visions.at"><img src="https://avatars.githubusercontent.com/u/5228369?v=4?s=100" width="100px;" alt=""/><br /><sub><b>arlecchino</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=kolbma" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://richthofen.io/"><img src="https://avatars.githubusercontent.com/u/7576730?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richthofen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jazzplato" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/cseltol"><img src="https://avatars.githubusercontent.com/u/64264529?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ivan Nerazumov</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cseltol" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/lauralindzey"><img src="https://avatars.githubusercontent.com/u/65185744?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lauralindzey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lauralindzey" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/sinharaksh1t"><img src="https://avatars.githubusercontent.com/u/28585848?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rakshit Sinha</b></sub></a><br /><a href="#content-sinharaksh1t" title="Content">🖋</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
The MIT License (MIT)
Copyright (c) 2016 Carol (Nichols || Goulding)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
[package]
name = "rustlings"
version = "4.5.0"
authors = ["anastasie <ana@ana.st>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
edition = "2018"
[dependencies]
argh = "0.1.4"
indicatif = "0.10.3"
console = "0.7.7"
notify = "4.0.15"
toml = "0.4.10"
regex = "1.1.6"
serde = {version = "1.0.10", features = ["derive"]}
[[bin]]
name = "rustlings"
path = "src/main.rs"
[dev-dependencies]
assert_cmd = "0.11.0"
predicates = "1.0.1"
glob = "0.3.0"
## Contributing to Rustlings
First off, thanks for taking the time to contribute!! ❤️
### Quick Reference
I want to...
_add an exercise! ➡️ [read this](#addex) and then [open a Pull Request](#prs)_
_update an outdated exercise! ➡️ [open a Pull Request](#prs)_
_report a bug! ➡️ [open an Issue](#issues)_
_fix a bug! ➡️ [open a Pull Request](#prs)_
_implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull Request](#issues)_
<a name="#src"></a>
### Working on the source code
`rustlings` is basically a glorified `rustc` wrapper. Therefore the source code
isn't really that complicated since the bulk of the work is done by `rustc`.
`src/main.rs` contains a simple `clap` CLI that loads from `src/verify.rs` and `src/run.rs`.
<a name="addex"></a>
### Adding an exercise
The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
Next make sure it runs with `rustlings`. The exercise metadata is stored in `info.toml`, under the `exercises` array. The order of the `exercises` array determines the order the exercises are run by `rustlings verify`.
Add the metadata for your exercise in the correct order in the `exercises` array. If you are unsure of the correct ordering, add it at the bottom and ask in your pull request. The exercise metadata should contain the following:
```diff
...
+ [[exercises]]
+ name = "yourTopicN"
+ path = "exercises/yourTopic/yourTopicN.rs"
+ mode = "compile"
+ hint = """
+ Some kind of useful hint for your exercise."""
...
```
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`.
That's all! Feel free to put up a pull request.
<a name="issues"></a>
### Issues
You can open an issue [here](https://github.com/rust-lang/rustlings/issues/new).
If you're reporting a bug, please include the output of the following commands:
- `rustc --version`
- `rustlings --version`
- `ls -la`
- Your OS name and version
<a name="prs"></a>
### Pull Requests
Opening a pull request is as easy as forking the repository and committing your
changes. There's a couple of things to watch out for:
#### Write correct commit messages
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
specification, because it makes it easier to generate changelogs automatically.
This means that you have to format your commit messages in a specific way. Say
you're working on adding a new exercise called `foobar1.rs`. You could write
the following commit message:
```
feat: Add foobar1.rs exercise
```
If you're just fixing a bug, please use the `fix` type:
```
fix(verify): Make sure verify doesn't self-destruct
```
The scope within the brackets is optional, but should be any of these:
- `installation` (for the installation script)
- `cli` (for general CLI changes)
- `verify` (for the verification source file)
- `watch` (for the watch functionality source)
- `run` (for the run functionality source)
- `EXERCISENAME` (if you're changing a specific exercise, or set of exercises,
substitute them here)
When the commit also happens to close an existing issue, link it in the message
body:
```
fix: Update foobar
closes #101029908
```
If you're doing simple changes, like updating a book link, use `chore`:
```
chore: Update exercise1.rs book link
```
If you're updating documentation, use `docs`:
```
docs: Add more information to Readme
```
If, and only if, you're absolutely sure you want to make a breaking change
(please discuss this beforehand!), add an exclamation mark to the type and
explain the breaking change in the message body:
```
fix!: Completely change verification
BREAKING CHANGE: This has to be done because lorem ipsum dolor
```
#### Pull Request Workflow
Once you open a Pull Request, it may be reviewed or labeled (or both) until
the maintainers accept your change. Then, [bors](https://github.com/bors) will
run the test suite with your changes and if it's successful, automatically
merge it in!
<a name="4.5.0"></a>
## 4.5.0 (2021-07-07)
#### Features
* Add move_semantics5 exercise. (#746) ([399ab328](https://github.com/rust-lang/rustlings/commit/399ab328d8d407265c09563aa4ef4534b2503ff2))
* **cli:** Add "next" to run the next unsolved exercise. (#785) ([d20e413a](https://github.com/rust-lang/rustlings/commit/d20e413a68772cd493561f2651cf244e822b7ca5))
#### Bug Fixes
* rename result1 to errors4 ([50ab289d](https://github.com/rust-lang/rustlings/commit/50ab289da6b9eb19a7486c341b00048c516b88c0))
* move_semantics5 hints ([1b858285](https://github.com/rust-lang/rustlings/commit/1b85828548f46f58b622b5e0c00f8c989f928807))
* remove trailing whitespaces from iterators1 ([4d4fa774](https://github.com/rust-lang/rustlings/commit/4d4fa77459392acd3581c6068aa8be9a02de12fc))
* add hints to generics1 and generics2 exercises ([31457940](https://github.com/rust-lang/rustlings/commit/31457940846b3844d78d4a4d2b074bc8d6aaf1eb))
* remove trailing whitespace ([d9b69bd1](https://github.com/rust-lang/rustlings/commit/d9b69bd1a0a7a99f2c0d80933ad2eea44c8c71b2))
* **installation:** first PowerShell command ([aa9a943d](https://github.com/rust-lang/rustlings/commit/aa9a943ddf3ae260782e73c26bcc9db60e5894b6))
* **iterators5:** derive Clone, Copy ([91fc9e31](https://github.com/rust-lang/rustlings/commit/91fc9e3118f4af603c9911698cc2a234725cb032))
* **quiz1:** Updated question description (#794) ([d8766496](https://github.com/rust-lang/rustlings/commit/d876649616cc8a8dd5f539f8bc1a5434b960b1e9))
* **try_from_into, from_str:** hints for dyn Error ([11d2cf0d](https://github.com/rust-lang/rustlings/commit/11d2cf0d604dee3f5023c17802d69438e69fa50e))
* **variables5:** confine the answer further ([48ffcbd2](https://github.com/rust-lang/rustlings/commit/48ffcbd2c4cc4d936c2c7480019190f179813cc5))
<a name="4.4.0"></a>
## 4.4.0 (2021-04-24)
#### Bug Fixes
* Fix spelling error in main.rs ([91ee27f2](https://github.com/rust-lang/rustlings/commit/91ee27f22bd3797a9db57e5fd430801c170c5db8))
* typo in default out text ([644c49f1](https://github.com/rust-lang/rustlings/commit/644c49f1e04cbb24e95872b3a52b07d692ae3bc8))
* **collections:** Naming exercises for vectors and hashmap ([bef39b12](https://github.com/rust-lang/rustlings/commit/bef39b125961310b34b34871e480a82e82af4678))
* **from_str:**
* Correct typos ([5f7c89f8](https://github.com/rust-lang/rustlings/commit/5f7c89f85db1f33da01911eaa479c3a2d4721678))
* test for error instead of unwrap/should_panic ([15e71535](https://github.com/rust-lang/rustlings/commit/15e71535f37cfaed36e22eb778728d186e2104ab))
* use trait objects for from_str ([c3e7b831](https://github.com/rust-lang/rustlings/commit/c3e7b831786c9172ed8bd5d150f3c432f242fba9))
* **functions3:** improve function argument type (#687) ([a6509cc4](https://github.com/rust-lang/rustlings/commit/a6509cc4d545d8825f01ddf7ee37823b372154dd))
* **hashmap2:** Update incorrect assertion (#660) ([72aaa15e](https://github.com/rust-lang/rustlings/commit/72aaa15e6ab4b72b3422f1c6356396e20a2a2bb8))
* **info:** Fix typo (#635) ([cddc1e86](https://github.com/rust-lang/rustlings/commit/cddc1e86e7ec744ee644cc774a4887b1a0ded3e8))
* **iterators2:** Moved errors out of tests. ([baf4ba17](https://github.com/rust-lang/rustlings/commit/baf4ba175ba6eb92989e3dd54ecbec4bedc9a863), closes [#359](https://github.com/rust-lang/rustlings/issues/359))
* **iterators3:** Enabled iterators3.rs to run without commented out tests. ([c6712dfc](https://github.com/rust-lang/rustlings/commit/c6712dfccd1a093e590ad22bbc4f49edc417dac0))
* **main:** Let find_exercise work with borrows ([347f30bd](https://github.com/rust-lang/rustlings/commit/347f30bd867343c5ace1097e085a1f7e356553f7))
* **move_semantics4:**
* Remove redundant "instead" (#640) ([cc266d7d](https://github.com/rust-lang/rustlings/commit/cc266d7d80b91e79df3f61984f231b7f1587218e))
* Small readbility improvement (#617) ([10965920](https://github.com/rust-lang/rustlings/commit/10965920fbdf8a1efc85bed869e55a1787006404))
* **option2:** Rename uninformative variables (#675) ([b4de6594](https://github.com/rust-lang/rustlings/commit/b4de6594380636817d13c2677ec6f472a964cf43))
* **quiz3:** Force an answer to Q2 (#672) ([0d894e6f](https://github.com/rust-lang/rustlings/commit/0d894e6ff739943901e1ae8c904582e5c2f843bd))
* **structs:** Add 5.3 to structs/README (#652) ([6bd791f2](https://github.com/rust-lang/rustlings/commit/6bd791f2f44aa7f0ad926df767f6b1fa8f12a9a9))
* **structs2:** correct grammar in hint (#663) ([ebdb66c7](https://github.com/rust-lang/rustlings/commit/ebdb66c7bfb6d687a14cc511a559a222e6fc5de4))
* **structs3:**
* reword heading comment (#664) ([9f3e8c2d](https://github.com/rust-lang/rustlings/commit/9f3e8c2dde645e5264c2d2200e68842b5f47bfa3))
* add check to prevent naive implementation of is_international ([05a753fe](https://github.com/rust-lang/rustlings/commit/05a753fe6333d36dbee5f68c21dec04eacdc75df))
* **threads1:** line number correction ([7857b0a6](https://github.com/rust-lang/rustlings/commit/7857b0a689b0847f48d8c14cbd1865e3b812d5ca))
* **try_from_into:** use trait objects ([2e93a588](https://github.com/rust-lang/rustlings/commit/2e93a588e0abe8badb7eafafb9e7d073c2be5df8))
#### Features
* Replace clap with argh ([7928122f](https://github.com/rust-lang/rustlings/commit/7928122fcef9ca7834d988b1ec8ca0687478beeb))
* Replace emojis when NO_EMOJI env variable present ([8d62a996](https://github.com/rust-lang/rustlings/commit/8d62a9963708dbecd9312e8bcc4b47049c72d155))
* Added iterators5.rs exercise. ([b29ea17e](https://github.com/rust-lang/rustlings/commit/b29ea17ea94d1862114af2cf5ced0e09c197dc35))
* **arc1:** Add more details to description and hint (#710) ([81be4044](https://github.com/rust-lang/rustlings/commit/81be40448777fa338ebced3b0bfc1b32d6370313))
* **cli:** Improve the list command with options, and then some ([8bbe4ff1](https://github.com/rust-lang/rustlings/commit/8bbe4ff1385c5c169c90cd3ff9253f9a91daaf8e))
* **list:**
* updated progress percentage ([1c6f7e4b](https://github.com/rust-lang/rustlings/commit/1c6f7e4b7b9b3bd36f4da2bb2b69c549cc8bd913))
* added progress info ([c0e3daac](https://github.com/rust-lang/rustlings/commit/c0e3daacaf6850811df5bc57fa43e0f249d5cfa4))
<a name="4.3.0"></a>
## 4.3.0 (2020-12-29)
#### Features
* Rewrite default out text ([44d39112](https://github.com/rust-lang/rustlings/commit/44d39112ff122b29c9793fe52e605df1612c6490))
* match exercise order to book chapters (#541) ([033bf119](https://github.com/rust-lang/rustlings/commit/033bf1198fc8bfce1b570e49da7cde010aa552e3))
* Crab? (#586) ([fa9f522b](https://github.com/rust-lang/rustlings/commit/fa9f522b7f043d7ef73a39f003a9272dfe72c4f4))
* add "rustlings list" command ([838f9f30](https://github.com/rust-lang/rustlings/commit/838f9f30083d0b23fd67503dcf0fbeca498e6647))
* **try_from_into:** remove duplicate annotation ([04f1d079](https://github.com/rust-lang/rustlings/commit/04f1d079aa42a2f49af694bc92c67d731d31a53f))
#### Bug Fixes
* update structs README ([bcf14cf6](https://github.com/rust-lang/rustlings/commit/bcf14cf677adb3a38a3ac3ca53f3c69f61153025))
* added missing exercises to info.toml ([90cfb6ff](https://github.com/rust-lang/rustlings/commit/90cfb6ff28377531bfc34acb70547bdb13374f6b))
* gives a bit more context to magic number ([30644c9a](https://github.com/rust-lang/rustlings/commit/30644c9a062b825c0ea89435dc59f0cad86b110e))
* **functions2:** Change signature to trigger precise error message: (#605) ([0ef95947](https://github.com/rust-lang/rustlings/commit/0ef95947cc30482e63a7045be6cc2fb6f6dcb4cc))
* **structs1:** Adjust wording (#573) ([9334783d](https://github.com/rust-lang/rustlings/commit/9334783da31d821cc59174fbe8320df95828926c))
* **try_from_into:**
* type error ([4f4cfcf3](https://github.com/rust-lang/rustlings/commit/4f4cfcf3c36c8718c7c170c9c3a6935e6ef0618c))
* Update description (#584) ([96347df9](https://github.com/rust-lang/rustlings/commit/96347df9df294f01153b29d9ad4ba361f665c755))
* **vec1:** Have test compare every element in a and v ([9b6c6293](https://github.com/rust-lang/rustlings/commit/9b6c629397b24b944f484f5b2bbd8144266b5695))
<a name="4.2.0"></a>
## 4.2.0 (2020-11-07)
#### Features
* Add HashMap exercises ([633c00cf](https://github.com/rust-lang/rustlings/commit/633c00cf8071e1e82959a3010452a32f34f29fc9))
* Add Vec exercises ([0c12fa31](https://github.com/rust-lang/rustlings/commit/0c12fa31c57c03c6287458a0a8aca7afd057baf6))
* **primitive_types6:** Add a test (#548) ([2b1fb2b7](https://github.com/rust-lang/rustlings/commit/2b1fb2b739bf9ad8d6b7b12af25fee173011bfc4))
* **try_from_into:** Add tests (#571) ([95ccd926](https://github.com/rust-lang/rustlings/commit/95ccd92616ae79ba287cce221101e0bbe4f68cdc))
#### Bug Fixes
* log error output when inotify limit is exceeded ([d61b4e5a](https://github.com/rust-lang/rustlings/commit/d61b4e5a13b44d72d004082f523fa1b6b24c1aca))
* more unique temp_file ([5643ef05](https://github.com/rust-lang/rustlings/commit/5643ef05bc81e4a840e9456f4406a769abbe1392))
* **installation:** Update the MinRustVersion ([21bfb2d4](https://github.com/rust-lang/rustlings/commit/21bfb2d4777429c87d8d3b5fbf0ce66006dcd034))
* **iterators2:** Update description (#578) ([197d3a3d](https://github.com/rust-lang/rustlings/commit/197d3a3d8961b2465579218a6749b2b2cefa8ddd))
* **primitive_types6:**
* remove 'unused doc comment' warning ([472d8592](https://github.com/rust-lang/rustlings/commit/472d8592d65c8275332a20dfc269e7ac0d41bc88))
* missing comma in test ([4fb230da](https://github.com/rust-lang/rustlings/commit/4fb230daf1251444fcf29e085cee222a91f8a37e))
* **quiz3:** Second test is for odd numbers, not even. (#553) ([18e0bfef](https://github.com/rust-lang/rustlings/commit/18e0bfef1de53071e353ba1ec5837002ff7290e6))
<a name="4.1.0"></a>
## 4.1.0 (2020-10-05)
#### Bug Fixes
* Update rustlings version in Cargo.lock ([1cc40bc9](https://github.com/rust-lang/rustlings/commit/1cc40bc9ce95c23d56f6d91fa1c4deb646231fef))
* **arc1:** index mod should equal thread count ([b4062ef6](https://github.com/rust-lang/rustlings/commit/b4062ef6993e80dac107c4093ea85166ad3ee0fa))
* **enums3:** Update Message::ChangeColor to take a tuple. (#457) ([4b6540c7](https://github.com/rust-lang/rustlings/commit/4b6540c71adabad647de8a09e57295e7c7c7d794))
* **exercises:** adding question mark to quiz2 ([101072ab](https://github.com/rust-lang/rustlings/commit/101072ab9f8c80b40b8b88cb06cbe38aca2481c5))
* **generics3:** clarify grade change ([47f7672c](https://github.com/rust-lang/rustlings/commit/47f7672c0307732056e7426e81d351f0dd7e22e5))
* **structs3:** Small adjustment of variable name ([114b54cb](https://github.com/rust-lang/rustlings/commit/114b54cbdb977234b39e5f180d937c14c78bb8b2))
* **using_as:** Add test so that proper type is returned. (#512) ([3286c5ec](https://github.com/rust-lang/rustlings/commit/3286c5ec19ea5fb7ded81d047da5f8594108a490))
#### Features
* Added iterators1.rs exercise ([9642f5a3](https://github.com/rust-lang/rustlings/commit/9642f5a3f686270a4f8f6ba969919ddbbc4f7fdd))
* Add ability to run rustlings on repl.it (#471) ([8f7b5bd0](https://github.com/rust-lang/rustlings/commit/8f7b5bd00eb83542b959830ef55192d2d76db90a))
* Add gitpod support (#473) ([4821a8be](https://github.com/rust-lang/rustlings/commit/4821a8be94af4f669042a06ab917934cfacd032f))
* Remind the user of the hint option (#425) ([816b1f5e](https://github.com/rust-lang/rustlings/commit/816b1f5e85d6cc6e72673813a85d0ada2a8f84af))
* Remind the user of the hint option (#425) ([9f61db5d](https://github.com/rust-lang/rustlings/commit/9f61db5dbe38538cf06571fcdd5f806e7901e83a))
* **cli:** Added 'cls' command to 'watch' mode (#474) ([4f2468e1](https://github.com/rust-lang/rustlings/commit/4f2468e14f574a93a2e9b688367b5752ed96ae7b))
* **try_from_into:** Add insufficient length test (#469) ([523d18b8](https://github.com/rust-lang/rustlings/commit/523d18b873a319f7c09262f44bd40e2fab1830e5))
<a name="4.0.0"></a>
## 4.0.0 (2020-07-08)
#### Breaking Changes
* Add a --nocapture option to display test harnesses' outputs ([8ad5f9bf](https://github.com/rust-lang/rustlings/commit/8ad5f9bf531a4848b1104b7b389a20171624c82f))
* Rename test to quiz, fixes #244 ([010a0456](https://github.com/rust-lang/rustlings/commit/010a04569282149cea7f7a76fc4d7f4c9f0f08dd))
#### Features
* Add traits README ([173bb141](https://github.com/rust-lang/rustlings/commit/173bb14140c5530cbdb59e53ace3991a99d804af))
* Add box1.rs exercise ([7479a473](https://github.com/rust-lang/rustlings/commit/7479a4737bdcac347322ad0883ca528c8675e720))
* Rewrite try_from_into (#393) ([763aa6e3](https://github.com/rust-lang/rustlings/commit/763aa6e378a586caae2d8d63755a85eeba227933))
* Add if2 exercise ([1da84b5f](https://github.com/rust-lang/rustlings/commit/1da84b5f7c489f65bd683c244f13c7d1ee812df0))
* Added exercise structs3.rs ([b66e2e09](https://github.com/rust-lang/rustlings/commit/b66e2e09622243e086a0f1258dd27e1a2d61c891))
* Add exercise variables6 covering const (#352) ([5999acd2](https://github.com/rust-lang/rustlings/commit/5999acd24a4f203292be36e0fd18d385887ec481))
#### Bug Fixes
* Change then to than ([ddd98ad7](https://github.com/rust-lang/rustlings/commit/ddd98ad75d3668fbb10eff74374148aa5ed2344d))
* rename quiz1 to tests1 in info (#420) ([0dd1c6ca](https://github.com/rust-lang/rustlings/commit/0dd1c6ca6b389789e0972aa955fe17aa15c95f29))
* fix quiz naming inconsistency (#421) ([5563adbb](https://github.com/rust-lang/rustlings/commit/5563adbb890587fc48fbbc9c4028642687f1e85b))
* confine the user further in variable exercises ([06ef4cc6](https://github.com/rust-lang/rustlings/commit/06ef4cc654e75d22a526812919ee49b8956280bf))
* update iterator and macro text for typos and clarity ([95900828](https://github.com/rust-lang/rustlings/commit/959008284834bece0196a01e17ac69a7e3590116))
* update generics2 closes #362 ([964c974a](https://github.com/rust-lang/rustlings/commit/964c974a0274199d755073b917c2bc5da0c9b4f1))
* confusing comment in conversions/try_from_into.rs ([c9e4f2cf](https://github.com/rust-lang/rustlings/commit/c9e4f2cfb4c48d0b7451263cfb43b9426438122d))
* **arc1:** Passively introduce attributes (#429) ([113cdae2](https://github.com/rust-lang/rustlings/commit/113cdae2d4e4c55905e8056ad326ede7fd7de356))
* **box1:** fix comment typo (#426) ([bb2ca251](https://github.com/rust-lang/rustlings/commit/bb2ca251106b27a7272d9a30872904dd1376654c))
* **errorsn:** Try harder to confine the user. (#388) ([2b20c8a0](https://github.com/rust-lang/rustlings/commit/2b20c8a0f5774d07c58d110d75879f33fc6273b5))
* **from_into.rs:** typo ([a901499e](https://github.com/rust-lang/rustlings/commit/a901499ededd3ce1995164700514fe4e9a0373ea))
* **generics2:** Guide students to the answer (#430) ([e6bd8021](https://github.com/rust-lang/rustlings/commit/e6bd8021d9a7dd06feebc30c9d5f953901d7b419))
* **installation:**
* Provide a backup git reference when tag can't be curl ([9e4fb100](https://github.com/rust-lang/rustlings/commit/9e4fb1009f1c9e3433915c03e22c2af422e5c5fe))
* Check if python is available while checking for git,rustc and cargo ([9cfb617d](https://github.com/rust-lang/rustlings/commit/9cfb617d5b0451b4b51644a1298965390cda9884))
* **option1:**
* Don't add only zeros to the numbers array ([cce6a442](https://github.com/rust-lang/rustlings/commit/cce6a4427718724a9096800754cd3abeca6a1580))
* Add cast to usize, as it is confusing in the context of an exercise about Option ([f6cffc7e](https://github.com/rust-lang/rustlings/commit/f6cffc7e487b42f15a6f958e49704c93a8d4465b))
* **option2:** Add TODO to comments (#400) ([10967bce](https://github.com/rust-lang/rustlings/commit/10967bce57682812dc0891a9f9757da1a9d87404))
* **options1:** Add hint about Array Initialization (#389) ([9f75554f](https://github.com/rust-lang/rustlings/commit/9f75554f2a30295996f03f0160b98c0458305502))
* **test2:** name of type String and &str (#394) ([d6c0a688](https://github.com/rust-lang/rustlings/commit/d6c0a688e6a96f93ad60d540d4b326f342fc0d45))
* **variables6:** minor typo (#419) ([524e17df](https://github.com/rust-lang/rustlings/commit/524e17df10db95f7b90a0f75cc8997182a8a4094))
<a name="3.0.0"></a>
## 3.0.0 (2020-04-11)
#### Breaking Changes
* make "compile" exercises print output (#278) ([3b6d5c](https://github.com/fmoko/rustlings/commit/3b6d5c3aaa27a242a832799eb66e96897d26fde3))
#### Bug Fixes
* **primitive_types:** revert primitive_types4 (#296) ([b3a3351e](https://github.com/rust-lang/rustlings/commit/b3a3351e8e6a0bdee07077d7b0382953821649ae))
* **run:** compile clippy exercise files (#295) ([3ab084a4](https://github.com/rust-lang/rustlings/commit/3ab084a421c0f140ae83bf1fc3f47b39342e7373))
* **conversions:**
* add additional test to meet exercise rules (#284) ([bc22ec3](https://github.com/fmoko/rustlings/commit/bc22ec382f843347333ef1301fc1bad773657f38))
* remove duplicate not done comment (#292) ([dab90f](https://github.com/fmoko/rustlings/commit/dab90f7b91a6000fe874e3d664f244048e5fa342))
* don't hardcode documentation version for traits (#288) ([30e6af](https://github.com/fmoko/rustlings/commit/30e6af60690c326fb5d3a9b7335f35c69c09137d))
#### Features
* add Option2 exercise (#290) ([86b5c08b](https://github.com/rust-lang/rustlings/commit/86b5c08b9bea1576127a7c5f599f5752072c087d))
* add excercise for option (#282) ([135e5d47](https://github.com/rust-lang/rustlings/commit/135e5d47a7c395aece6f6022117fb20c82f2d3d4))
* add new exercises for generics (#280) ([76be5e4e](https://github.com/rust-lang/rustlings/commit/76be5e4e991160f5fd9093f03ee2ba260e8f7229))
* **ci:** add buildkite config ([b049fa2c](https://github.com/rust-lang/rustlings/commit/b049fa2c84dba0f0c8906ac44e28fd45fba51a71))
<a name="2.2.1"></a>
### 2.2.1 (2020-02-27)
#### Bug Fixes
* Re-add cloning the repo to install scripts ([3d9b03c5](https://github.com/rust-lang/rustlings/commit/3d9b03c52b8dc51b140757f6fd25ad87b5782ef5))
#### Features
* Add clippy lints (#269) ([1e2fd9c9](https://github.com/rust-lang/rustlings/commit/1e2fd9c92f8cd6e389525ca1a999fca4c90b5921))
<a name="2.2.0"></a>
## 2.2.0 (2020-02-25)
#### Bug Fixes
* Update deps to version compatable with aarch64-pc-windows (#263) ([19a93428](https://github.com/rust-lang/rustlings/commit/19a93428b3c73d994292671f829bdc8e5b7b3401))
* **docs:**
* Added a necessary step to Windows installation process (#242) ([3906efcd](https://github.com/rust-lang/rustlings/commit/3906efcd52a004047b460ed548037093de3f523f))
* Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9))
* Updated iterators readme to account for iterators4 exercise (#273) ([bec8e3a](https://github.com/rust-lang/rustlings/commit/bec8e3a644cbd88db1c73ea5f1d8a364f4a34016))
* **installation:** make fatal errors more obvious (#272) ([17d0951e](https://github.com/rust-lang/rustlings/commit/17d0951e66fda8e11b204d5c4c41a0d5e22e78f7))
* **iterators2:**
* Remove reference to missing iterators2.rs (#245) ([419f7797](https://github.com/rust-lang/rustlings/commit/419f7797f294e4ce6a2b883199731b5bde77d262))
* **as_ref_mut:** Enable a test and improve per clippy's suggestion (#256) ([dfdf809](https://github.com/rust-lang/rustlings/commit/dfdf8093ebbd4145864995627b812780de52f902))
* **tests1:**
* Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce)
* Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf))
#### Features
* Add variables5.rs exercise (#264) ([0c73609e](https://github.com/rust-lang/rustlings/commit/0c73609e6f2311295e95d6f96f8c747cfc4cba03))
* Show a completion message when watching (#253) ([d25ee55a](https://github.com/rust-lang/rustlings/commit/d25ee55a3205882d35782e370af855051b39c58c))
* Add type conversion and parsing exercises (#249) ([0c85dc11](https://github.com/rust-lang/rustlings/commit/0c85dc1193978b5165491b99cc4922caf8d14a65))
* Created consistent money unit (#258) ([fd57f8f](https://github.com/rust-lang/rustlings/commit/fd57f8f2c1da2af8ddbebbccec214e6f40f4dbab))
* Enable test for exercise test4 (#276) ([8b971ff](https://github.com/rust-lang/rustlings/commit/8b971ffab6079a706ac925f5917f987932b55c07))
* Added traits exercises (#274 but specifically #216, which originally added
this :heart:) ([b559cdd](https://github.com/rust-lang/rustlings/commit/b559cdd73f32c0d0cfc1feda39f82b3e3583df17))
<a name="2.1.0"></a>
## 2.1.0 (2019-11-27)
#### Bug Fixes
* add line numbers in several exercises and hints ([b565c4d3](https://github.com/rust-lang/rustlings/commit/b565c4d3e74e8e110bef201a082fa1302722a7c3))
* **arc1:** Fix some words in the comment ([c42c3b21](https://github.com/rust-lang/rustlings/commit/c42c3b2101df9164c8cd7bb344def921e5ba3e61))
* **enums:** Add link to chapter on pattern syntax (#242) ([615ce327](https://github.com/rust-lang/rustlings/commit/615ce3279800c56d89f19d218ccb7ef576624feb))
* **primitive_types4:**
* update outdated hint ([4c5189df](https://github.com/rust-lang/rustlings/commit/4c5189df2bdd9a231f6b2611919ba5aa14da0d3f))
* update outdated comment ([ded2c034](https://github.com/rust-lang/rustlings/commit/ded2c034ba93fa1e3c2c2ea16b83abc1a57265e8))
* **strings2:** update line number in hint ([a09f684f](https://github.com/rust-lang/rustlings/commit/a09f684f05c58d239a6fc59ec5f81c2533e8b820))
* **variables1:** Correct wrong word in comment ([fda5a470](https://github.com/rust-lang/rustlings/commit/fda5a47069e0954f16a04e8e50945e03becb71a5))
#### Features
* **watch:** show hint while watching ([8143d57b](https://github.com/rust-lang/rustlings/commit/8143d57b4e88c51341dd4a18a14c536042cc009c))
<a name="2.0.0"></a>
## 2.0.0 (2019-11-12)
#### Bug Fixes
* **default:** Clarify the installation procedure ([c371b853](https://github.com/rust-lang/rustlings/commit/c371b853afa08947ddeebec0edd074b171eeaae0))
* **info:** Fix trailing newlines for hints ([795b6e34](https://github.com/rust-lang/rustlings/commit/795b6e348094a898e9227a14f6232f7bb94c8d31))
* **run:** make `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
#### Breaking Changes
* Refactor hint system ([9bdb0a12](https://github.com/rust-lang/rustlings/commit/9bdb0a12e45a8e9f9f6a4bd4a9c172c5376c7f60))
* improve `watch` execution mode ([2cdd6129](https://github.com/rust-lang/rustlings/commit/2cdd61294f0d9a53775ee24ad76435bec8a21e60))
* Index exercises by name ([627cdc07](https://github.com/rust-lang/rustlings/commit/627cdc07d07dfe6a740e885e0ddf6900e7ec336b))
* **run:** makes `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
#### Features
* **cli:** check for rustc before doing anything ([36a033b8](https://github.com/rust-lang/rustlings/commit/36a033b87a6549c1e5639c908bf7381c84f4f425))
* **hint:** Add test for hint ([ce9fa6eb](https://github.com/rust-lang/rustlings/commit/ce9fa6ebbfdc3e7585d488d9409797285708316f))
<a name="1.5.1"></a>
### 1.5.1 (2019-11-11)
#### Bug Fixes
* **errors3:** Update hint ([dcfb427b](https://github.com/rust-lang/rustlings/commit/dcfb427b09585f0193f0a294443fdf99f11c64cb), closes [#185](https://github.com/rust-lang/rustlings/issues/185))
* **if1:** Remove `return` reference ([ad03d180](https://github.com/rust-lang/rustlings/commit/ad03d180c9311c0093e56a3531eec1a9a70cdb45))
* **strings:** Move Strings before Structs ([6dcecb38](https://github.com/rust-lang/rustlings/commit/6dcecb38a4435593beb87c8e12d6314143631482), closes [#204](https://github.com/rust-lang/rustlings/issues/204))
* **structs1:** Remove misleading comment ([f72e5a8f](https://github.com/rust-lang/rustlings/commit/f72e5a8f05568dde04eaeac10b9a69872f21cb37))
* **threads:** Move Threads behind SLT ([fbe91a67](https://github.com/rust-lang/rustlings/commit/fbe91a67a482bfe64cbcdd58d06ba830a0f39da3), closes [#205](https://github.com/rust-lang/rustlings/issues/205))
* **watch:** clear screen before each `verify()` ([3aff590](https://github.com/rust-lang/rustlings/commit/3aff59085586c24196a547c2693adbdcf4432648))
<a name="1.5.0"></a>
## 1.5.0 (2019-11-09)
#### Bug Fixes
* **test1:** Rewrite logic ([79a56942](https://github.com/rust-lang/rustlings/commit/79a569422c8309cfc9e4aed25bf4ab3b3859996b))
* **installation:** Fix rustlings installation check ([7a252c47](https://github.com/rust-lang/rustlings/commit/7a252c475551486efb52f949b8af55803b700bc6))
* **iterators:** Rename iterator3.rs ([433d2115](https://github.com/rust-lang/rustlings/commit/433d2115bc1c04b6d34a335a18c9a8f3e2672bc6))
* **iterators2:** Remove syntax resulting in misleading error message ([4cde8664](https://github.com/rust-lang/rustlings/commit/4cde86643e12db162a66e62f23b78962986046ac))
* **option1:**
* Fix arguments passed to assert! macro (#222) ([4c2cf6da](https://github.com/rust-lang/rustlings/commit/4c2cf6da755efe02725e05ecc3a303304c10a6da))
* Fix arguments passed to assert! macro ([ead4f7af](https://github.com/rust-lang/rustlings/commit/ead4f7af9e10e53418efdde5c359159347282afd))
* Add test for prematurely passing exercise ([a750e4a1](https://github.com/rust-lang/rustlings/commit/a750e4a1a3006227292bb17d57d78ce84da6bfc6))
* **primitive_types4:** Fail on a slice covering the wrong area ([5b1e673c](https://github.com/rust-lang/rustlings/commit/5b1e673cec1658afc4ebbbc800213847804facf5))
* **readme:** http to https ([70946b85](https://github.com/rust-lang/rustlings/commit/70946b85e536e80e70ed9505cb650ca0a3a1fbb5))
* **test1:**
* Swap assertion parameter order ([4086d463](https://github.com/rust-lang/rustlings/commit/4086d463a981e81d97781851d17db2ced290f446))
* renamed function name to snake case closes #180 ([89d5186c](https://github.com/rust-lang/rustlings/commit/89d5186c0dae8135ecabf90ee8bb35949bc2d29b))
#### Features
* Add enums exercises ([dc150321](https://github.com/rust-lang/rustlings/commit/dc15032112fc485226a573a18139e5ce928b1755))
* Added exercise for struct update syntax ([1c4c8764](https://github.com/rust-lang/rustlings/commit/1c4c8764ed118740cd4cee73272ddc6cceb9d959))
* **iterators2:** adds iterators2 exercise including config ([9288fccf](https://github.com/rust-lang/rustlings/commit/9288fccf07a2c5043b76d0fd6491e4cf72d76031))
<a name="1.4.1"></a>
### 1.4.1 (2019-08-13)
#### Bug Fixes
* **iterators2:** Remove syntax resulting in misleading error message ([4cde8664](https://github.com/rust-lang/rustlings/commit/4cde86643e12db162a66e62f23b78962986046ac))
* **option1:** Add test for prematurely passing exercise ([a750e4a1](https://github.com/rust-lang/rustlings/commit/a750e4a1a3006227292bb17d57d78ce84da6bfc6))
* **test1:** Swap assertion parameter order ([4086d463](https://github.com/rust-lang/rustlings/commit/4086d463a981e81d97781851d17db2ced290f446))
<a name="1.4.0"></a>
## 1.4.0 (2019-07-13)
#### Bug Fixes
* **installation:** Fix rustlings installation check ([7a252c47](https://github.com/rust-lang/rustlings/commit/7a252c475551486efb52f949b8af55803b700bc6))
* **iterators:** Rename iterator3.rs ([433d2115](https://github.com/rust-lang/rustlings/commit/433d2115bc1c04b6d34a335a18c9a8f3e2672bc6))
* **readme:** http to https ([70946b85](https://github.com/rust-lang/rustlings/commit/70946b85e536e80e70ed9505cb650ca0a3a1fbb5))
* **test1:** renamed function name to snake case ([89d5186c](https://github.com/rust-lang/rustlings/commit/89d5186c0dae8135ecabf90ee8bb35949bc2d29b))
* **cli:** Check if changed exercise file exists before calling verify ([ba85ca3](https://github.com/rust-lang/rustlings/commit/ba85ca32c4cfc61de46851ab89f9c58a28f33c88))
* **structs1:** Fix the irrefutable let pattern warning ([cc6a141](https://github.com/rust-lang/rustlings/commit/cc6a14104d7c034eadc98297eaaa972d09c50b1f))
#### Features
* **changelog:** Use clog for changelogs ([34e31232](https://github.com/rust-lang/rustlings/commit/34e31232dfddde284a341c9609b33cd27d9d5724))
* **iterators2:** adds iterators2 exercise including config ([9288fccf](https://github.com/rust-lang/rustlings/commit/9288fccf07a2c5043b76d0fd6491e4cf72d76031))
<a name="1.3.0"></a>
### 1.3.0 (2019-06-05)
#### Features
- Adds a simple exercise for structures (#163, @briankung)
#### Bug Fixes
- Add Result type signature as it is difficult for new comers to understand Generics and Error all at once. (#157, @veggiemonk)
- Rustfmt and whitespace fixes (#161, @eddyp)
- errorsn.rs: Separate also the hints from each other to avoid accidental viewing (#162, @eddyp)
- fixed outdated links (#165, @gushroom)
- Fix broken link (#164, @HanKruiger)
- Remove highlighting and syntect (#167, @komaeda)
<a name="1.2.2"></a>
### 1.2.2 (2019-05-07)
#### Bug Fixes
- Reverted `--nocapture` flag since it was causing tests to pass unconditionally
<a name="1.2.1"></a>
### 1.2.1 (2019-04-22)
#### Bug Fixes
- Fix the `--nocapture` feature (@komaeda)
- Provide a nicer error message for when you're in the wrong directory
<a name="1.2.0"></a>
### 1.2.0 (2019-04-22)
#### Features
- Add errors to exercises that compile without user changes (@yvan-sraka)
- Use --nocapture when testing, enabling `println!` when running (@komaeda)
<a name="1.1.1"></a>
### 1.1.1 (2019-04-14)
#### Bug fixes
- Fix permissions on exercise files (@zacanger, #133)
- Make installation checks more thorough (@komaeda, 1b3469f236bc6979c27f6e1a04e4138a88e55de3)
- Fix order of true/false in tests for executables (@mgeier, #137)
- Stop run from panicking when compile fails (@cjpearce, #141)
- Fix intermittent test failure caused by race condition (@cjpearce, #140)
- Fix links by deleting book version (@diodfr, #142)
- Canonicalize paths to fix path matching (@cjpearce, #143)
<a name="1.1.0"></a>
### 1.1.0 (2019-03-20)
- errors2.rs: update link to Rust book (#124)
- Start verification at most recently modified file (#120)
- Watch for file creation events in watch mode (#117)
- Add standard library types to exercises suite (#119)
- Give a warning when Rustlings isn't run from the right directory (#123)
- Verify that rust version is recent enough to install Rustlings (#131)
<a name="1.0.1"></a>
### 1.0.1 (2019-03-06)
- Adds a way to install Rustlings in one command (`curl -L https://git.io/rustlings | bash`)
- Makes `rustlings watch` react to create file events (@shaunbennett, #117)
- Reworks the exercise management to use an external TOML file instead of just listing them in the code
<a name="1.0.0"></a>
### 1.0.0 (2019-03-06)
Initial release.