diff --git a/.all-contributorsrc b/.all-contributorsrc index 0917089a..9e2f307f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1569,6 +1569,141 @@ "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" + ] } ], "contributorsPerLine": 8, @@ -1576,5 +1711,6 @@ "projectOwner": "rust-lang", "repoType": "github", "repoHost": "https://github.com", - "skipCi": true + "skipCi": true, + "commitConvention": "angular" } diff --git a/.gitignore b/.gitignore index 623e11d6..05318167 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,8 @@ exercises/clippy/Cargo.toml exercises/clippy/Cargo.lock rust-project.json .idea -.vscode +.vscode/* +!.vscode/extensions.json *.iml *.o rustlings/ \ No newline at end of file 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 29d330d2..44d8a0ff 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -9,221 +9,242 @@ 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

πŸ–‹

rzrymiak

πŸ–‹

Miguel Raz GuzmΓ‘n Macedo

πŸ–‹

Magnus Markling

πŸ–‹
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

πŸ–‹
diff --git a/Cargo.toml b/Cargo.toml index dadded68..3f5b253d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "rustlings" version = "5.2.1" -authors = ["Liv ", "Carol (Nichols || Goulding) "] +authors = [ + "Liv ", + "Carol (Nichols || Goulding) ", +] edition = "2021" [dependencies] diff --git a/README.md b/README.md index 9b619d6f..38972a4b 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.2.1) +git clone -b 5.2.1 --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`: @@ -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 diff --git a/exercises/conversions/as_ref_mut.rs b/exercises/conversions/as_ref_mut.rs index 9f479739..c9eed7d0 100644 --- a/exercises/conversions/as_ref_mut.rs +++ b/exercises/conversions/as_ref_mut.rs @@ -17,7 +17,7 @@ fn char_counter(arg: T) -> usize { arg.as_ref().chars().count() } -// Squares a number using AsMut. Add the trait bound as is appropriate and +// Squares a number using as_mut(). Add the trait bound as is appropriate and // implement the function body. fn num_sq(arg: &mut T) { ??? 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/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/quiz2.rs b/exercises/quiz2.rs index 0082b003..d0df0f42 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! pub enum Command { Uppercase, diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs index c29e1ab3..a91c3d56 100644 --- a/exercises/structs/structs3.rs +++ b/exercises/structs/structs3.rs @@ -82,5 +82,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/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..15c82b77 --- /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.2.1"; + + 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 6feeb186..df3820d2 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 @@ -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.""" @@ -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 @@ -1077,7 +1075,7 @@ 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 cd79d9ff..bf8503d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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!(); }