diff --git a/.all-contributorsrc b/.all-contributorsrc index f2033dcd..94141140 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1542,6 +1542,177 @@ "contributions": [ "content" ] + }, + { + "login": "rzrymiak", + "name": "rzrymiak", + "avatar_url": "https://avatars.githubusercontent.com/u/106121613?v=4", + "profile": "https://github.com/rzrymiak", + "contributions": [ + "content" + ] + }, + { + "login": "miguelraz", + "name": "Miguel Raz Guzmán Macedo", + "avatar_url": "https://avatars.githubusercontent.com/u/13056181?v=4", + "profile": "https://github.com/miguelraz", + "contributions": [ + "content" + ] + }, + { + "login": "memark", + "name": "Magnus Markling", + "avatar_url": "https://avatars.githubusercontent.com/u/318504?v=4", + "profile": "https://github.com/memark", + "contributions": [ + "content" + ] + }, + { + "login": "gasparitiago", + "name": "Tiago De Gaspari", + "avatar_url": "https://avatars.githubusercontent.com/u/3237254?v=4", + "profile": "https://github.com/gasparitiago", + "contributions": [ + "content" + ] + }, + { + "login": "skaunov", + "name": "skaunov", + "avatar_url": "https://avatars.githubusercontent.com/u/65976143?v=4", + "profile": "https://github.com/skaunov", + "contributions": [ + "content" + ] + }, + { + "login": "cj81499", + "name": "Cal Jacobson", + "avatar_url": "https://avatars.githubusercontent.com/u/9152032?v=4", + "profile": "http://caljacobson.dev", + "contributions": [ + "content" + ] + }, + { + "login": "duchonic", + "name": "Duchoud Nicolas", + "avatar_url": "https://avatars.githubusercontent.com/u/34117620?v=4", + "profile": "https://github.com/duchonic", + "contributions": [ + "content" + ] + }, + { + "login": "gfaugere", + "name": "Gaëtan Faugère", + "avatar_url": "https://avatars.githubusercontent.com/u/11901979?v=4", + "profile": "https://github.com/gfaugere", + "contributions": [ + "tool" + ] + }, + { + "login": "bhbuehler", + "name": "bhbuehler", + "avatar_url": "https://avatars.githubusercontent.com/u/25541343?v=4", + "profile": "https://github.com/bhbuehler", + "contributions": [ + "content" + ] + }, + { + "login": "nyurik", + "name": "Yuri Astrakhan", + "avatar_url": "https://avatars.githubusercontent.com/u/1641515?v=4", + "profile": "https://github.com/nyurik", + "contributions": [ + "code" + ] + }, + { + "login": "azzamsa", + "name": "azzamsa", + "avatar_url": "https://avatars.githubusercontent.com/u/17734314?v=4", + "profile": "http://azzamsa.com", + "contributions": [ + "code" + ] + }, + { + "login": "mvanschellebeeck", + "name": "mvanschellebeeck", + "avatar_url": "https://avatars.githubusercontent.com/u/17671052?v=4", + "profile": "https://github.com/mvanschellebeeck", + "contributions": [ + "content" + ] + }, + { + "login": "aaarkid", + "name": "Arkid", + "avatar_url": "https://avatars.githubusercontent.com/u/39987510?v=4", + "profile": "https://github.com/aaarkid", + "contributions": [ + "content" + ] + }, + { + "login": "tfpk", + "name": "Tom Kunc", + "avatar_url": "https://avatars.githubusercontent.com/u/10906982?v=4", + "profile": "http://tfpk.dev", + "contributions": [ + "content" + ] + }, + { + "login": "mfurak", + "name": "Marek Furák", + "avatar_url": "https://avatars.githubusercontent.com/u/38523093?v=4", + "profile": "https://github.com/mfurak", + "contributions": [ + "content" + ] + }, + { + "login": "winterqt", + "name": "Winter", + "avatar_url": "https://avatars.githubusercontent.com/u/78392041?v=4", + "profile": "https://winter.cafe", + "contributions": [ + "code" + ] + }, + { + "login": "MoritzBoehme", + "name": "Moritz Böhme", + "avatar_url": "https://avatars.githubusercontent.com/u/42215704?v=4", + "profile": "https://moritzboeh.me", + "contributions": [ + "code" + ] + }, + { + "login": "craymel", + "name": "craymel", + "avatar_url": "https://avatars.githubusercontent.com/u/71062756?v=4", + "profile": "https://github.com/craymel", + "contributions": [ + "content" + ] + }, + { + "login": "tkburis", + "name": "TK Buristrakul", + "avatar_url": "https://avatars.githubusercontent.com/u/20501289?v=4", + "profile": "https://github.com/tkburis", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, @@ -1549,5 +1720,6 @@ "projectOwner": "rust-lang", "repoType": "github", "repoHost": "https://github.com", - "skipCi": true + "skipCi": true, + "commitConvention": "angular" } diff --git a/.gitignore b/.gitignore index 534453bc..c14f9227 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ exercises/clippy/Cargo.toml exercises/clippy/Cargo.lock rust-project.json .idea -.vscode +.vscode/* +!.vscode/extensions.json *.iml *.o diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..b85de749 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "rust-lang.rust-analyzer" + ] +} diff --git a/AUTHORS.md b/AUTHORS.md index 8edf09bf..2fc637f2 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -9,216 +9,243 @@ authors. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Carol (Nichols || Goulding)

💻 🖋

QuietMisdreavus

💻 🖋

Robert M Lugg

🖋

Hynek Schlawack

💻

Katharina Fey

💻

lukabavdaz

💻 🖋

Erik Vesteraas

💻

delet0r

💻

Shaun Bennett

💻

Andrew Bagshaw

💻

Kyle Isom

💻

Colin Pitrat

💻

Zac Anger

💻

Matthias Geier

💻

Chris Pearce

💻

Yvan Sraka

💻

Denys Smirnov

💻

eddyp

💻

Brian Kung

💻 🖋

Russell

💻

Dan Wilhelm

📖

Jesse

💻 🖋

Fredrik Jambrén

💻

Pete McFarlane

🖋

nkanderson

💻 🖋

Ajax M

📖

Dylan Nugent

🖋

vyaslav

💻 🖋

George

💻

Thomas Holloway

💻 🖋

Jubilee

💻

WofWca

💻

Roberto Vidal

💻 📖 🤔 🚧

Jens

📖

Rahat Ahmed

📖

Abdou Seck

💻 🖋 👀

Katie

💻

Socrates

📖

gnodarse

🖋

Harrison Metzger

💻

Torben Jonas

💻 🖋

Paul Bissex

📖

Steven Mann

💻 🖋

Mario Reder

💻 🖋

skim

💻

Sanjay K

💻 🖋

Rohan Jain

💻

Said Aspen

💻 🖋

Ufuk Celebi

💻

lebedevsergey

📖

Aleksei Trifonov

🖋

Darren Meehan

🖋

Jihchi Lee

🖋

Christofer Bertonha

🖋

Vivek Bharath Akupatni

💻 ⚠️

Dídac Sementé Fernández

💻 🖋

Rob Story

💻

Siobhan Jacobson

💻

Evan Carroll

🖋

Jawaad Mahmood

🖋

Gaurang Tandon

🖋

Stefan Kupresak

🖋

Greg Leonard

🖋

Ryan McQuen

💻

Annika

👀

Axel Viala

💻

Mohammed Sazid Al Rashid

🖋 💻

Caleb Webber

🚧

Peter N

🚧

seancad

🚧

Will Hayworth

🖋

Christian Zeller

🖋

Jean-Francois Chevrette

🖋 💻

John Baber-Lucero

🖋

Tal

🖋

apogeeoak

🖋 💻

Larry Garfield

🖋

circumspect

🖋

Cyrus Wyett

🖋

cadolphs

💻

Pascal H.

🖋

Rod Elias

🖋

Matt Lebl

💻

Ignacio Le Fluk

🖋

Taylor Yu

💻 🖋

Patrick Hintermayer

💻

Pete Pavlovski

🖋

k12ish

🖋

Shao Yang Hong

🖋

Brandon Macer

🖋

Stoian Dan

🖋

Pi Delport

🖋

Sateesh

💻 🖋

ZC

🖋

hyperparabolic

💻

arlecchino

📖

Richthofen

💻

Ivan Nerazumov

📖

lauralindzey

📖

Rakshit Sinha

🖋

Damian

🖋

Ben Armstead

💻

anuk909

🖋 💻

granddaifuku

🖋

Weilet

🖋

LIU JIE

🖋

Antoine Büsch

💻

frogtd

🖋

Zhenghao Lu

🖋

Fredrik Enestad

🖋

xuesong

🖋

Michael Walsh

💻

alirezaghey

🖋

Franklin van Nes

💻

nekonako

💻

ZX

🖋

Yang Wen

🖋

Brandon High

📖

x-hgg-x

💻

Kisaragi

📖

Lucas Aries

🖋

ragreenburg

🖋

stevenfukase

🖋

J-S-Kim

🖋

Fointard

🖋

Ryan Lowe

💻

cui fliter

🖋

Ron Lusk

🖋

Bryan Lee

🖋

Nandaja Varma

📖

pwygab

💻

Lucas Grigolon Varela

🖋

Bufo

🖋

Jack Clayton

💻

Konstantin

🖋

0pling

🖋

KatanaFluorescent

💻

Drew Morris

💻

camperdue42

🖋

YsuOS

🖋

Steven Nguyen

🖋

nacairns1

🖋

Paulo Gabriel Justino Bezerra

🖋

Jason

🖋

exdx

🖋

James Zow

🖋

James Bromley

🖋

swhiteCQC

🖋

Neil Pate

🖋

wojexe

🖋

Mattia Schiavon

🖋

Eric Jolibois

🖋

Edwin Chang

🖋

Saikat Das

🖋

Jeremy Goh

🖋

Lioness100

🖋

Tristan Nicholls

🖋

Claire

🖋

Maurice Van Wassenhove

🖋

John Mendelewski

💻

Brian Fakhoury

🖋

Markus Boehme

💻

Nico Vromans

🖋

vostok92

🖋

Magnus Rødseth

🖋

rubiesonthesky

🖋

Gabriel Bianconi

🖋

Kody Low

🖋
Carol (Nichols || Goulding)
Carol (Nichols || Goulding)

💻 🖋
QuietMisdreavus
QuietMisdreavus

💻 🖋
Robert M Lugg
Robert M Lugg

🖋
Hynek Schlawack
Hynek Schlawack

💻
Katharina Fey
Katharina Fey

💻
lukabavdaz
lukabavdaz

💻 🖋
Erik Vesteraas
Erik Vesteraas

💻
delet0r
delet0r

💻
Shaun Bennett
Shaun Bennett

💻
Andrew Bagshaw
Andrew Bagshaw

💻
Kyle Isom
Kyle Isom

💻
Colin Pitrat
Colin Pitrat

💻
Zac Anger
Zac Anger

💻
Matthias Geier
Matthias Geier

💻
Chris Pearce
Chris Pearce

💻
Yvan Sraka
Yvan Sraka

💻
Denys Smirnov
Denys Smirnov

💻
eddyp
eddyp

💻
Brian Kung
Brian Kung

💻 🖋
Russell
Russell

💻
Dan Wilhelm
Dan Wilhelm

📖
Jesse
Jesse

💻 🖋
Fredrik Jambrén
Fredrik Jambrén

💻
Pete McFarlane
Pete McFarlane

🖋
nkanderson
nkanderson

💻 🖋
Ajax M
Ajax M

📖
Dylan Nugent
Dylan Nugent

🖋
vyaslav
vyaslav

💻 🖋
George
George

💻
Thomas Holloway
Thomas Holloway

💻 🖋
Jubilee
Jubilee

💻
WofWca
WofWca

💻
Roberto Vidal
Roberto Vidal

💻 📖 🤔 🚧
Jens
Jens

📖
Rahat Ahmed
Rahat Ahmed

📖
Abdou Seck
Abdou Seck

💻 🖋 👀
Katie
Katie

💻
Socrates
Socrates

📖
gnodarse
gnodarse

🖋
Harrison Metzger
Harrison Metzger

💻
Torben Jonas
Torben Jonas

💻 🖋
Paul Bissex
Paul Bissex

📖
Steven Mann
Steven Mann

💻 🖋
Mario Reder
Mario Reder

💻 🖋
skim
skim

💻
Sanjay K
Sanjay K

💻 🖋
Rohan Jain
Rohan Jain

💻
Said Aspen
Said Aspen

💻 🖋
Ufuk Celebi
Ufuk Celebi

💻
lebedevsergey
lebedevsergey

📖
Aleksei Trifonov
Aleksei Trifonov

🖋
Darren Meehan
Darren Meehan

🖋
Jihchi Lee
Jihchi Lee

🖋
Christofer Bertonha
Christofer Bertonha

🖋
Vivek Bharath Akupatni
Vivek Bharath Akupatni

💻 ⚠️
Dídac Sementé Fernández
Dídac Sementé Fernández

💻 🖋
Rob Story
Rob Story

💻
Siobhan Jacobson
Siobhan Jacobson

💻
Evan Carroll
Evan Carroll

🖋
Jawaad Mahmood
Jawaad Mahmood

🖋
Gaurang Tandon
Gaurang Tandon

🖋
Stefan Kupresak
Stefan Kupresak

🖋
Greg Leonard
Greg Leonard

🖋
Ryan McQuen
Ryan McQuen

💻
Annika
Annika

👀
Axel Viala
Axel Viala

💻
Mohammed Sazid Al Rashid
Mohammed Sazid Al Rashid

🖋 💻
Caleb Webber
Caleb Webber

🚧
Peter N
Peter N

🚧
seancad
seancad

🚧
Will Hayworth
Will Hayworth

🖋
Christian Zeller
Christian Zeller

🖋
Jean-Francois Chevrette
Jean-Francois Chevrette

🖋 💻
John Baber-Lucero
John Baber-Lucero

🖋
Tal
Tal

🖋
apogeeoak
apogeeoak

🖋 💻
Larry Garfield
Larry Garfield

🖋
circumspect
circumspect

🖋
Cyrus Wyett
Cyrus Wyett

🖋
cadolphs
cadolphs

💻
Pascal H.
Pascal H.

🖋
Rod Elias
Rod Elias

🖋
Matt Lebl
Matt Lebl

💻
Ignacio Le Fluk
Ignacio Le Fluk

🖋
Taylor Yu
Taylor Yu

💻 🖋
Patrick Hintermayer
Patrick Hintermayer

💻
Pete Pavlovski
Pete Pavlovski

🖋
k12ish
k12ish

🖋
Shao Yang Hong
Shao Yang Hong

🖋
Brandon Macer
Brandon Macer

🖋
Stoian Dan
Stoian Dan

🖋
Pi Delport
Pi Delport

🖋
Sateesh
Sateesh

💻 🖋
ZC
ZC

🖋
hyperparabolic
hyperparabolic

💻
arlecchino
arlecchino

📖
Richthofen
Richthofen

💻
Ivan Nerazumov
Ivan Nerazumov

📖
lauralindzey
lauralindzey

📖
Rakshit Sinha
Rakshit Sinha

🖋
Damian
Damian

🖋
Ben Armstead
Ben Armstead

💻
anuk909
anuk909

🖋 💻
granddaifuku
granddaifuku

🖋
Weilet
Weilet

🖋
LIU JIE
LIU JIE

🖋
Antoine Büsch
Antoine Büsch

💻
frogtd
frogtd

🖋
Zhenghao Lu
Zhenghao Lu

🖋
Fredrik Enestad
Fredrik Enestad

🖋
xuesong
xuesong

🖋
Michael Walsh
Michael Walsh

💻
alirezaghey
alirezaghey

🖋
Franklin van Nes
Franklin van Nes

💻
nekonako
nekonako

💻
ZX
ZX

🖋
Yang Wen
Yang Wen

🖋
Brandon High
Brandon High

📖
x-hgg-x
x-hgg-x

💻
Kisaragi
Kisaragi

📖
Lucas Aries
Lucas Aries

🖋
ragreenburg
ragreenburg

🖋
stevenfukase
stevenfukase

🖋
J-S-Kim
J-S-Kim

🖋
Fointard
Fointard

🖋
Ryan Lowe
Ryan Lowe

💻
cui fliter
cui fliter

🖋
Ron Lusk
Ron Lusk

🖋
Bryan Lee
Bryan Lee

🖋
Nandaja Varma
Nandaja Varma

📖
pwygab
pwygab

💻
Lucas Grigolon Varela
Lucas Grigolon Varela

🖋
Bufo
Bufo

🖋
Jack Clayton
Jack Clayton

💻
Konstantin
Konstantin

🖋
0pling
0pling

🖋
KatanaFluorescent
KatanaFluorescent

💻
Drew Morris
Drew Morris

💻
camperdue42
camperdue42

🖋
YsuOS
YsuOS

🖋
Steven Nguyen
Steven Nguyen

🖋
nacairns1
nacairns1

🖋
Paulo Gabriel Justino Bezerra
Paulo Gabriel Justino Bezerra

🖋
Jason
Jason

🖋
exdx
exdx

🖋
James Zow
James Zow

🖋
James Bromley
James Bromley

🖋
swhiteCQC
swhiteCQC

🖋
Neil Pate
Neil Pate

🖋
wojexe
wojexe

🖋
Mattia Schiavon
Mattia Schiavon

🖋
Eric Jolibois
Eric Jolibois

🖋
Edwin Chang
Edwin Chang

🖋
Saikat Das
Saikat Das

🖋
Jeremy Goh
Jeremy Goh

🖋
Lioness100
Lioness100

🖋
Tristan Nicholls
Tristan Nicholls

🖋
Claire
Claire

🖋
Maurice Van Wassenhove
Maurice Van Wassenhove

🖋
John Mendelewski
John Mendelewski

💻
Brian Fakhoury
Brian Fakhoury

🖋
Markus Boehme
Markus Boehme

💻
Nico Vromans
Nico Vromans

🖋
vostok92
vostok92

🖋
Magnus Rødseth
Magnus Rødseth

🖋
rubiesonthesky
rubiesonthesky

🖋
Gabriel Bianconi
Gabriel Bianconi

🖋
Kody Low
Kody Low

🖋
rzrymiak
rzrymiak

🖋
Miguel Raz Guzmán Macedo
Miguel Raz Guzmán Macedo

🖋
Magnus Markling
Magnus Markling

🖋
Tiago De Gaspari
Tiago De Gaspari

🖋
skaunov
skaunov

🖋
Cal Jacobson
Cal Jacobson

🖋
Duchoud Nicolas
Duchoud Nicolas

🖋
Gaëtan Faugère
Gaëtan Faugère

🔧
bhbuehler
bhbuehler

🖋
Yuri Astrakhan
Yuri Astrakhan

💻
azzamsa
azzamsa

💻
mvanschellebeeck
mvanschellebeeck

🖋
Arkid
Arkid

🖋
Tom Kunc
Tom Kunc

🖋
Marek Furák
Marek Furák

🖋
Winter
Winter

💻
Moritz Böhme
Moritz Böhme

💻
craymel
craymel

🖋
TK Buristrakul
TK Buristrakul

🖋
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b15cf99..c351fce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,50 @@ + +## 5.3.0 (2022-12-23) + +#### Added + +- **cli**: Added a percentage display in watch mode +- Added a `flake.nix` for Nix users + +#### Changed + +- **structs3**: Added an additional test +- **macros**: Added a link to MacroKata in the README + +#### Fixed + +- **strings3**: Added a link to `std` in the hint +- **threads1**: Corrected a hint link +- **iterators1**: Clarified hint steps +- **errors5**: Fix a typo in the hint +- **options1**: Clarified on the usage of the 24-hour system +- **threads2, threads3**: Explicitly use `Arc::clone` +- **structs3**: Clarifed the hint +- **quiz2, as_ref_mut, options1, traits1, traits2**: Clarified hints +- **traits1, traits2, cli**: Tidied up unmatching backticks +- **enums2**: Removed unneccessary indirection of self +- **enums3**: Added an extra tuple comment + +#### Housekeeping + +- Added a VSCode extension recommendation +- Applied some Clippy and rustfmt formatting +- Added a note on Windows PowerShell and other shell compatibility + + +## 5.2.1 (2022-09-06) + +#### Fixed + +- **quiz1**: Reworded the comment to actually reflect what's going on in the tests. + Also added another assert just to make sure. +- **rc1**: Fixed a typo in the hint. +- **lifetimes**: Add quotes to the `println!` output, for readability. + +#### Housekeeping + +- Fixed a typo in README.md + ## 5.2.0 (2022-08-27) diff --git a/Cargo.lock b/Cargo.lock index 2370e8dc..49f20b66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" -version = "5.1.1" +version = "5.3.0" dependencies = [ "argh", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 25cd7bfe..c2c54fd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "rustlings" -version = "5.2.0" -authors = ["Liv ", "Carol (Nichols || Goulding) "] +version = "5.3.0" +authors = [ + "Liv ", + "Carol (Nichols || Goulding) ", +] edition = "2021" [dependencies] diff --git a/README.md b/README.md index 2392ba9d..956bb6d0 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,19 @@ curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | This will install Rustlings and give you access to the `rustlings` command. Run it to get started! +### Nix +Basically: Clone the repository at the latest tag, finally run `nix develop` or `nix-shell`. + +```bash +# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.3.0) +git clone -b 5.3.0 --depth 1 https://github.com/rust-lang/rustlings +cd rustlings +# if nix version > 2.3 +nix develop +# if nix version <= 2.3 +nix-shell +``` + ## Windows In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`: @@ -42,7 +55,7 @@ Then, you can run: Start-BitsTransfer -Source https://raw.githubusercontent.com/rust-lang/rustlings/main/install.ps1 -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. +To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it. Keep in mind that this works best in PowerShell, and any other terminals may give you errors. If you get a permission denied message, you might have to exclude the directory where you cloned Rustlings in your antivirus. @@ -57,8 +70,8 @@ If you get a permission denied message, you might have to exclude the directory Basically: Clone the repository at the latest tag, run `cargo install --path .`. ```bash -# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.1.1) -git clone -b 5.1.1 --depth 1 https://github.com/rust-lang/rustlings +# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.3.0) +git clone -b 5.3.0 --depth 1 https://github.com/rust-lang/rustlings cd rustlings cargo install --force --path . ``` @@ -126,7 +139,7 @@ After every couple of sections, there will be a quiz that'll test your knowledge ## Enabling `rust-analyzer` -Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise. +Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise. ## Continuing On @@ -134,7 +147,7 @@ Once you've completed Rustlings, put your new knowledge to good use! Continue pr ## Uninstalling Rustlings -If you want to remove Rustlings from your system, there's two steps. First, you'll need to remove the exercises folder that the install script created +If you want to remove Rustlings from your system, there are two steps. First, you'll need to remove the exercises folder that the install script created for you: ```bash diff --git a/exercises/conversions/as_ref_mut.rs b/exercises/conversions/as_ref_mut.rs index 9f479739..e6a9d114 100644 --- a/exercises/conversions/as_ref_mut.rs +++ b/exercises/conversions/as_ref_mut.rs @@ -5,21 +5,22 @@ // I AM NOT DONE -// Obtain the number of bytes (not characters) in the given argument -// Add the AsRef trait appropriately as a trait bound +// Obtain the number of bytes (not characters) in the given argument. +// TODO: Add the AsRef trait appropriately as a trait bound. fn byte_counter(arg: T) -> usize { arg.as_ref().as_bytes().len() } -// Obtain the number of characters (not bytes) in the given argument -// Add the AsRef trait appropriately as a trait bound +// Obtain the number of characters (not bytes) in the given argument. +// TODO: Add the AsRef trait appropriately as a trait bound. fn char_counter(arg: T) -> usize { arg.as_ref().chars().count() } -// Squares a number using AsMut. Add the trait bound as is appropriate and -// implement the function body. +// Squares a number using as_mut(). +// TODO: Add the appropriate trait bound. fn num_sq(arg: &mut T) { + // TODO: Implement the function body. ??? } diff --git a/exercises/enums/enums2.rs b/exercises/enums/enums2.rs index 18479f87..167a6b2e 100644 --- a/exercises/enums/enums2.rs +++ b/exercises/enums/enums2.rs @@ -10,7 +10,7 @@ enum Message { impl Message { fn call(&self) { - println!("{:?}", &self); + println!("{:?}", self); } } diff --git a/exercises/enums/enums3.rs b/exercises/enums/enums3.rs index 55acf6bc..54fd6f60 100644 --- a/exercises/enums/enums3.rs +++ b/exercises/enums/enums3.rs @@ -52,7 +52,7 @@ mod tests { position: Point { x: 0, y: 0 }, color: (0, 0, 0), }; - state.process(Message::ChangeColor((255, 0, 255))); + state.process(Message::ChangeColor((255, 0, 255))); // Remember: The extra parentheses mark a tuple type. state.process(Message::Echo(String::from("hello world"))); state.process(Message::Move(Point { x: 10, y: 15 })); state.process(Message::Quit); diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs index 2ba8f903..6da06ef3 100644 --- a/exercises/error_handling/errors5.rs +++ b/exercises/error_handling/errors5.rs @@ -7,7 +7,7 @@ // For now, think of the `Box` type as an "I want anything that does ???" type, which, given // Rust's usual standards for runtime safety, should strike you as somewhat lenient! -// In short, this particular use case for boxes is for when you want to own a value and you care only that it is a +// In short, this particular use case for boxes is for when you want to own a value and you care only that it is a // type which implements a particular trait. To do so, The Box is declared as of type Box where Trait is the trait // the compiler looks for on any value used in that context. For this exercise, that context is the potential errors // which can be returned in a Result. @@ -46,7 +46,7 @@ impl PositiveNonzeroInteger { match value { x if x < 0 => Err(CreationError::Negative), x if x == 0 => Err(CreationError::Zero), - x => Ok(PositiveNonzeroInteger(x as u64)) + x => Ok(PositiveNonzeroInteger(x as u64)), } } } diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs index 1306fb03..8097b490 100644 --- a/exercises/error_handling/errors6.rs +++ b/exercises/error_handling/errors6.rs @@ -16,7 +16,7 @@ use std::num::ParseIntError; #[derive(PartialEq, Debug)] enum ParsePosNonzeroError { Creation(CreationError), - ParseInt(ParseIntError) + ParseInt(ParseIntError), } impl ParsePosNonzeroError { @@ -27,14 +27,11 @@ impl ParsePosNonzeroError { // fn from_parseint... } -fn parse_pos_nonzero(s: &str) - -> Result -{ +fn parse_pos_nonzero(s: &str) -> Result { // 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) + PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation) } // Don't change anything below this line. @@ -53,7 +50,7 @@ impl PositiveNonzeroInteger { match value { x if x < 0 => Err(CreationError::Negative), x if x == 0 => Err(CreationError::Zero), - x => Ok(PositiveNonzeroInteger(x as u64)) + x => Ok(PositiveNonzeroInteger(x as u64)), } } } diff --git a/exercises/hashmaps/hashmaps3.rs b/exercises/hashmaps/hashmaps3.rs index 18dd44c9..ad3baa68 100644 --- a/exercises/hashmaps/hashmaps3.rs +++ b/exercises/hashmaps/hashmaps3.rs @@ -37,7 +37,7 @@ fn build_scores_table(results: String) -> HashMap { let team_2_score: u8 = v[3].parse().unwrap(); // TODO: Populate the scores table with details extracted from the // current line. Keep in mind that goals scored by team_1 - // will be number of goals conceded from team_2, and similarly + // will be the number of goals conceded from team_2, and similarly // goals scored by team_2 will be the number of goals conceded by // team_1. } diff --git a/exercises/lifetimes/lifetimes1.rs b/exercises/lifetimes/lifetimes1.rs index 58e995c6..0236470d 100644 --- a/exercises/lifetimes/lifetimes1.rs +++ b/exercises/lifetimes/lifetimes1.rs @@ -22,5 +22,5 @@ fn main() { let string2 = "xyz"; let result = longest(string1.as_str(), string2); - println!("The longest string is {}", result); + println!("The longest string is '{}'", result); } diff --git a/exercises/lifetimes/lifetimes2.rs b/exercises/lifetimes/lifetimes2.rs index c73a28ad..b48feabc 100644 --- a/exercises/lifetimes/lifetimes2.rs +++ b/exercises/lifetimes/lifetimes2.rs @@ -23,5 +23,5 @@ fn main() { let string2 = String::from("xyz"); result = longest(string1.as_str(), string2.as_str()); } - println!("The longest string is {}", result); + println!("The longest string is '{}'", result); } diff --git a/exercises/macros/README.md b/exercises/macros/README.md index 31a941b7..e34bc3a8 100644 --- a/exercises/macros/README.md +++ b/exercises/macros/README.md @@ -4,6 +4,10 @@ Rust's macro system is very powerful, but also kind of difficult to wrap your head around. We're not going to teach you how to write your own fully-featured macros. Instead, we'll show you how to use and create them. +If you'd like to learn more about writing your own macros, the +[macrokata](https://github.com/tfpk/macrokata) project has a similar style +of exercises to Rustlings, but is all about learning to write Macros. + ## Further information - [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) diff --git a/exercises/options/options1.rs b/exercises/options/options1.rs index d1735c2f..1f891b0e 100644 --- a/exercises/options/options1.rs +++ b/exercises/options/options1.rs @@ -6,10 +6,10 @@ // This function returns how much icecream there is left in the fridge. // If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them // all, so there'll be no more left :( -// TODO: Return an Option! fn maybe_icecream(time_of_day: u16) -> Option { - // We use the 24-hour system here, so 10PM is a value of 22 - // The Option output should gracefully handle cases where time_of_day > 24. + // We use the 24-hour system here, so 10PM is a value of 22 and 12AM is a value of 0 + // The Option output should gracefully handle cases where time_of_day > 23. + // TODO: Complete the function body - remember to return an Option! ??? } diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs index d1e76e59..dbb5cdc9 100644 --- a/exercises/quiz1.rs +++ b/exercises/quiz1.rs @@ -4,9 +4,11 @@ // - Functions // - If -// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy -// 40 or more 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! +// Mary is buying apples. The price of an apple is calculated as follows: +// - An apple costs 2 rustbucks. +// - If Mary buys more than 40 apples, each apple only costs 1 rustbuck! +// Write a function that calculates the price of an order of apples given +// the quantity bought. No hints this time! // I AM NOT DONE @@ -18,9 +20,11 @@ fn verify_test() { let price1 = calculate_price_of_apples(35); let price2 = calculate_price_of_apples(40); - let price3 = calculate_price_of_apples(65); + let price3 = calculate_price_of_apples(41); + let price4 = calculate_price_of_apples(65); assert_eq!(70, price1); assert_eq!(80, price2); - assert_eq!(65, price3); + assert_eq!(41, price3); + assert_eq!(65, price4); } diff --git a/exercises/quiz2.rs b/exercises/quiz2.rs index d8fa954a..715788b8 100644 --- a/exercises/quiz2.rs +++ b/exercises/quiz2.rs @@ -16,7 +16,7 @@ // - The input is going to be a Vector of a 2-length tuple, // the first element is the string, the second one is the command. // - The output element is going to be a Vector of strings. -// Execute `rustlings hint quiz2` or use the `hint` watch subcommand for a hint. +// No hints this time! // I AM NOT DONE @@ -42,7 +42,7 @@ mod my_module { #[cfg(test)] mod tests { - // TODO: What do we have to import to have `transformer` in scope? + // TODO: What do we need to import to have `transformer` in scope? use ???; use super::Command; diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs index 0b3615f4..3536a457 100644 --- a/exercises/structs/structs3.rs +++ b/exercises/structs/structs3.rs @@ -78,5 +78,6 @@ mod tests { let package = Package::new(sender_country, recipient_country, 1500); assert_eq!(package.get_fees(cents_per_gram), 4500); + assert_eq!(package.get_fees(cents_per_gram * 2), 9000); } } diff --git a/exercises/threads/threads2.rs b/exercises/threads/threads2.rs index d0f8578f..ada3d14a 100644 --- a/exercises/threads/threads2.rs +++ b/exercises/threads/threads2.rs @@ -17,7 +17,7 @@ fn main() { let status = Arc::new(JobStatus { jobs_completed: 0 }); let mut handles = vec![]; for _ in 0..10 { - let status_shared = status.clone(); + let status_shared = Arc::clone(&status); let handle = thread::spawn(move || { thread::sleep(Duration::from_millis(250)); // TODO: You must take an action before you update a shared value diff --git a/exercises/threads/threads3.rs b/exercises/threads/threads3.rs index 27e99088..9e9f285a 100644 --- a/exercises/threads/threads3.rs +++ b/exercises/threads/threads3.rs @@ -26,8 +26,8 @@ impl Queue { fn send_tx(q: Queue, tx: mpsc::Sender) -> () { let qc = Arc::new(q); - let qc1 = qc.clone(); - let qc2 = qc.clone(); + let qc1 = Arc::clone(&qc); + let qc2 = Arc::clone(&qc); thread::spawn(move || { for val in &qc1.first_half { diff --git a/exercises/traits/traits1.rs b/exercises/traits/traits1.rs index 5b9d8d50..f5320a5a 100644 --- a/exercises/traits/traits1.rs +++ b/exercises/traits/traits1.rs @@ -2,7 +2,7 @@ // Time to implement some traits! // // Your task is to implement the trait -// `AppendBar' for the type `String'. +// `AppendBar` for the type `String`. // // The trait AppendBar has only one function, // which appends "Bar" to any object @@ -16,7 +16,7 @@ trait AppendBar { } impl AppendBar for String { - //Add your code here + // TODO: Implement `AppendBar` for type `String`. } fn main() { diff --git a/exercises/traits/traits2.rs b/exercises/traits/traits2.rs index 708bb19a..288b4983 100644 --- a/exercises/traits/traits2.rs +++ b/exercises/traits/traits2.rs @@ -1,7 +1,7 @@ // traits2.rs // // Your task is to implement the trait -// `AppendBar' for a vector of strings. +// `AppendBar` for a vector of strings. // // To implement this trait, consider for // a moment what it means to 'append "Bar"' @@ -17,7 +17,7 @@ trait AppendBar { fn append_bar(self) -> Self; } -//TODO: Add your code here +// TODO: Implement trait `AppendBar` for a vector of strings. #[cfg(test)] mod tests { diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..ceb62c6d --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1666629043, + "narHash": "sha256-Yoq6Ut2F3Ol73yO9hG93x6ts5c4F5BhKTbcF3DtBEAw=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "b39fd6e4edef83cb4a135ebef98751ce23becc33", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..a6703199 --- /dev/null +++ b/flake.nix @@ -0,0 +1,53 @@ +{ + description = "Small exercises to get you used to reading and writing Rust code"; + + inputs = { + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; + flake-utils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + }; + + outputs = { self, flake-utils, nixpkgs, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + rustlings = + pkgs.rustPlatform.buildRustPackage { + name = "rustlings"; + version = "5.3.0"; + + src = with pkgs.lib; cleanSourceWith { + src = self; + # a function that returns a bool determining if the path should be included in the cleaned source + filter = path: type: + let + # filename + baseName = builtins.baseNameOf (toString path); + # path from root directory + path' = builtins.replaceStrings [ "${self}/" ] [ "" ] path; + # checks if path is in the directory + inDirectory = directory: hasPrefix directory path'; + in + inDirectory "src" || + inDirectory "tests" || + hasPrefix "Cargo" baseName || + baseName == "info.toml"; + }; + + cargoLock.lockFile = ./Cargo.lock; + }; + in + { + devShell = pkgs.mkShell { + buildInputs = with pkgs; [ + cargo + rustc + rust-analyzer + rustlings + ]; + }; + }); +} diff --git a/info.toml b/info.toml index 060643d7..8356f6ab 100644 --- a/info.toml +++ b/info.toml @@ -386,11 +386,9 @@ 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 :) +For get_fees: This method takes an additional argument, is there a field in the Package struct that this relates to? Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html""" @@ -416,8 +414,8 @@ path = "exercises/enums/enums3.rs" mode = "test" hint = """ As a first step, you can define enums to compile this code without errors. -and then create a match expression in `process()`. -Note that you need to deconstruct some message variants +and then create a match expression in `process()`. +Note that you need to deconstruct some message variants in the match expression to get value in the variant.""" # STRINGS @@ -449,7 +447,7 @@ path = "exercises/strings/strings3.rs" mode = "test" hint = """ There's tons of useful standard library functions for strings. Let's try and use some of -them! +them: ! For the compose_me method: You can either use the `format!` macro, or convert the string slice into an owned string, which you can then freely extend.""" @@ -476,7 +474,7 @@ name = "modules2" path = "exercises/modules/modules2.rs" mode = "compile" hint = """ -The delicious_snacks module is trying to present an external interface that is +The delicious_snacks module is trying to present an external interface that is different than its internal structure (the `fruits` and `veggies` modules and associated constants). Complete the `use` statements to fit the uses in main and find the one keyword missing for both constants.""" @@ -623,12 +621,12 @@ path = "exercises/error_handling/errors5.rs" mode = "compile" hint = """ There are two different possible `Result` types produced within `main()`, which are -propagated using `?` operators. How do we declare a return type from `main()` that allows both? +propagated using `?` operators. How do we declare a return type from `main()` that allows both? Under the hood, the `?` operator calls `From::from` on the error value to convert it to a boxed trait object, a `Box`. This boxed trait object is polymorphic, and since all -errors implement the `error:Error` trait, we can capture lots of different errors in one "Box" -object. +errors implement the `error::Error` trait, we can capture lots of different errors in one "Box" +object. Check out this section of the book: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator @@ -667,7 +665,7 @@ 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. +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]] @@ -697,7 +695,7 @@ name = "traits2" path = "exercises/traits/traits2.rs" mode = "test" hint = """ -Notice how the trait takes ownership of 'self',and returns `Self'. +Notice how the trait takes ownership of 'self',and returns `Self`. Try mutating the incoming string vector. Have a look at the tests to see what the result should look like! @@ -818,9 +816,9 @@ Step 1: We need to apply something to the collection `my_fav_fruits` before we start to go through it. What could that be? Take a look at the struct definition for a vector for inspiration: https://doc.rust-lang.org/std/vec/struct.Vec.html. -Step 2 & step 2.1: +Step 2 & step 3: Very similar to the lines above and below. You've got this! -Step 3: +Step 4: An iterator goes through all elements in a collection, but what if we've run out of elements? What should we expect here? If you're stuck, take a look at https://doc.rust-lang.org/std/iter/trait.Iterator.html for some ideas. @@ -862,7 +860,7 @@ case is a vector of integers and the failure case is a DivisionError. The list_of_results function needs to return a vector of results. -See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how +See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how the `FromIterator` trait is used in `collect()`. This trait is REALLY powerful! It can make the solution to this exercise infinitely easier.""" @@ -943,7 +941,7 @@ After using drop() to move the Planets out of scope individually, the reference In the end the sun only has one reference again, to itself. See more at: https://doc.rust-lang.org/book/ch15-04-rc.html -* Unforunately Pluto is no longer considered a planet :( +* Unfortunately Pluto is no longer considered a planet :( """ [[exercises]] @@ -964,12 +962,12 @@ name = "threads1" path = "exercises/threads/threads1.rs" mode = "compile" hint = """ -`JoinHandle` is a struct that is returned from a spawned thread: +`JoinHandle` is a struct that is returned from a spawned thread: https://doc.rust-lang.org/std/thread/fn.spawn.html -A challenge with multi-threaded applications is that the main thread can +A challenge with multi-threaded applications is that the main thread can finish before the spawned threads are completed. -https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handle +https://doc.rust-lang.org/book/ch16-01-threads.html#waiting-for-all-threads-to-finish-using-join-handles Collect the JoinHandles and wait for them to finish. https://doc.rust-lang.org/std/thread/struct.JoinHandle.html @@ -1073,11 +1071,11 @@ path = "exercises/clippy/clippy1.rs" mode = "clippy" hint = """ Rust stores the highest precision version of any long or inifinite precision -mathematical constants in the rust standard library. +mathematical constants in the Rust standard library. https://doc.rust-lang.org/stable/std/f32/consts/index.html We may be tempted to use our own approximations for certain mathematical constants, -but clippy recognizes those imprecise mathematical constants as a source of +but clippy recognizes those imprecise mathematical constants as a source of potential error. See the suggestions of the clippy warning in compile output and use the appropriate replacement constant from std::f32::consts...""" diff --git a/shell.nix b/shell.nix new file mode 100644 index 00000000..fa2a56c7 --- /dev/null +++ b/shell.nix @@ -0,0 +1,6 @@ +(import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock); +in fetchTarball { + url = + "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; +}) { src = ./.; }).shellNix diff --git a/src/exercise.rs b/src/exercise.rs index 4be3a2cc..c0dae34e 100644 --- a/src/exercise.rs +++ b/src/exercise.rs @@ -20,7 +20,7 @@ fn temp_file() -> String { .filter(|c| c.is_alphanumeric()) .collect(); - format!("./temp_{}_{}", process::id(), thread_id) + format!("./temp_{}_{thread_id}", process::id()) } // The mode of the exercise. diff --git a/src/main.rs b/src/main.rs index 8eebc086..6dc18e8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ mod run; mod verify; // In sync with crate version -const VERSION: &str = "5.2.0"; +const VERSION: &str = "5.3.0"; #[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code @@ -121,12 +121,12 @@ fn main() { let args: Args = argh::from_env(); if args.version { - println!("v{}", VERSION); + println!("v{VERSION}"); std::process::exit(0); } if args.nested.is_none() { - println!("\n{}\n", WELCOME); + println!("\n{WELCOME}\n"); } if !Path::new("info.toml").exists() { @@ -150,7 +150,7 @@ fn main() { let verbose = args.nocapture; let command = args.nested.unwrap_or_else(|| { - println!("{}\n", DEFAULT_OUT); + println!("{DEFAULT_OUT}\n"); std::process::exit(0); }); match command { @@ -179,11 +179,11 @@ fn main() { }; if solve_cond && (filter_cond || subargs.filter.is_none()) { let line = if subargs.paths { - format!("{}\n", fname) + format!("{fname}\n") } else if subargs.names { format!("{}\n", e.name) } else { - format!("{:<17}\t{:<46}\t{:<7}\n", e.name, fname, status) + format!("{:<17}\t{fname:<46}\t{status:<7}\n", e.name) }; // Somehow using println! leads to the binary panicking // when its output is piped. @@ -202,7 +202,7 @@ fn main() { }); let percentage_progress = exercises_done as f32 / exercises.len() as f32 * 100.0; println!( - "Progress: You completed {} / {} exercises ({:.2} %).", + "Progress: You completed {} / {} exercises ({:.1} %).", exercises_done, exercises.len(), percentage_progress @@ -266,7 +266,7 @@ fn main() { "{emoji} All exercises completed! {emoji}", emoji = Emoji("🎉", "★") ); - println!("\n{}\n", FENISH_LINE); + println!("\n{FENISH_LINE}\n"); } Ok(WatchStatus::Unfinished) => { println!("We hope you're enjoying learning about Rust!"); @@ -289,7 +289,7 @@ fn spawn_watch_shell( let input = input.trim(); if input == "hint" { if let Some(hint) = &*failed_exercise_hint.lock().unwrap() { - println!("{}", hint); + println!("{hint}"); } } else if input == "clear" { println!("\x1B[2J\x1B[1;1H"); @@ -306,10 +306,10 @@ fn spawn_watch_shell( println!("Watch mode automatically re-evaluates the current exercise"); println!("when you edit a file's contents.") } else { - println!("unknown command: {}", input); + println!("unknown command: {input}"); } } - Err(error) => println!("error reading command: {}", error), + Err(error) => println!("error reading command: {error}"), } }); } @@ -329,7 +329,7 @@ fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise { .iter() .find(|e| e.name == name) .unwrap_or_else(|| { - println!("No exercise found for '{}'!", name); + println!("No exercise found for '{name}'!"); std::process::exit(1) }) } @@ -392,7 +392,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result { Err(RecvTimeoutError::Timeout) => { // the timeout expired, just check the `should_quit` variable below then loop again } - Err(e) => println!("watch error: {:?}", e), + Err(e) => println!("watch error: {e:?}"), } // Check if we need to exit if should_quit.load(Ordering::SeqCst) { diff --git a/src/run.rs b/src/run.rs index 826f00a6..1e2e56cf 100644 --- a/src/run.rs +++ b/src/run.rs @@ -35,7 +35,7 @@ pub fn reset(exercise: &Exercise) -> Result<(), ()> { // This is strictly for non-test binaries, so output is displayed fn compile_and_run(exercise: &Exercise) -> Result<(), ()> { let progress_bar = ProgressBar::new_spinner(); - progress_bar.set_message(format!("Compiling {}...", exercise)); + progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.enable_steady_tick(100); let compilation_result = exercise.compile(); @@ -52,7 +52,7 @@ fn compile_and_run(exercise: &Exercise) -> Result<(), ()> { } }; - progress_bar.set_message(format!("Running {}...", exercise)); + progress_bar.set_message(format!("Running {exercise}...")); let result = compilation.run(); progress_bar.finish_and_clear(); diff --git a/src/verify.rs b/src/verify.rs index 6f877831..97471b8f 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -16,7 +16,7 @@ pub fn verify<'a>( let (num_done, total) = progress; let bar = ProgressBar::new(total as u64); bar.set_style(ProgressStyle::default_bar() - .template("Progress: [{bar:60.green/red}] {pos}/{len}") + .template("Progress: [{bar:60.green/red}] {pos}/{len} {msg}") .progress_chars("#>-") ); bar.set_position(num_done as u64); @@ -29,6 +29,8 @@ pub fn verify<'a>( if !compile_result.unwrap_or(false) { return Err(exercise); } + let percentage = num_done as f32 / total as f32 * 100.0; + bar.set_message(format!("({:.1} %)", percentage)); bar.inc(1); } Ok(()) @@ -48,7 +50,7 @@ pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> { // Invoke the rust compiler without running the resulting binary fn compile_only(exercise: &Exercise) -> Result { let progress_bar = ProgressBar::new_spinner(); - progress_bar.set_message(format!("Compiling {}...", exercise)); + progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.enable_steady_tick(100); let _ = compile(exercise, &progress_bar)?; @@ -60,12 +62,12 @@ fn compile_only(exercise: &Exercise) -> Result { // Compile the given Exercise and run the resulting binary in an interactive mode fn compile_and_run_interactively(exercise: &Exercise) -> Result { let progress_bar = ProgressBar::new_spinner(); - progress_bar.set_message(format!("Compiling {}...", exercise)); + progress_bar.set_message(format!("Compiling {exercise}...")); progress_bar.enable_steady_tick(100); let compilation = compile(exercise, &progress_bar)?; - progress_bar.set_message(format!("Running {}...", exercise)); + progress_bar.set_message(format!("Running {exercise}...")); let result = compilation.run(); progress_bar.finish_and_clear(); @@ -86,7 +88,7 @@ fn compile_and_run_interactively(exercise: &Exercise) -> Result { // the output if verbose is set to true fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool) -> Result { let progress_bar = ProgressBar::new_spinner(); - progress_bar.set_message(format!("Testing {}...", exercise)); + progress_bar.set_message(format!("Testing {exercise}...")); progress_bar.enable_steady_tick(100); let compilation = compile(exercise, &progress_bar)?; @@ -165,16 +167,16 @@ fn prompt_for_completion(exercise: &Exercise, prompt_output: Option) -> println!(); if no_emoji { - println!("~*~ {} ~*~", success_msg) + println!("~*~ {success_msg} ~*~") } else { - println!("🎉 🎉 {} 🎉 🎉", success_msg) + println!("🎉 🎉 {success_msg} 🎉 🎉") } println!(); if let Some(output) = prompt_output { println!("Output:"); println!("{}", separator()); - println!("{}", output); + println!("{output}"); println!("{}", separator()); println!(); }