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 DONEfn 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_exercisefn 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 Exercisepub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> {compile_and_test(exercise, RunMode::NonInteractive, verbose)?;Ok(())}// Invoke the rust compiler without running the resulting binaryfn 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 modefn 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 truefn 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 compilationfn 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 displayedfn 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 versionconst 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 codestruct 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 orderstruct VerifyArgs {}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand, name = "watch")]/// Reruns `verify` when files were editedstruct WatchArgs {}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand, name = "run")]/// Runs/Tests a single exercisestruct RunArgs {#[argh(positional)]/// the name of the exercisename: String,}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand, name = "hint")]/// Returns a hint for the given exercisestruct HintArgs {#[argh(positional)]/// the name of the exercisename: String,}#[derive(FromArgs, PartialEq, Debug)]#[argh(subcommand, name = "list")]/// Lists the exercises available in Rustlingsstruct ListArgs {#[argh(switch, short = 'p')]/// show only the paths of the exercisespaths: bool,#[argh(switch, short = 'n')]/// show only the names of the exercisesnames: bool,#[argh(option, short = 'f')]/// provide a string to match exercise names/// comma separated patterns are acceptablefilter: Option<String>,#[argh(switch, short = 'u')]/// display only exercises not yet solvedunsolved: bool,#[argh(switch, short = 's')]/// display only exercises that have been solvedsolved: 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 anywaylet 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 binaryCompile,// Indicates that the exercise should be compiled as a test harnessTest,// Indicates that the exercise should be linted with clippyClippy,}#[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 exercisepub name: String,// The path to the file containing the exercise's source codepub path: PathBuf,// The mode of the exercise (Test, Compile, or Clippy)pub mode: Mode,// The hint text associated with the exercisepub 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 completedDone,// The state of the exercise while it's not completed yetPending(Vec<ContextLine>),}// The context information of a pending exercise#[derive(PartialEq, Debug)]pub struct ContextLine {// The source code that is still pending completionpub line: String,// The line number of the source code still pending completionpub number: usize,// Whether or not this is importantpub important: bool,}// The result of compiling an exercisepub struct CompiledExercise<'a> {exercise: &'a Exercise,_handle: FileHandle,}impl<'a> CompiledExercise<'a> {// Run the compiled exercisepub 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 binarypub stdout: String,// The textual contents of the standard error of the binarypub 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/3837Command::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 counterintuitivepub 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 bashecho "Let's get you set up with Rustlings!"echo "Checking requirements..."if [ -x "$(command -v git)" ]thenecho "SUCCESS: Git is installed"elseecho "ERROR: Git does not seem to be installed."echo "Please download Git using your package manager or over https://git-scm.com/!"exit 1fiif [ -x "$(command -v rustc)" ]thenecho "SUCCESS: Rust is installed"elseecho "ERROR: Rust does not seem to be installed."echo "Please download Rust using https://rustup.rs!"exit 1fiif [ -x "$(command -v cargo)" ]thenecho "SUCCESS: Cargo is installed"elseecho "ERROR: Cargo does not seem to be installed."echo "Please download Rust and Cargo using https://rustup.rs!"exit 1fi# Look up python installations, starting with 3 with a fallback of 2if [ -x "$(command -v python3)" ]thenPY="$(command -v python3)"elif [ -x "$(command -v python)" ]thenPY="$(command -v python)"elif [ -x "$(command -v python2)" ]thenPY="$(command -v python2)"elseecho "ERROR: No working python installation was found"echo "Please install python and add it to the PATH variable"exit 1fi# 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 ]]thenreturn 0fiv1=( ${1//./ } )v2=( ${2//./ } )len1=${#v1[@]}len2=${#v2[@]}max_len=$len1if [[ $max_len -lt $len2 ]]thenmax_len=$len2fifor i in `seq 0 $max_len`do# Fill empty fields with zeros in v1if [ -z "${v1[$i]}" ]thenv1[$i]=0fi# And in v2if [ -z "${v2[$i]}" ]thenv2[$i]=0fiif [ ${v1[$i]} -gt ${v2[$i]} ]thenreturn 1fiif [ ${v1[$i]} -lt ${v2[$i]} ]thenreturn 2fidonereturn 0}RustVersion=$(rustc --version | cut -d " " -f 2)MinRustVersion=1.39vercomp $RustVersion $MinRustVersionif [ $? -eq 2 ]thenecho "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion"echo "Please update Rust with 'rustup update'"exit 1elseecho "SUCCESS: Rust is up to date"fiPath=${1:-rustlings/}echo "Cloning Rustlings at $Path..."git clone -q https://github.com/rust-lang/rustlings $Pathcd $PathVersion=$(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} ]]thenecho "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} ]]thenecho "No valid tag version found"echo "Rustlings will be installed using the main branch"Version="main"elseVersion="tags/${Version}"fielseVersion="tags/${Version}"fiecho "Checking out version $Version..."git checkout -q ${Version}echo "Installing the 'rustlings' executable..."cargo install --force --path .if ! [ -x "$(command -v rustlings)" ]thenecho "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/1514Clippy=$(rustup component list | grep "clippy" | grep "installed")if [ -z "$Clippy" ]thenecho "Installing the 'cargo-clippy' executable..."rustup component add clippyfiecho "All done! Run 'rustlings' to get started."
#!/usr/bin/env pwsh#Requires -Version 5param($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 $pathif (!($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_nameWrite-Host "Checking out version $version..."Set-Location $pathgit checkout -q tags/$versionWrite-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-Stringif (!$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 Rustto 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 thevariable 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 tryingto reassign a different value to x! There's a keyword we can use to makea 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 online 7, and we're trying to use it on line 8, but we haven't given it avalue. 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 anyprogramming 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 mutableusing a special keyword. Unfortunately this doesn't help us much in this exercisebecause we want to assign a different typed value to an existing variable. Sometimesyou may also like to reuse existing variable names because you are just convertingvalues 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#shadowingTry 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 ofvariable available; constants.Constants are always immutable and they are declared with keyword 'const' ratherthan 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 thefunction 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 wrongwith 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 atthe `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 returna 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 conditionalblock return the same type! To get the tests passing, you will need a coupleconditions 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 13where 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 online 10, which means it gets dropped at the end of `fill_vec`, which means wecan'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 themall!1. Make another, separate version of the data that's in `vec0` and pass thatto `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 bemutable), modify it directly, then not return anything. Then you can get ridof `vec1` entirely -- note that this will change what gets printed by thefirst `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 lineof `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 changean 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 trydoing 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 shouldreflect that it does not take any arguments- since we're not creating a new vec in `main` anymore, we need to createa 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 invogue. Does it help to update the value of referent (x) immediately afterthe 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 youreorder 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 notrequire 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 truefor `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.htmland use the starting and ending indices of the items in the Arraythat you want to end up in the slice.If you're curious why the first argument of `assert_eq!` does nothave an ampersand for a reference since the second argument is areference, 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-typeParticularly 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 partsof 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, tryindexing into it instead, as explained in the last example of theData Types -> The Tuple Type section of the book:https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-typeNow 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 typessuch 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 useto make something public! The compiler error should point to the thing thatneeds to be public."""[[exercises]]name = "modules2"path = "exercises/modules/modules2.rs"mode = "compile"hint = """The delicious_snacks module is trying to present an externalinterface (the `fruit` and `veggie` constants) that is different thanits internal structure (the `fruits` and `veggies` modules andassociated constants). It's almost there except for one keyword missing foreach 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 vectorand fill it with the `push()` method.2. The second way, which is simpler is to use the `vec![]` macro anddefine your elements inside the square brackets.Check this chapter: https://doc.rust-lang.org/stable/book/ch08-01-vectors.htmlof 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 outthe type for the `basket`.Hint 2: Number of fruits should be at least 5. And you have to putat 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'tcome from a file or user input or another program -- so it will live as long as our programlives. But it is still a string slice. There's one way to create a `String` by converting astring 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 astring slice instead of a `String`, wouldn't it?? There is a way to add one character to line9, 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 sayingis 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> thatcould be the variants `Ok(String)` and `Err(String)`- change the body of the function to return `Ok(stuff)` where it currentlyreturns `Some(stuff)`- change the body of the function to return `Err(error message)` where itcurrently 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'sa `?` operator that does pretty much what you would make that match statementdo 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--operatorand 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 onlyreturning 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 areturn 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 ofdifferent kinds of errors can be returned from the same function becauseall 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--operatorThis exercise uses some concepts that we won't get to until later in thecourse, like `Box` and the `From` trait. It's not important to understandthem 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.htmlRead 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` fromerrors4.Below the line that TODO asks you to change, there is an example of usingthe `map_err()` method on a `Result` to transform one type of error intoanother. Try using something similar on the `Result` from `parse()`. Youmight use the `?` operator to return early from the function, or you mightuse a `match` expression, or maybe there's another way!You can create another function inside `impl ParsePosNonzeroError` to usewith `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 yourknowledge 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 theReportCard struct generic, but also the correct property - you will need to change the implementationof 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_someis_noneunwrapand:pattern matchingHint 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.htmlhttps://doc.rust-lang.org/rust-by-example/flow_control/while_let.htmlRemember that Options can be stacked in if let and while let.For example: Some(Some(variable)) = variable2Also 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 correctionneeded. After making the correction as suggested by the compiler, doread: 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. Seethe 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, eventhough 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 willpass) or `assert!` will panic (in which case the test will fail). So try giving different valuesto `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 andrun. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it twovalues that are equal! Try giving it two arguments that are different! Try giving it two valuesthat 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 dosomething like `assert!(having_fun())`. If you want to check that you indeed get false, youcan 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 1The compiler's message should help: since we cannot store the value of the actual typewhen 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-boxesStep 2Creating 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 definitionand 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 orderto 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 athread-local copy of the numbers.This is a simple exercise if you understand the underlying concepts, but if thisis 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 throughit. 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 ofelements? What should we expect here? If you're stuck, take a look athttps://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 1The variable `first` is a `char`. It needs to be capitalized and added to theremaining 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.htmlStep 2Create an iterator from the slice. Transform the iterated values by applyingthe `capitalize_first` function. Remember to collect the iterator.Step 3.This is surprising similar to the previous solution. Collect is very powerfuland 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 notpossible.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 successcase 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 howthe `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 updatesa mutable variable. Or, you might write code utilizing recursionand a match clause. In Rust you can take another functionalapproach, 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 methodsthat would be helpful here.Return 0 from count_collection_iterator to make the code compile in order totest count_iterator.The collection variable in count_collection_iterator is a slice of HashMaps. Itneeds 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 finda 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 accessto **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 tomutate 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-arctand 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 textthat says "We can use Arc<T> to fix this.". If not, give that a try! If youdo and would like more hints, keep reading!!Make sure neither of your threads are holding onto the lock of the mutexwhile they are sleeping, since this will prevent the other thread frombeing allowed to get the lock. Locks are automatically released whenthey go out of scope.Ok, so, real talk, this was actually tricky for *me* to do too. AndI could see a lot of different problems you might run into, so at thispoint I'm not sure which one you've hit :)Please open an issue if you're still running into a problem thatthese hints are not helping you with, or if you've looked at the sampleanswers and don't understand why they work and yours doesn't.If you've learned from the sample solutions, I encourage you to comeback to this exercise and try it again in a few days to reinforcewhat 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 aregular 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 ofwhat'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 somethingspecial to the module to lift the macro out into its parent.The same trick also works on "extern crate" statements for crates that haveexported 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 inmemory. Take a look at the description ofhttps://doc.rust-lang.org/stable/std/primitive.f32.htmlWhen using the binary compare operators with floating points you won't comparethe floating point values but the binary representation in memory. This isusually not what you would like to do.See the suggestions of the clippy warning in compile output and use themachine 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.htmlYou might want to look back at the exercise errors5 (or its hints) to remindyourself 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 implementationof `From<&str>` for `Box<dyn Error>`. This means you can use `.into()` orthe `?` 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 errortype 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 thehints for try_from_into."""
// variables6.rs// Make me compile! Execute the command `rustlings hint variables6` if you want a hint :)// I AM NOT DONEconst 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 DONEfn main() {let number = "T-H-R-E-E"; // don't change this lineprintln!("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 DONEfn 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 DONEfn main() {let x = 3;println!("Number {}", x);x = 5; // don't change this lineprintln!("Number {}", x);}
// variables2.rs// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)// I AM NOT DONEfn 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 DONEfn main() {x = 5;println!("x has the value {}", x);}
# VariablesIn 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 DONEtrait 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 DONEtrait 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"));}}
# TraitsA 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 DONEuse 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));}}
# ThreadsIn 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 DONEpub 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!();}}
# TestsGoing 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 DONEstruct 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!");}}
# StructsRust 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 DONEfn 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 DONEfn main() {let answer = current_favorite_color();println!("My current favorite color is {}", answer);}fn current_favorite_color() -> String {"blue"}
# StringsRust 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 howto 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 DONEuse 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 DONEpub 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 DONEfn main () {let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];let mut my_iterable_fav_fruits = ???; // TODO: Step 1assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1assert_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 = // TODOlet mut joinhandles = Vec::new();for offset in 0..8 {let child_numbers = // TODOjoinhandles.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 typesThis 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 DONEpub 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 DONEfn 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 DONEfn 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 DONEfn 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 DONEfn 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 DONEfn 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 TypesRust has a couple of basic types that are directly implemented into thecompiler. 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 DONEstruct 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 DONEfn main() {let optional_word = Some(String::from("rustlings"));// TODO: Make this an if let statement whose value is "Some" typeword = 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 letinteger = 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 sigfn 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;}}
# OptionType 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 DONEfn 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 DONEfn 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 argumentfn 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 DONEfn 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 DONEfn 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 DONEfn 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 SemanticsThese exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!## Further informationFor 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 DONEmod 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 DONEmod sausage_factory {fn make_sausage() {println!("sausage!");}}fn main() {sausage_factory::make_sausage();}
# ModulesIn 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 DONEmacro_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 DONEmod 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 DONEfn 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 DONEmacro_rules! my_macro {() => {println!("Check out my macro!");};}fn main() {my_macro();}
# MacrosRust's macro system is very powerful, but also kind of difficult to wrap yourhead around. We're not going to teach you how to write your own fully-featuredmacros. 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 DONEpub 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 DONEpub 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 DONEpub 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 DONEstruct 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 DONEfn main() {let mut shopping_list: Vec<?> = Vec::new();shopping_list.push("milk");}
# GenericsGenerics 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 DONEfn 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 DONEfn 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 DONEfn 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 DONEfn 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 DONEfn main() {call_me();}
# FunctionsHere, 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 DONEuse 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 DONEuse 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 DONEuse 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 DONEuse 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 DONEpub 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 handlingMost 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 DONEenum 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);}
# EnumsRust 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 DONEfn 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.htmluse 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 implementationimpl TryFrom<(i16, i16, i16)> for Color {type Error = Box<dyn error::Error>;fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {}}// Array implementationimpl TryFrom<[i16; 3]> for Color {type Error = Box<dyn error::Error>;fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}}// Slice implementationimpl TryFrom<&[i16]> for Color {type Error = Box<dyn error::Error>;fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}}fn main() {// Use the `from` functionlet c1 = Color::try_from((183, 65, 14));println!("{:?}", c1);// Since From is implemented for Color, we should be able to use Intolet c2: Result<Color, _> = [183, 65, 14].try_into();println!("{:?}", c2);let v = vec![183, 65, 14];// With slice we should use `from` functionlet c3 = Color::try_from(&v[..]);println!("{:?}", c3);// or take slice within round brackets and use Intolet 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.htmluse 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 objectimpl 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 objectimpl 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 DONEimpl From<&str> for Person {fn from(s: &str) -> Person {}}fn main() {// Use the `from` functionlet p1 = Person::from("Mark,20");// Since From is implemented for Person, we should be able to use Intolet 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 Johnlet 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 providedlet p = Person::from("");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_good_convert() {// Test that "Mark,20" workslet 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 agelet 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 boundfn 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 boundfn 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 conversionsRust 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 informationThese 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 DONEfn 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 DONEfn array_and_vec() -> ([i32; 4], Vec<i32>) {let a = [10, 20, 30, 40]; // a plain arraylet 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 DONEuse 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 DONEuse 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);}}
# CollectionsRust’s standard library includes a number of very useful datastructures called collections. Most other data types represent onespecific value, but collections can contain multiple values. Unlikethe built-in array and tuple types, the data these collections pointto is stored on the heap, which means the amount of data does not needto be known at compile time and can grow or shrink as the programruns.This exercise will get you familiar with two fundamental datastructures that are used very often in Rust programs:* A *vector* allows you to store a variable number of values next toeach 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 DONEfn 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 DONEfn main() {let x = 1.2331f64;let y = 1.2332f64;if y != x {println!("Success!");}}
# ClippyThe 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 aregoing to teach you a lot of things about Rust, but before we can getstarted, here's a couple of notes about how Rustlings operates:1. The central concept behind Rustlings is that you solve exercises. Theseexercises usually have some sort of syntax error in them, which will causethem to fail compilation or testing. Sometimes there's a logic error insteadof 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 andRustlings will be able to move on to the next exercise.2. If you run Rustlings in watch mode (which we recommend), it'll automaticallystart with the first exercise. Don't get confused by an error message poppingup as soon as you run Rustlings! This is part of the exercise that you'resupposed to solve, so open the exercise file in an editor and start yourdetective 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 firstexercise. Make sure to have your editor open!
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->[](#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/LinuxJust run:```bashcurl -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!## WindowsIn PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:```psSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser```Then, you can run:```psStart-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)## ManuallyBasically: 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/rustlingscd rustlingscargo install --force --path .```If there are installation errors, ensure that your toolchain is up to date. For the latest, run:```bashrustup update```Then, same as above, run `rustlings` to get started.## Doing exercisesThe 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:```bashrustlings 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:```bashrustlings 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:```bashrustlings run myExercise1```Or simply use the following command to run the next unsolved exercise in the course:```bashrustlings run next```In case you get stuck, you can run the following command to get a hint for yourexercise:``` bashrustlings hint myExercise1```You can also get the hint for the next unsolved exercise with the following command:``` bashrustlings hint next```To check your progress, you can run the following command:```bashrustlings list```## Testing yourselfAfter 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 OnOnce 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 RustlingsIf 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 createdfor you:``` bashrm -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, andexactly that is the case. Run `cargo uninstall` to remove the `rustlings` binary:``` bashcargo uninstall rustlings```Now you should be done!## CompletionRustlings 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 moreIf you are interested in improving or adding new ones, please feel free to contribute! Read on for more information :)## ContributingSee [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 copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, 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 THESOFTWARE.
[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 RustlingsFirst off, thanks for taking the time to contribute!! ❤️### Quick ReferenceI 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 codeisn'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 exerciseThe first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure toput 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>### IssuesYou 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 RequestsOpening a pull request is as easy as forking the repository and committing yourchanges. There's a couple of things to watch out for:#### Write correct commit messagesWe 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. Sayyou're working on adding a new exercise called `foobar1.rs`. You could writethe 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 messagebody:```fix: Update foobarcloses #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 andexplain the breaking change in the message body:```fix!: Completely change verificationBREAKING CHANGE: This has to be done because lorem ipsum dolor```#### Pull Request WorkflowOnce you open a Pull Request, it may be reviewed or labeled (or both) untilthe maintainers accept your change. Then, [bors](https://github.com/bors) willrun the test suite with your changes and if it's successful, automaticallymerge 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 addedthis :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.