1
0
mirror of https://github.com/rust-lang/rustlings.git synced 2025-12-26 00:11:49 +02:00

Compare commits

...

239 Commits
1.5.0 ... 4.0.0

Author SHA1 Message Date
mokou
f9ccc6a289 release: 4.0.0 2020-07-08 11:35:27 +02:00
fmoko
b32a666541 Merge pull request #458 from Sowed/main 2020-07-01 10:19:45 +02:00
iamcastelli
b636825de3 Merge pull request #1 from Sowed/then-to-than-docs-patch
fix: Change then to than
2020-06-27 16:49:39 +04:00
iamcastelli
ddd98ad75d fix: Change then to than
`than` makes more grammatical sense than `then` in this context.
2020-06-27 15:58:53 +04:00
mokou
d355927024 Merge remote-tracking branch 'origin/master' into main 2020-06-22 04:47:27 +02:00
fmoko
75c0053bb1 Merge pull request #433 from SebastienCaunes/fix#432
fix : Use of integer for prices, therefore also for weight
2020-06-22 00:09:09 +02:00
mokou
55a9284665 chore: Move from master branch to main branch 2020-06-14 14:48:51 +02:00
Alexx Roche
113cdae2d4 fix(arc1): Passively introduce attributes (#429)
Ensure that std::sync::Arc is actually used, as this exercise can be compiled using things already learnt in previous exercises.
2020-06-14 12:15:35 +02:00
fmoko
c6295ade33 Merge pull request #428 from millefalcon/master
Added example with `String` to show the AsRef working
2020-06-13 22:15:57 +02:00
fmoko
e1e453075f Merge pull request #422 from AbdouSeck/show-tests-prints 2020-06-12 23:04:51 +02:00
Sebastien Caunes
9ca08b8f2b fix : Use of integer for prices, therefore also for weight
rename confusing "from" and "to" to sender_country and recipient_country as suggested
2020-06-11 11:44:47 -05:00
tim bangma
f47d3f422d docs: Update Invoke-WebRequest to Start-BitsTransfer (#373) 2020-06-10 10:51:03 +02:00
Alexx Roche
e6bd8021d9 fix(generics2): Guide students to the answer (#430) 2020-06-09 13:54:18 +02:00
millefalcon
307252e9ae Added example to show the AsRef working 2020-06-08 07:51:34 -04:00
Alexx Roche
bb2ca25110 fix(box1): fix comment typo (#426)
Doesn't effect the code.
2020-06-06 12:07:39 +02:00
Abdou Seck
9e4fb1009f fix(installation): Provide a backup git reference when tag can't be curl
closes #423

If the parsed JSON data curled during a bash installation is not valid, use the repository's tag files
as a backup. If those files don't exist somehow, then checkout the master branch and install it.
2020-06-05 16:33:14 -04:00
Abdou Seck
8ad5f9bf53 feat: Add a --nocapture option to display test harnesses' outputs
This new feature can be accessed by invoking rustlings with --nocapture.

Both unit and integration tests added.

closes #262

BREAKING CHANGES:
The following function take a new boolean argument:
	* `run`
	* `verify`
	* `test`
	* `compile_and_test`
2020-06-04 11:18:26 -04:00
Abdou Seck
02a2fe4871 Collapse nested if statements 2020-06-04 11:18:09 -04:00
Abdou Seck
40741c5b0b Use .to_string rather than format macro 2020-06-03 17:18:48 -04:00
Alexx Roche
0dd1c6ca6b fix: rename quiz1 to tests1 in info (#420)
`rustlings run tests1` wasn't working because of this typo.
2020-06-03 20:07:06 +02:00
Alexx Roche
5563adbb89 fix: fix quiz naming inconsistency (#421)
Inconsistent naming when compared with the other quiz files.
2020-06-03 20:06:35 +02:00
Alexx Roche
524e17df10 fix(variables6): minor typo (#419)
Looks like this was cloned from variables5.rs
2020-06-03 13:34:43 +02:00
fmoko
73e848e96f Merge pull request #416 from danwilhelm/traits-readme
feat: Add traits README
2020-05-30 17:58:31 +02:00
fmoko
5f0806967c Merge pull request #409 from AlexandruGG/feature/box-exercise 2020-05-30 17:58:16 +02:00
Dan Wilhelm
173bb14140 feat: Add traits README 2020-05-28 20:21:33 -07:00
fmoko
918f310674 Merge pull request #410 from tsauvajon/fix-option1
fix(option1): Don't add only zeros to the numbers array
2020-05-29 00:33:00 +02:00
fmoko
a75fdbd8ad Merge pull request #415 from danwilhelm/powershell-correction
chore: Fix PowerShell capitalization
2020-05-29 00:32:45 +02:00
Dan Wilhelm
9d3f189b0e chore: Fix PowerShell capitalization 2020-05-28 14:51:20 -07:00
AlexandruGG
7e79c51222 Add .idea to gitignore 2020-05-28 18:01:32 +01:00
fmoko
a180d831a1 Merge pull request #413 from danwilhelm/generics3-90chars 2020-05-28 10:15:55 +02:00
Dan Wilhelm
e81adc2752 chore: Add Powershell reminder 2020-05-28 09:35:29 +02:00
Allan Soares Duarte
500422d594 chore: Update variables6.rs book link 2020-05-28 09:33:15 +02:00
Dan Wilhelm
0311c03735 chore: Limit generics3 lines to 90 chars 2020-05-27 23:39:11 -07:00
AlexandruGG
df81141d6f Address PR feedback: add tests 2020-05-27 10:03:59 +01:00
Thomas Sauvajon
cce6a44277 fix(option1): Don't add only zeros to the numbers array 2020-05-27 18:55:12 +10:00
AlexandruGG
7479a4737b feat: Add box1.rs exercise 2020-05-26 21:46:24 +01:00
Evan Carroll
06ef4cc654 fix: confine the user further in variable exercises
We want to teach a specific lesson. To ensure that we do, let's try to
provide more clarity on what the user should not do.
2020-05-25 10:09:11 +02:00
Jade McGough
c7c3130507 chore: remove struct2 hint comment 2020-05-20 08:31:28 +02:00
Sanjay K
010a045692 feat: renames test to quiz, fixes #244
BREAKING CHANGE

* changed test to quiz: fixes issues in #244
* fixed info.toml: #244
* fixed naming related issues
2020-05-19 18:47:44 +02:00
fmoko
51666609f1 Merge pull request #365 from sjmann/generics-2-fix 2020-05-19 17:49:55 +02:00
Stefan Kupresak
10967bce57 fix(option2): Add TODO to comments (#400) 2020-05-16 22:48:18 +02:00
IkaR49
763aa6e378 feat: Rewrite try_from_into (#393) 2020-05-15 23:02:57 +02:00
Gaurang Tandon
d6c0a688e6 fix(test2): name of type String and &str (#394) 2020-05-13 12:38:14 +02:00
Jawaad Mahmood
9f75554f2a fix(options1): Add hint about Array Initialization (#389) 2020-05-10 13:21:29 +02:00
Evan Carroll
2b20c8a0f5 fix(errorsn): Try harder to confine the user. (#388) 2020-05-06 21:12:15 +02:00
fmoko
1b4590b42b Merge pull request #385 from siobhanjacobson/fix-enums3-test 2020-05-05 19:50:28 +02:00
Siobhan Jacobson
09e89bbcd3 Update Message::Move in the enums3 test to take a Point. 2020-05-04 18:59:23 -04:00
fmoko
7c4b1f910c Merge pull request #372 from DiD92/exercise_structs3 2020-05-03 19:44:26 +02:00
fmoko
3ceabe91f8 Merge pull request #383 from wrobstory/wrobstory-exercises 2020-05-03 19:44:08 +02:00
fmoko
a39ffb2fb8 Merge pull request #368 from apatniv/update_test_case 2020-05-03 13:31:46 +02:00
apatniv
41f989135d Review Comments: Add other test cases 2020-05-02 20:41:11 -04:00
Rob Story
f6cffc7e48 fix(option1): Add cast to usize, as it is confusing in the context of an exercise about Option 2020-05-02 16:39:37 -07:00
Rob Story
1da84b5f7c feat: Add if2 exercise 2020-05-02 13:02:16 -07:00
fmoko
ebfe76cdb6 Merge pull request #382 from bertonha/deprecated-description 2020-05-02 18:38:32 +02:00
Christofer Bertonha
c301814d68 chore: Remove deprecated description from error_handling/errorsn.rs 2020-05-02 18:30:11 +02:00
fmoko
09478571df Merge pull request #378 from Darrenmeehan/patch-2 2020-04-30 18:33:46 +02:00
Jihchi Lee
a901499ede fix(from_into.rs): typo 2020-04-30 15:53:50 +02:00
fmoko
de65026db0 Merge pull request #377 from danwilhelm/dw-typos 2020-04-30 09:21:42 +02:00
fmoko
071b51d588 Check if python is available while checking for git, rustc and cargo (#376) 2020-04-30 09:21:17 +02:00
Darren Meehan
80390d8a03 docs: Remove outdated MacOS instructions
The quoted file no longer exists
2020-04-30 08:13:41 +01:00
Dan Wilhelm
9590082848 fix: update iterator and macro text for typos and clarity
- /macros/README.md: Typo "modules" => "macros"
- iterators2.py: Reduce line length to <90-char width.
- iterators4.py: Update 'fun' => 'challenge' as per PR#177
- rustlings hint iterators4: improve clarity
2020-04-29 19:11:54 -07:00
Abdou Seck
9cfb617d5b fix(installation): Check if python is available while checking for git,rustc and cargo
closes #374
2020-04-29 15:11:05 -04:00
Dídac Sementé Fernández
b66e2e0962 feat: Added exercise structs3.rs 2020-04-27 20:26:34 +02:00
Aleksei Trifonov
32721bbc83 chore: fix missing space in the hint for errorsn.rs 2020-04-25 10:25:41 +02:00
apatniv
19fb1c240c test: Add missing test case for from_str exercise 2020-04-21 22:51:56 -04:00
Steven Mann
630ff0e00b chore: add explanatory comment to clippy1 2020-04-21 18:50:00 +02:00
sjmann
964c974a02 fix: update generics2 closes #362 2020-04-21 13:34:25 +01:00
lebedevsergey
c9e4f2cfb4 fix: confusing comment in conversions/try_from_into.rs
Co-authored-by: Lebedev <sergey.lebedev@corp.mail.ru>
2020-04-17 15:43:01 +02:00
Said Aspen
a3a554aeed Hints for structs1 and structs2 (#355) 2020-04-16 16:21:36 +02:00
Ufuk Celebi
6c3cc2caf5 chore: delete orphaned error_handling/option1.rs
`error_handling/option1.rs` has been replaced by `option/option1.rs` and
is not referenced in `info.toml` any more.
2020-04-15 23:52:31 +02:00
Said Aspen
5999acd24a feat: Add exercise variables6 covering const (#352) 2020-04-14 10:13:20 +02:00
allcontributors[bot]
59f56b24d9 docs: add saidaspen as a contributor (#353)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-14 10:12:51 +02:00
Saurav
abd0ec379c chore: update variables5.rs book link (#351)
chore: update variables5.rs book link

chore: update variables5.rs book link
2020-04-12 19:35:20 +02:00
fmoko
cfb98a5617 docs: remove now obsolete credits section 2020-04-12 01:03:28 +02:00
allcontributors[bot]
fafcffed25 docs: add crodjer as a contributor (#350)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 01:00:22 +02:00
allcontributors[bot]
3f1209ce19 docs: add sanjaykdragon as a contributor (#349)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:59:07 +02:00
allcontributors[bot]
b217961254 docs: add sl4m as a contributor (#348)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:57:55 +02:00
allcontributors[bot]
cd06b39a42 docs: add Tarnadas as a contributor (#347)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:57:18 +02:00
allcontributors[bot]
84e1f85be2 docs: add sjmann as a contributor (#346)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:56:40 +02:00
allcontributors[bot]
f060f099d4 docs: add pbx as a contributor (#345)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:55:30 +02:00
allcontributors[bot]
e093af4c05 docs: add TorbenJ as a contributor (#344)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:54:59 +02:00
allcontributors[bot]
eface5ef45 docs: add harrisonmetz as a contributor (#343)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:54:28 +02:00
allcontributors[bot]
5b72f478a7 docs: add gnodarse as a contributor (#342)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:53:46 +02:00
allcontributors[bot]
5f5a0465cb docs: add codehearts as a contributor (#341)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: fmoko <mokou@posteo.de>
2020-04-12 00:52:51 +02:00
allcontributors[bot]
f509e479a1 docs: add Socratides as a contributor (#339)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:51:02 +02:00
allcontributors[bot]
ad00c2cf51 docs: add AbdouSeck as a contributor (#338)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:49:57 +02:00
allcontributors[bot]
a20f80623e docs: add rahatarmanahmed as a contributor (#337)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:49:05 +02:00
allcontributors[bot]
f26dca6d8e docs: add jensim as a contributor (#336)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:48:12 +02:00
fmoko
9ea089a5d9 docs: bump contributors per line down to 8 2020-04-12 00:47:24 +02:00
allcontributors[bot]
f07d1c9488 docs: add jrvidal as a contributor (#335)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:46:29 +02:00
allcontributors[bot]
0d0c79a5cb docs: add WofWca as a contributor (#334)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:45:01 +02:00
allcontributors[bot]
9bb5aa583f docs: add workingjubilee as a contributor (#333)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:44:27 +02:00
allcontributors[bot]
f26ed591f3 docs: add nyxtom as a contributor (#332)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:43:54 +02:00
allcontributors[bot]
0b4576a028 docs: add gdoenlen as a contributor (#331)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:43:08 +02:00
allcontributors[bot]
d7bb220ba3 docs: add vyaslav as a contributor (#330)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:42:30 +02:00
allcontributors[bot]
f907c710b2 docs: add Dylnuge as a contributor (#329)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:41:21 +02:00
allcontributors[bot]
c6bcb319f8 docs: add ajaxm as a contributor (#328)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:40:26 +02:00
allcontributors[bot]
443600194c docs: add nkanderson as a contributor (#327)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:39:56 +02:00
allcontributors[bot]
7b6f14c25a docs: add petemcfarlane as a contributor (#326)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:39:14 +02:00
allcontributors[bot]
887d919323 docs: add MrFroop as a contributor (#325)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:38:25 +02:00
allcontributors[bot]
74d32f0cca docs: add Jesse-Cameron as a contributor (#324)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:37:45 +02:00
allcontributors[bot]
3f479be7e7 docs: add danwilhelm as a contributor (#323)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:36:55 +02:00
allcontributors[bot]
95d02a23d0 docs: add miller-time as a contributor (#322)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:35:42 +02:00
allcontributors[bot]
8b59b9852f docs: add briankung as a contributor (#321)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:34:41 +02:00
allcontributors[bot]
53bda94f77 docs: add eddyp as a contributor (#320)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:34:06 +02:00
allcontributors[bot]
52580cfd0d docs: add dendi239 as a contributor (#319)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:32:56 +02:00
allcontributors[bot]
cf3d5b44e6 docs: add yvan-sraka as a contributor (#318)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:32:07 +02:00
allcontributors[bot]
491dc2e5ca docs: add cjpearce as a contributor (#317)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:31:21 +02:00
allcontributors[bot]
b89cdef120 docs: add mgeier as a contributor (#316)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:30:31 +02:00
allcontributors[bot]
348fe339b9 docs: add zacanger as a contributor (#315)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:28:52 +02:00
fmoko
e79d7ea981 docs: increase contributors per line 2020-04-12 00:28:06 +02:00
allcontributors[bot]
e7841ba2ed docs: add ColinPitrat as a contributor (#314)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:27:26 +02:00
allcontributors[bot]
37687e9323 docs: add kisom as a contributor (#313)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:24:27 +02:00
allcontributors[bot]
b749314944 docs: add abagshaw as a contributor (#312)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:23:18 +02:00
allcontributors[bot]
3eb0fb5aa6 docs: add shaunbennett as a contributor (#311)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:22:30 +02:00
allcontributors[bot]
44a4cf3b27 docs: add Delet0r as a contributor (#310)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:21:37 +02:00
allcontributors[bot]
9a8762ba6e docs: add evestera as a contributor (#309)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:21:03 +02:00
allcontributors[bot]
2e1bd5ef4e docs: add lukabavdaz as a contributor (#308)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:20:06 +02:00
allcontributors[bot]
a9dc101701 docs: add spacekookie as a contributor (#307)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:18:53 +02:00
allcontributors[bot]
e2835de137 docs: add hynek as a contributor (#306)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:17:40 +02:00
allcontributors[bot]
535e7a6a28 docs: add robertlugg as a contributor (#305)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:16:50 +02:00
allcontributors[bot]
fe96de2e2d docs: add QuietMisdreavus as a contributor (#304)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:14:45 +02:00
allcontributors[bot]
9fd881443f docs: add carols10cents as a contributor (#303)
* docs: update README.md [skip ci]

* docs: create .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-04-12 00:09:23 +02:00
mokou
2ff3f7ae13 3.0.0 2020-04-12 00:01:08 +02:00
fmoko
2b80f6ed41 chore: Remove duplicate option1 exercise 2020-04-11 17:27:10 +02:00
Rohan Jain
3ab084a421 fix(run): compile clippy exercise files
Additionally to running clippy, also compile the exercise file so that
`rustling run clippy1` works after a successful completion of the
exercise.

closes #291

Signed-off-by: Rohan Jain <crodjer@gmail.com>
2020-04-11 08:58:23 +02:00
mokou
495174ff7c chore: remove travis ci
And add a buildkite build status badge
2020-04-08 12:27:28 +02:00
mokou
b049fa2c84 feat(ci): add buildkite config 2020-04-08 12:08:37 +02:00
fmoko
052f0aa7d4 Merge pull request #292 from Tuxified/patch-1
Remove duplicate not done comment
2020-04-08 11:23:49 +02:00
Tonći Galić
60393999b8 remove bottom comment instead of top 2020-04-08 11:00:11 +02:00
Roberto Vidal
b3a3351e8e fix: revert primitive_types4 (#296) 2020-04-08 10:42:35 +02:00
Sanjay K
86b5c08b9b feat: Add Option2 exercise (#290)
* added option2

* changed up the exercise, modified the help section

* Update exercises/option/option2.rs

Co-Authored-By: fmoko <mokou@posteo.net>

* Update exercises/option/option2.rs

Co-Authored-By: fmoko <mokou@posteo.net>

* Update exercises/option/option2.rs

Co-Authored-By: fmoko <mokou@posteo.net>

Co-authored-by: fmoko <mokou@posteo.net>
2020-04-07 20:16:10 +02:00
Tonći Galić
dab90f7b91 Remove duplicate not done comment
As indicated in #259 , I found it confusing to have 2 comments as the code wouldn't compile unless I solved both issues (I used the script from #281 to remove a comment and use `:wn` to go to next exercise, hence this tripped me).
2020-04-07 17:00:45 +02:00
fmoko
71d31256a6 Merge pull request #278 from jrvidal/output-mode
feature: adds "output" mode, resolves #270
2020-04-07 11:26:48 +02:00
Roberto Vidal
3b6d5c3aaa feature: makes "compile" exercise print output, resolves #270
When running "compile"-mode exercises in interactive `verify` mode,
we print their output when we prompt the learner if they want to
continue. This improves the "experimentation" experience, since
trying different things does produce a visible change.
2020-04-06 16:17:14 +02:00
fmoko
7ce42941ea Merge pull request #282 from sanjaykdragon/master
feat: added option exercise
2020-04-05 15:58:09 +02:00
Sanjay K
3f8171475c updated info.toml 2020-04-05 09:45:07 -04:00
fmoko
b135b589e0 Merge pull request #280 from sjmann/generics-exercises
feat: added generics exercises
2020-04-05 14:40:34 +02:00
Sanjay K
05ca3d77f7 Merge branch 'master' of https://github.com/sanjaykdragon/rustlings 2020-04-02 08:41:14 -04:00
Sanjay K
6deee7e3e9 fixed spacing 2020-04-02 08:40:59 -04:00
fmoko
9dc404077a Merge pull request #288 from vjousse/fix-traits-doc
chore(TRAITS1): don't hardcode documentation version
2020-03-26 21:16:52 +01:00
Vincent Jousse
30e6af6069 Don't hardcode documentation version for traits 2020-03-26 15:22:22 +01:00
Sanjay K
9788496a85 Update option1.rs 2020-03-11 13:44:41 -04:00
Sanjay K
6d3a412d47 Update option1.rs 2020-03-11 13:44:10 -04:00
bors
700b236f4d Auto merge of #284 - sl4m:update-from-into-ex, r=fmoko
Adds additional test to meet exercise rules

This PR adds an additional test to meet this exercise [rule](https://github.com/rust-lang/rustlings/blob/master/exercises/conversions/from_into.rs#L33).
2020-03-11 15:06:23 +00:00
skim
bc22ec382f adds additional test to meet exercise rules 2020-03-11 07:58:04 -07:00
Sanjay K
135e5d47a7 feat: added excercise for option 2020-03-05 15:52:54 -05:00
sjmann
0f8001ea44 add I AM NOT DONE comments 2020-02-28 00:31:55 +00:00
sjmann
5b6e23c323 removed artifact from manual testing 2020-02-28 00:29:30 +00:00
sjmann
29b30ec946 Merge branch 'master' of https://github.com/sjmann/rustlings into generics-exercises 2020-02-28 00:19:45 +00:00
sjmann
76be5e4e99 feat: added new exercises for generics 2020-02-28 00:09:08 +00:00
mokou
8b9479071c 2.2.1 2020-02-27 19:22:55 +01:00
mokou
3d9b03c52b fix: Re-add cloning the repo to install scripts 2020-02-27 19:19:31 +01:00
bors
a03d9655a8 Auto merge of #269 - Tarnadas:master, r=fmoko
feat: Add clippy lints

This is a feature PR which adds the possiblity to create clippy exercises.

Clippy has many awesome linting rules, which can give a deeper understanding about the Rust programming language, therefor I made this PR.
2020-02-26 14:22:51 +00:00
Mario Reder
1e2fd9c92f feat: Add clippy lints
- adds a new 'clippy' category for exercises
- clippy exercises should throw no warnings
- install script now also installs clippy

is related to https://github.com/rust-lang/rust-clippy/issues/2604
2020-02-26 14:07:07 +01:00
bors
7e8530b21f Auto merge of #271 - jrvidal:refactor, r=fmoko
refactor: exercise evaluation

After working a bit on #270, I realized that it'd be useful to first perform a minor refactor of exercise evaluation.

* Now we have standard methods to compile + execute that return `Result`s.
* Success/failure messages are standardized.
2020-02-26 11:48:01 +00:00
bors
98358597a9 Auto merge of #277 - sjmann:update-ignore, r=fmoko
chore: update gitignore to ignore pdb files

Pr for issue #275
2020-02-26 10:46:53 +00:00
sjmann
8064facbb8 chore: update gitignore to ignore pdb files 2020-02-26 10:43:13 +00:00
sjmann
f981dcfde4 Merge branch 'master' of https://github.com/sjmann/rustlings 2020-02-26 10:38:50 +00:00
mokou
6eb62fa2ce 2.2.0 2020-02-25 23:00:19 +01:00
bors
78295ce92f Auto merge of #274 - sjmann:master, r=fmoko
chore: fixed merge conflicts from traits exercises added by s-marios

I hope this doesn't step on any toes but I wanted to try the traits exercises from #216 so I updated them to match the new structure with hints included in info.toml
2020-02-25 21:27:39 +00:00
fmoko
358fb473cd Merge pull request #276 from stigjb-forks/testing-test4
Enable test for exercise test4
2020-02-25 14:25:22 +01:00
Stig Johan Berggren
a45486f2d0 Add a second test case 2020-02-25 14:25:03 +01:00
Stig Johan Berggren
8b971ffab6 Enable test for exercise test4 2020-02-25 14:13:10 +01:00
Steven Mann
dc84aacc65 remove confusing comment wording 2020-02-25 11:00:09 +00:00
sjmann
bbf8922ef7 Merge remote-tracking branch 'upstream/master' 2020-02-25 10:00:38 +00:00
sjmann
b559cdd73f added traits exercises 2020-02-25 09:48:50 +00:00
fmoko
ec51cdb229 Merge pull request #273 from sjmann/master
docs(iterators): Updated iterators readme to account for iterators4 exercise
2020-02-22 15:34:51 +01:00
sjmann
a3f70124dc fixed typo 2020-02-22 14:28:07 +00:00
sjmann
bec8e3a644 reworded missing exercise explanation 2020-02-22 13:04:37 +00:00
bors
c228a06e49 Auto merge of #272 - QuintenJohnson:fix/installation-warning-messages, r=fmoko
fix(installation): make fatal errors more obvious

I initially ran the installation script without rust installed. The fact that the error message was labeled with WARNING made me unsure whether installation was successful or I needed to re-run after installing rust. There's an error code returned on fatal errors, but this change will make things clearer.
2020-02-21 20:56:11 +00:00
Quinten Johnson
17d0951e66 fix(installation): make fatal errors more obvious 2020-02-21 11:52:47 -06:00
Roberto Vidal
43dc31193a refactor: exercise evaluation
Exercise evaluation (compilation + execution) now uses Results
Success/failure messages are standardized
2020-02-20 20:27:05 +01:00
fmoko
83bbd9e82e chore: Correct test command in tests1.rs comment (#267)
chore: Correct test command in tests1.rs comment
2020-01-29 15:39:10 +01:00
Jason Tsai
39fa7ae8b7 chore: Correct test command in tests1.rs comment 2020-01-29 13:48:43 +08:00
fmoko
3161a8fd9d Fixed mangled sentence from book; edited for clarity (#266)
Fixed mangled sentence from book; edited for clarity
2020-01-25 13:27:53 +01:00
Paul Bissex
ade52ffb73 Fixed mangled sentence from book; edited for clarity 2020-01-25 03:24:14 -05:00
fmoko
89c73647f1 Add variables5 to introduce shadowing (#264)
Add variables5 to introduce shadowing
2020-01-14 23:32:45 +01:00
Torben Jonas
0c73609e6f feat: Add variables5.rs exercise
closes #260
2020-01-14 21:10:07 +01:00
fmoko
19a93428b3 fix: Update deps to version compatable with aarch64-pc-windows (#263)
fix: Update deps to version compatable with aarch64-pc-windows
2020-01-11 12:23:23 +01:00
Harrison Metzger
32a9cf7b8d fix: Update deps to version compatable with aarch64-pc-windows 2020-01-11 02:45:38 -06:00
fmoko
c86b217e1d Created consistent money unit (#258)
Created consistent money unit
2019-12-30 16:48:04 +01:00
gnodarse
fd57f8f2c1 Created consistent money unit 2019-12-29 19:15:32 -05:00
bors
0d1f1a19b7 Auto merge of #253 - codehearts:watch-completion-message, r=fmoko
feat: Show a completion message when watching

The completion message is shown only once all exercises succeed and are
not annotated with "I AM NOT DONE." The watch command will also exit

closes #251

Let me know if there are any tests I could add or if the completion message should be tweaked!
2019-12-28 20:01:28 +00:00
Kate Hart
d25ee55a32 feat: Show a completion message when watching
The completion message is shown only once all exercises succeed and are
not annotated with "I AM NOT DONE." The watch command will also exit

closes #251
2019-12-26 20:27:49 -08:00
fmoko
3afa96bed4 Enable a test and improve per clippy's suggestion. (#256)
Enable a test and improve per clippy's suggestion.
2019-12-25 00:59:35 +01:00
dmitri-mamrukov
dfdf8093eb Enable a test and improve per clippy's suggestion. 2019-12-23 21:37:09 -05:00
fmoko
3906efcd52 fix(docs): Added a necessary step to Windows installation process 2019-12-22 13:21:24 +01:00
Socrates
2021a1ac7d Update README.md
Added an essential step to Windows installation process (Setting ExecutionPolicy to RemoteSigned because it wouldn't install otherwise).
2019-12-22 14:16:04 +02:00
bors
426a7bb87f Auto merge of #249 - AbdouSeck:conversions, r=fmoko
feat: Add type conversion and parsing exercises

This pull request adds exercises for converting values into specific types. The exercises uses string to struct type conversions, but most of the traits in the exercises can handle more than just string parsing and conversions.

The following traits are covered:
1. `From` and `Into`
2. `TryFrom` and `TryInto`
3. `AsRef`
4. `FromStr`

The `as` operator is also covered.
2019-12-16 16:41:03 +00:00
Abdou Seck
fc26b5e151 I AM NOT DONE comment in conversions exercise files 2019-12-16 11:33:00 -05:00
Abdou Seck
0c85dc1193 feat: Add type conversion and parsing exercises 2019-12-16 09:12:13 -05:00
marisa
fe10e06c37 fix(tests1): Change test command
Closes #243.
2019-12-16 13:05:25 +01:00
marisa
419f7797f2 fix(iterators2): Remove reference to missing iterators2.rs (#245)
fix(iterators2): Remove reference to missing iterators2.rs
2019-12-16 12:51:03 +01:00
Rahat Ahmed
54571a5fca fix(iterators2): Remove reference to missing iterators2.rs 2019-12-07 23:25:13 -08:00
marisa
4b79691d5e 2.1.0 2019-11-27 10:46:09 +01:00
marisa
615ce32798 fix(enums): Add link to chapter on pattern syntax (#242)
Add link to chapter on pattern syntax
2019-11-25 12:16:51 +00:00
Jens
31c25ebb50 Add link to chapter on pattern syntax
After being stuck on exercise enums3.rs for about an hour or two, having read the entire chapter on enums 2-3 times, and still being unable to complete the exercise, i started broadening my reading. I finally found the answer in the rust docs via google.
2019-11-24 09:28:33 +01:00
bors
f4acb888a6 Auto merge of #241 - vyaslav:master, r=fmoko
feat(watch): show hint while watching

`rustlings hint ...` command is not convenient when doing exercises with `rustlings watch`.
This PR makes it possible for user to type `hint` while running `watch`  and get hint text for exercise which is currently failing.
e.g.
```rust
...
  --> exercises/variables/variables1.rs:13:36
   |
13 |     println!("x has the value {}", x);
   |                                    ^ not found in this scope

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0425`.

type 'hint' to get help:
hint
Hint: The declaration on line 12 is missing a keyword that is needed in Rust
to create a new variable binding.
```
2019-11-18 22:23:14 +00:00
vyaslav
8143d57b4e feat(watch): show hint while watching 2019-11-18 20:52:57 +01:00
bors
a40ad092e9 Auto merge of #239 - jrvidal:master, r=fmoko
fix: line numbers in several exercises and hints

The introduction of `I AM NOT DONE` shifted the lines of all exercises, which now need adjustment.
2019-11-14 08:23:50 +00:00
Roberto Vidal
b565c4d3e7 fix: line numbers in several exercises and hints
The introduction of `I AM NOT DONE` shifted the lines of all
exercises, which now need adjustment.
2019-11-14 08:21:56 +01:00
bors
e9a835c1c0 Auto merge of #237 - ckeschnat:master, r=fmoko
fix(variables1): Correct wrong word in comment
2019-11-13 23:45:56 +00:00
bors
cf38f03459 Auto merge of #238 - ageorgou:functions4-update, r=fmoko
Update line numbers in hints and outdated comment

In functions4, the missing code is in line 14 in the latest version:
```rust
error: expected type, found `{`
  --> exercises/functions/functions4.rs:14:30
   |
14 | fn sale_price(price: i32) -> {
   |                              ^ expected type

error: aborting due to previous error
```
but the hint points to line 12. This is due to a recent change in 2cdd61294f.

Also includes similar updates for strings2 and primitive_types4.
2019-11-13 23:41:00 +00:00
Anastasis Georgoulas
4c5189df2b fix(primitive_types4): update outdated hint
Exercise was changed to test (and the order was switched) in #209.
2019-11-13 23:23:34 +00:00
Anastasis Georgoulas
a09f684f05 fix(strings2): update line number in hint 2019-11-13 23:23:34 +00:00
ageorgou
8cc5af121c Fix(functions4): Update line number in hint 2019-11-12 23:49:19 +00:00
Chris Keschnat
c42c3b2101 fix(arc1): Fix some words in the comment 2019-11-12 18:37:23 +01:00
Chris Keschnat
fda5a47069 fix(variables1): Correct wrong word in comment 2019-11-12 17:33:25 +01:00
marisa
57a837bde6 Merge pull request #236 from jrvidal/master
fix(primitive_types4): update outdated comment
2019-11-12 13:00:28 +01:00
Roberto Vidal
ded2c034ba fix(primitive_types4): update outdated comment 2019-11-12 12:52:28 +01:00
marisa
eac07df96c 2.0.0 2019-11-12 12:24:30 +01:00
bors
8c1376df07 Auto merge of #235 - rust-lang:fmoko-patch-1, r=fmoko
fix(default): Clarify the installation procedure
2019-11-12 11:13:06 +00:00
bors
45d68d9b39 Auto merge of #232 - rust-lang:update-docs, r=fmoko
chore: Update docs for 2.0

Only merge this once we're ready to release 2.0.
2019-11-12 11:07:56 +00:00
marisa
c371b853af fix(default): Clarify the installation procedure 2019-11-12 11:53:58 +01:00
bors
bc32a63c69 Auto merge of #234 - jrvidal:no-prompt-on-run, r=fmoko
fix(run): makes `run` never prompt

`watch` and `verify` do prompt the user to actively move to the
next exercise. This change fixes `run` to never prompt. Previously
it was inconsistent between "test" and "compile" exercises.

BREAKING CHANGE: we again change the behavior of the `run` command
2019-11-12 10:50:19 +00:00
Roberto Vidal
4b26546589 fix(run): makes run never prompt
`watch` and `verify` do prompt the user to actively move to the
next exercise. This change fixes `run` to never prompt. Previously
it was inconsistent between "test" and "compile" exercises.

BREAKING CHANGE: we again change the behavior of the `run` command
2019-11-12 11:35:40 +01:00
bors
bc56788fe6 Auto merge of #233 - jrvidal:rustc-check, r=fmoko
feat(cli): check for rustc before doing anything

Addresses #190. From the backtraces shown there, it seems like we're not able to launch `rustc` (which is odd, given that they probably compiled and installed `rustlings` 🤷‍♀️)
2019-11-11 18:19:07 +00:00
marisa
b4d41c1b7a chore: Update docs for 2.0 2019-11-11 18:02:56 +01:00
Roberto Vidal
36a033b87a feat(cli): check for rustc before doing anything
Addresses #190.
2019-11-11 18:00:54 +01:00
bors
9544ba1029 Auto merge of #231 - rust-lang:refactor-hints, r=jrvidal
Refactor hints

Breaking change. This removes hints from the end of files, and puts them into `info.toml`. You can now access hints using:

```
rustlings hint <exerciseName>
```

ALSO this changes the exercise system to index by name for `run` and `hint`, so:

```
rustlings run exercises/if/if1.rs
```

becomes

```
rustlings run if1
```
2019-11-11 16:51:12 +00:00
marisa
1a7bb5a400 Address feedback 2019-11-11 17:47:45 +01:00
marisa
48c35bcfbc fix tests 2019-11-11 17:28:19 +01:00
marisa
ec2d4bd3ee Merge branch 'master' into refactor-hints 2019-11-11 17:21:06 +01:00
marisa
ce9fa6ebbf feat(hint): Add test for hint 2019-11-11 17:19:50 +01:00
marisa
9a9007abae chore: Add .editorconfig file 2019-11-11 17:12:11 +01:00
bors
88ec6f6b16 Auto merge of #230 - jrvidal:master, r=fmoko
Changes the execution mode for `watch`, asking for user input

We've [observed](https://hackmd.io/-cK6aPhnTwiCiI7u6k0xug?both) that learners can get confused when they do get everything right, but they _still_ get errors... which come from the next exercise, no the one they just edited.

This PR changes it so they have to confirm they want to move forward by removing the `I AM NOT DONE` comment.

![Screenshot at 2019-11-11 15:13:39](https://user-images.githubusercontent.com/1636604/68593566-0abd3900-0496-11ea-9e9d-6c43b91bf21d.png)

* [ ] The particular string is of course subject to bikeshed.

### Alternatives/doubts
* The coolest solution I could imagine would involve a proc-macro attribute `#![ready(false)]` that they could edit once they're done, but it's a bit complicated to set up.
* For now I've put `I AM NOT DONE` everywhere, I think it's what make more sense.
2019-11-11 15:59:35 +00:00
marisa
795b6e3480 fix(info): Fix trailing newlines for hints 2019-11-11 16:56:39 +01:00
marisa
9bdb0a12e4 feat: Refactor hint system
Hints are now accessible using the CLI subcommand `rustlings hint
<exercise name`.

BREAKING CHANGE: This fundamentally changes the way people interact with exercises.
2019-11-11 16:51:38 +01:00
Roberto Vidal
2cdd61294f feat: improve watch execution mode
The `watch` command now requires user action to move to the next
exercise.

BREAKING CHANGE: this changes the behavior of `watch`.
2019-11-11 16:23:35 +01:00
marisa
627cdc07d0 feat: Index exercises by name
BREAKING CHANGE: This changes the way you use `rustlings run` by now
requiring an abridged form of the previous filename, e.g:

`rustlings run exercises/if/if1.rs` becomes
`rustlings run if1`
2019-11-11 15:46:32 +01:00
marisa
a47a62172a 1.5.1 2019-11-11 14:02:27 +01:00
marisa
f72e5a8f05 fix(structs1): Remove misleading comment 2019-11-11 13:57:59 +01:00
marisa
fbe91a67a4 fix(threads): Move Threads behind SLT
Closes #205.
2019-11-11 13:48:09 +01:00
marisa
6dcecb38a4 fix(strings): Move Strings before Structs
Closes #204.
2019-11-11 13:46:42 +01:00
marisa
dcfb427b09 fix(errors3): Update hint
Closes #185.
2019-11-11 13:37:43 +01:00
marisa
ad03d180c9 fix(if1): Remove return reference
This closes #153.
2019-11-11 13:34:21 +01:00
bors
3232a4d60d Auto merge of #228 - WofWca:clear-screen, r=fmoko
improvement(watch): clear screen before each `verify()`

Closes #146
It seems to me that #227 wasn't really fixing the issue.
2019-11-09 15:23:53 +00:00
WofWca
3aff590855 improvement(watch): clear screen before each verify()
Closes #146
2019-11-09 22:24:24 +08:00
106 changed files with 3355 additions and 2084 deletions

465
.all-contributorsrc Normal file
View File

@@ -0,0 +1,465 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "carols10cents",
"name": "Carol (Nichols || Goulding)",
"avatar_url": "https://avatars2.githubusercontent.com/u/193874?v=4",
"profile": "http://carol-nichols.com",
"contributions": [
"code",
"content"
]
},
{
"login": "QuietMisdreavus",
"name": "QuietMisdreavus",
"avatar_url": "https://avatars2.githubusercontent.com/u/5217170?v=4",
"profile": "https://twitter.com/QuietMisdreavus",
"contributions": [
"code",
"content"
]
},
{
"login": "robertlugg",
"name": "Robert M Lugg",
"avatar_url": "https://avatars0.githubusercontent.com/u/6054540?v=4",
"profile": "https://github.com/robertlugg",
"contributions": [
"content"
]
},
{
"login": "hynek",
"name": "Hynek Schlawack",
"avatar_url": "https://avatars3.githubusercontent.com/u/41240?v=4",
"profile": "https://hynek.me/about/",
"contributions": [
"code"
]
},
{
"login": "spacekookie",
"name": "Katharina Fey",
"avatar_url": "https://avatars0.githubusercontent.com/u/7669898?v=4",
"profile": "https://spacekookie.de",
"contributions": [
"code"
]
},
{
"login": "lukabavdaz",
"name": "lukabavdaz",
"avatar_url": "https://avatars0.githubusercontent.com/u/9624558?v=4",
"profile": "https://github.com/lukabavdaz",
"contributions": [
"code",
"content"
]
},
{
"login": "evestera",
"name": "Erik Vesteraas",
"avatar_url": "https://avatars2.githubusercontent.com/u/4187449?v=4",
"profile": "http://vestera.as",
"contributions": [
"code"
]
},
{
"login": "Delet0r",
"name": "delet0r",
"avatar_url": "https://avatars1.githubusercontent.com/u/23195618?v=4",
"profile": "https://github.com/Delet0r",
"contributions": [
"code"
]
},
{
"login": "shaunbennett",
"name": "Shaun Bennett",
"avatar_url": "https://avatars1.githubusercontent.com/u/10522375?v=4",
"profile": "http://phinary.ca",
"contributions": [
"code"
]
},
{
"login": "abagshaw",
"name": "Andrew Bagshaw",
"avatar_url": "https://avatars2.githubusercontent.com/u/8594541?v=4",
"profile": "https://github.com/abagshaw",
"contributions": [
"code"
]
},
{
"login": "kisom",
"name": "Kyle Isom",
"avatar_url": "https://avatars2.githubusercontent.com/u/175578?v=4",
"profile": "https://ai6ua.net/",
"contributions": [
"code"
]
},
{
"login": "ColinPitrat",
"name": "Colin Pitrat",
"avatar_url": "https://avatars3.githubusercontent.com/u/1541863?v=4",
"profile": "https://github.com/ColinPitrat",
"contributions": [
"code"
]
},
{
"login": "zacanger",
"name": "Zac Anger",
"avatar_url": "https://avatars3.githubusercontent.com/u/12520493?v=4",
"profile": "https://zacanger.com",
"contributions": [
"code"
]
},
{
"login": "mgeier",
"name": "Matthias Geier",
"avatar_url": "https://avatars1.githubusercontent.com/u/705404?v=4",
"profile": "https://github.com/mgeier",
"contributions": [
"code"
]
},
{
"login": "cjpearce",
"name": "Chris Pearce",
"avatar_url": "https://avatars1.githubusercontent.com/u/3453268?v=4",
"profile": "https://github.com/cjpearce",
"contributions": [
"code"
]
},
{
"login": "yvan-sraka",
"name": "Yvan Sraka",
"avatar_url": "https://avatars2.githubusercontent.com/u/705213?v=4",
"profile": "https://yvan-sraka.github.io",
"contributions": [
"code"
]
},
{
"login": "dendi239",
"name": "Denys Smirnov",
"avatar_url": "https://avatars3.githubusercontent.com/u/16478650?v=4",
"profile": "https://github.com/dendi239",
"contributions": [
"code"
]
},
{
"login": "eddyp",
"name": "eddyp",
"avatar_url": "https://avatars2.githubusercontent.com/u/123772?v=4",
"profile": "https://github.com/eddyp",
"contributions": [
"code"
]
},
{
"login": "briankung",
"name": "Brian Kung",
"avatar_url": "https://avatars1.githubusercontent.com/u/2836167?v=4",
"profile": "http://about.me/BrianKung",
"contributions": [
"code",
"content"
]
},
{
"login": "miller-time",
"name": "Russell",
"avatar_url": "https://avatars3.githubusercontent.com/u/281039?v=4",
"profile": "https://rcousineau.gitlab.io",
"contributions": [
"code"
]
},
{
"login": "danwilhelm",
"name": "Dan Wilhelm",
"avatar_url": "https://avatars3.githubusercontent.com/u/6137185?v=4",
"profile": "http://danwilhelm.com",
"contributions": [
"doc"
]
},
{
"login": "Jesse-Cameron",
"name": "Jesse",
"avatar_url": "https://avatars3.githubusercontent.com/u/3723654?v=4",
"profile": "https://github.com/Jesse-Cameron",
"contributions": [
"code",
"content"
]
},
{
"login": "MrFroop",
"name": "Fredrik Jambrén",
"avatar_url": "https://avatars3.githubusercontent.com/u/196700?v=4",
"profile": "https://github.com/MrFroop",
"contributions": [
"code"
]
},
{
"login": "petemcfarlane",
"name": "Pete McFarlane",
"avatar_url": "https://avatars3.githubusercontent.com/u/3472717?v=4",
"profile": "https://github.com/petemcfarlane",
"contributions": [
"content"
]
},
{
"login": "nkanderson",
"name": "nkanderson",
"avatar_url": "https://avatars0.githubusercontent.com/u/4128825?v=4",
"profile": "https://github.com/nkanderson",
"contributions": [
"code",
"content"
]
},
{
"login": "ajaxm",
"name": "Ajax M",
"avatar_url": "https://avatars0.githubusercontent.com/u/13360138?v=4",
"profile": "https://github.com/ajaxm",
"contributions": [
"doc"
]
},
{
"login": "Dylnuge",
"name": "Dylan Nugent",
"avatar_url": "https://avatars2.githubusercontent.com/u/118624?v=4",
"profile": "https://dylnuge.com",
"contributions": [
"content"
]
},
{
"login": "vyaslav",
"name": "vyaslav",
"avatar_url": "https://avatars0.githubusercontent.com/u/1385427?v=4",
"profile": "https://github.com/vyaslav",
"contributions": [
"code",
"content"
]
},
{
"login": "gdoenlen",
"name": "George",
"avatar_url": "https://avatars1.githubusercontent.com/u/17297466?v=4",
"profile": "https://join.sfxd.org",
"contributions": [
"code"
]
},
{
"login": "nyxtom",
"name": "Thomas Holloway",
"avatar_url": "https://avatars2.githubusercontent.com/u/222763?v=4",
"profile": "https://github.com/nyxtom",
"contributions": [
"code",
"content"
]
},
{
"login": "workingjubilee",
"name": "Jubilee",
"avatar_url": "https://avatars1.githubusercontent.com/u/46493976?v=4",
"profile": "https://github.com/workingjubilee",
"contributions": [
"code"
]
},
{
"login": "WofWca",
"name": "WofWca",
"avatar_url": "https://avatars1.githubusercontent.com/u/39462442?v=4",
"profile": "https://github.com/WofWca",
"contributions": [
"code"
]
},
{
"login": "jrvidal",
"name": "Roberto Vidal",
"avatar_url": "https://avatars0.githubusercontent.com/u/1636604?v=4",
"profile": "https://github.com/jrvidal",
"contributions": [
"code",
"doc",
"ideas",
"maintenance"
]
},
{
"login": "jensim",
"name": "Jens",
"avatar_url": "https://avatars0.githubusercontent.com/u/3663856?v=4",
"profile": "https://github.com/jensim",
"contributions": [
"doc"
]
},
{
"login": "rahatarmanahmed",
"name": "Rahat Ahmed",
"avatar_url": "https://avatars3.githubusercontent.com/u/3174006?v=4",
"profile": "http://rahatah.me/d",
"contributions": [
"doc"
]
},
{
"login": "AbdouSeck",
"name": "Abdou Seck",
"avatar_url": "https://avatars2.githubusercontent.com/u/6490055?v=4",
"profile": "https://github.com/AbdouSeck",
"contributions": [
"code",
"content",
"review"
]
},
{
"login": "codehearts",
"name": "Katie",
"avatar_url": "https://avatars0.githubusercontent.com/u/2885412?v=4",
"profile": "https://codehearts.com",
"contributions": [
"code"
]
},
{
"login": "Socratides",
"name": "Socrates",
"avatar_url": "https://avatars3.githubusercontent.com/u/27732983?v=4",
"profile": "https://github.com/Socratides",
"contributions": [
"doc"
]
},
{
"login": "gnodarse",
"name": "gnodarse",
"avatar_url": "https://avatars3.githubusercontent.com/u/46761795?v=4",
"profile": "https://github.com/gnodarse",
"contributions": [
"content"
]
},
{
"login": "harrisonmetz",
"name": "Harrison Metzger",
"avatar_url": "https://avatars1.githubusercontent.com/u/7883408?v=4",
"profile": "https://github.com/harrisonmetz",
"contributions": [
"code"
]
},
{
"login": "TorbenJ",
"name": "Torben Jonas",
"avatar_url": "https://avatars2.githubusercontent.com/u/9077102?v=4",
"profile": "https://github.com/TorbenJ",
"contributions": [
"code",
"content"
]
},
{
"login": "pbx",
"name": "Paul Bissex",
"avatar_url": "https://avatars0.githubusercontent.com/u/641?v=4",
"profile": "http://paulbissex.com/",
"contributions": [
"doc"
]
},
{
"login": "sjmann",
"name": "Steven Mann",
"avatar_url": "https://avatars0.githubusercontent.com/u/6589896?v=4",
"profile": "https://github.com/sjmann",
"contributions": [
"code",
"content"
]
},
{
"login": "Tarnadas",
"name": "Mario Reder",
"avatar_url": "https://avatars2.githubusercontent.com/u/5855071?v=4",
"profile": "https://smmdb.net/",
"contributions": [
"code",
"content"
]
},
{
"login": "sl4m",
"name": "skim",
"avatar_url": "https://avatars0.githubusercontent.com/u/47347?v=4",
"profile": "https://keybase.io/skim",
"contributions": [
"code"
]
},
{
"login": "sanjaykdragon",
"name": "Sanjay K",
"avatar_url": "https://avatars1.githubusercontent.com/u/10261698?v=4",
"profile": "https://github.com/sanjaykdragon",
"contributions": [
"code",
"content"
]
},
{
"login": "crodjer",
"name": "Rohan Jain",
"avatar_url": "https://avatars1.githubusercontent.com/u/343499?v=4",
"profile": "http://www.rohanjain.in",
"contributions": [
"code"
]
},
{
"login": "saidaspen",
"name": "Said Aspen",
"avatar_url": "https://avatars1.githubusercontent.com/u/7727687?v=4",
"profile": "https://www.saidaspen.se",
"contributions": [
"code",
"content"
]
}
],
"contributorsPerLine": 8,
"projectName": "rustlings",
"projectOwner": "fmoko",
"repoType": "github",
"repoHost": "https://github.com",
"skipCi": true
}

7
.editorconfig Normal file
View File

@@ -0,0 +1,7 @@
root = true
[*.rs]
end_of_line = lf
insert_final_newfile = true
indent_style = space
indent_size = 4

4
.gitignore vendored
View File

@@ -2,3 +2,7 @@
target/
**/*.rs.bk
.DS_Store
*.pdb
exercises/clippy/Cargo.toml
exercises/clippy/Cargo.lock
.idea

View File

@@ -1,11 +0,0 @@
language: rust
rust:
- stable
- beta
- nightly
script: cargo test --verbose
matrix:
allow_failures:
- rust: nightly
fast_finish: true
cache: cargo

View File

@@ -1,3 +1,160 @@
<a name="4.0.0"></a>
## 4.0.0 (2020-07-08)
#### Breaking Changes
* Add a --nocapture option to display test harnesses' outputs ([8ad5f9bf](https://github.com/rust-lang/rustlings/commit/8ad5f9bf531a4848b1104b7b389a20171624c82f)
* Rename test to quiz, fixes #244 ([010a0456](https://github.com/rust-lang/rustlings/commit/010a04569282149cea7f7a76fc4d7f4c9f0f08dd)
#### Features
* Add traits README ([173bb141](https://github.com/rust-lang/rustlings/commit/173bb14140c5530cbdb59e53ace3991a99d804af))
* Add box1.rs exercise ([7479a473](https://github.com/rust-lang/rustlings/commit/7479a4737bdcac347322ad0883ca528c8675e720))
* Rewrite try_from_into (#393) ([763aa6e3](https://github.com/rust-lang/rustlings/commit/763aa6e378a586caae2d8d63755a85eeba227933))
* Add if2 exercise ([1da84b5f](https://github.com/rust-lang/rustlings/commit/1da84b5f7c489f65bd683c244f13c7d1ee812df0))
* Added exercise structs3.rs ([b66e2e09](https://github.com/rust-lang/rustlings/commit/b66e2e09622243e086a0f1258dd27e1a2d61c891))
* Add exercise variables6 covering const (#352) ([5999acd2](https://github.com/rust-lang/rustlings/commit/5999acd24a4f203292be36e0fd18d385887ec481))
#### Bug Fixes
* Change then to than ([ddd98ad7](https://github.com/rust-lang/rustlings/commit/ddd98ad75d3668fbb10eff74374148aa5ed2344d))
* rename quiz1 to tests1 in info (#420) ([0dd1c6ca](https://github.com/rust-lang/rustlings/commit/0dd1c6ca6b389789e0972aa955fe17aa15c95f29))
* fix quiz naming inconsistency (#421) ([5563adbb](https://github.com/rust-lang/rustlings/commit/5563adbb890587fc48fbbc9c4028642687f1e85b))
* confine the user further in variable exercises ([06ef4cc6](https://github.com/rust-lang/rustlings/commit/06ef4cc654e75d22a526812919ee49b8956280bf))
* update iterator and macro text for typos and clarity ([95900828](https://github.com/rust-lang/rustlings/commit/959008284834bece0196a01e17ac69a7e3590116))
* update generics2 closes #362 ([964c974a](https://github.com/rust-lang/rustlings/commit/964c974a0274199d755073b917c2bc5da0c9b4f1))
* confusing comment in conversions/try_from_into.rs ([c9e4f2cf](https://github.com/rust-lang/rustlings/commit/c9e4f2cfb4c48d0b7451263cfb43b9426438122d))
* **arc1:** Passively introduce attributes (#429) ([113cdae2](https://github.com/rust-lang/rustlings/commit/113cdae2d4e4c55905e8056ad326ede7fd7de356))
* **box1:** fix comment typo (#426) ([bb2ca251](https://github.com/rust-lang/rustlings/commit/bb2ca251106b27a7272d9a30872904dd1376654c))
* **errorsn:** Try harder to confine the user. (#388) ([2b20c8a0](https://github.com/rust-lang/rustlings/commit/2b20c8a0f5774d07c58d110d75879f33fc6273b5))
* **from_into.rs:** typo ([a901499e](https://github.com/rust-lang/rustlings/commit/a901499ededd3ce1995164700514fe4e9a0373ea))
* **generics2:** Guide students to the answer (#430) ([e6bd8021](https://github.com/rust-lang/rustlings/commit/e6bd8021d9a7dd06feebc30c9d5f953901d7b419))
* **installation:**
* Provide a backup git reference when tag can't be curl ([9e4fb100](https://github.com/rust-lang/rustlings/commit/9e4fb1009f1c9e3433915c03e22c2af422e5c5fe))
* Check if python is available while checking for git,rustc and cargo ([9cfb617d](https://github.com/rust-lang/rustlings/commit/9cfb617d5b0451b4b51644a1298965390cda9884))
* **option1:**
* Don't add only zeros to the numbers array ([cce6a442](https://github.com/rust-lang/rustlings/commit/cce6a4427718724a9096800754cd3abeca6a1580))
* Add cast to usize, as it is confusing in the context of an exercise about Option ([f6cffc7e](https://github.com/rust-lang/rustlings/commit/f6cffc7e487b42f15a6f958e49704c93a8d4465b))
* **option2:** Add TODO to comments (#400) ([10967bce](https://github.com/rust-lang/rustlings/commit/10967bce57682812dc0891a9f9757da1a9d87404))
* **options1:** Add hint about Array Initialization (#389) ([9f75554f](https://github.com/rust-lang/rustlings/commit/9f75554f2a30295996f03f0160b98c0458305502))
* **test2:** name of type String and &str (#394) ([d6c0a688](https://github.com/rust-lang/rustlings/commit/d6c0a688e6a96f93ad60d540d4b326f342fc0d45))
* **variables6:** minor typo (#419) ([524e17df](https://github.com/rust-lang/rustlings/commit/524e17df10db95f7b90a0f75cc8997182a8a4094))
<a name="3.0.0"></a>
## 3.0.0 (2020-04-11)
#### Breaking Changes
* make "compile" exercises print output (#278) ([3b6d5c](https://github.com/fmoko/rustlings/commit/3b6d5c3aaa27a242a832799eb66e96897d26fde3))
#### Bug Fixes
* **primitive_types:** revert primitive_types4 (#296) ([b3a3351e](https://github.com/rust-lang/rustlings/commit/b3a3351e8e6a0bdee07077d7b0382953821649ae))
* **run:** compile clippy exercise files (#295) ([3ab084a4](https://github.com/rust-lang/rustlings/commit/3ab084a421c0f140ae83bf1fc3f47b39342e7373))
* **conversions:**
* add additional test to meet exercise rules (#284) ([bc22ec3](https://github.com/fmoko/rustlings/commit/bc22ec382f843347333ef1301fc1bad773657f38))
* remove duplicate not done comment (#292) ([dab90f](https://github.com/fmoko/rustlings/commit/dab90f7b91a6000fe874e3d664f244048e5fa342))
* don't hardcode documentation version for traits (#288) ([30e6af](https://github.com/fmoko/rustlings/commit/30e6af60690c326fb5d3a9b7335f35c69c09137d))
#### Features
* add Option2 exercise (#290) ([86b5c08b](https://github.com/rust-lang/rustlings/commit/86b5c08b9bea1576127a7c5f599f5752072c087d))
* add excercise for option (#282) ([135e5d47](https://github.com/rust-lang/rustlings/commit/135e5d47a7c395aece6f6022117fb20c82f2d3d4))
* add new exercises for generics (#280) ([76be5e4e](https://github.com/rust-lang/rustlings/commit/76be5e4e991160f5fd9093f03ee2ba260e8f7229))
* **ci:** add buildkite config ([b049fa2c](https://github.com/rust-lang/rustlings/commit/b049fa2c84dba0f0c8906ac44e28fd45fba51a71))
<a name="2.2.1"></a>
### 2.2.1 (2020-02-27)
#### Bug Fixes
* Re-add cloning the repo to install scripts ([3d9b03c5](https://github.com/rust-lang/rustlings/commit/3d9b03c52b8dc51b140757f6fd25ad87b5782ef5))
#### Features
* Add clippy lints (#269) ([1e2fd9c9](https://github.com/rust-lang/rustlings/commit/1e2fd9c92f8cd6e389525ca1a999fca4c90b5921))
<a name="2.2.0"></a>
## 2.2.0 (2020-02-25)
#### Bug Fixes
* Update deps to version compatable with aarch64-pc-windows (#263) ([19a93428](https://github.com/rust-lang/rustlings/commit/19a93428b3c73d994292671f829bdc8e5b7b3401))
* **docs:**
* Added a necessary step to Windows installation process (#242) ([3906efcd](https://github.com/rust-lang/rustlings/commit/3906efcd52a004047b460ed548037093de3f523f))
* Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9))
* Updated iterators readme to account for iterators4 exercise (#273) ([bec8e3a](https://github.com/rust-lang/rustlings/commit/bec8e3a644cbd88db1c73ea5f1d8a364f4a34016))
* **installation:** make fatal errors more obvious (#272) ([17d0951e](https://github.com/rust-lang/rustlings/commit/17d0951e66fda8e11b204d5c4c41a0d5e22e78f7))
* **iterators2:**
* Remove reference to missing iterators2.rs (#245) ([419f7797](https://github.com/rust-lang/rustlings/commit/419f7797f294e4ce6a2b883199731b5bde77d262))
* **as_ref_mut:** Enable a test and improve per clippy's suggestion (#256) ([dfdf809](https://github.com/rust-lang/rustlings/commit/dfdf8093ebbd4145864995627b812780de52f902))
* **tests1:**
* Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce)
* Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf))
#### Features
* Add variables5.rs exercise (#264) ([0c73609e](https://github.com/rust-lang/rustlings/commit/0c73609e6f2311295e95d6f96f8c747cfc4cba03))
* Show a completion message when watching (#253) ([d25ee55a](https://github.com/rust-lang/rustlings/commit/d25ee55a3205882d35782e370af855051b39c58c))
* Add type conversion and parsing exercises (#249) ([0c85dc11](https://github.com/rust-lang/rustlings/commit/0c85dc1193978b5165491b99cc4922caf8d14a65))
* Created consistent money unit (#258) ([fd57f8f](https://github.com/rust-lang/rustlings/commit/fd57f8f2c1da2af8ddbebbccec214e6f40f4dbab))
* Enable test for exercise test4 (#276) ([8b971ff](https://github.com/rust-lang/rustlings/commit/8b971ffab6079a706ac925f5917f987932b55c07))
* Added traits exercises (#274 but specifically #216, which originally added
this :heart:) ([b559cdd](https://github.com/rust-lang/rustlings/commit/b559cdd73f32c0d0cfc1feda39f82b3e3583df17))
<a name="2.1.0"></a>
## 2.1.0 (2019-11-27)
#### Bug Fixes
* add line numbers in several exercises and hints ([b565c4d3](https://github.com/rust-lang/rustlings/commit/b565c4d3e74e8e110bef201a082fa1302722a7c3))
* **arc1:** Fix some words in the comment ([c42c3b21](https://github.com/rust-lang/rustlings/commit/c42c3b2101df9164c8cd7bb344def921e5ba3e61))
* **enums:** Add link to chapter on pattern syntax (#242) ([615ce327](https://github.com/rust-lang/rustlings/commit/615ce3279800c56d89f19d218ccb7ef576624feb))
* **primitive_types4:**
* update outdated hint ([4c5189df](https://github.com/rust-lang/rustlings/commit/4c5189df2bdd9a231f6b2611919ba5aa14da0d3f))
* update outdated comment ([ded2c034](https://github.com/rust-lang/rustlings/commit/ded2c034ba93fa1e3c2c2ea16b83abc1a57265e8))
* **strings2:** update line number in hint ([a09f684f](https://github.com/rust-lang/rustlings/commit/a09f684f05c58d239a6fc59ec5f81c2533e8b820))
* **variables1:** Correct wrong word in comment ([fda5a470](https://github.com/rust-lang/rustlings/commit/fda5a47069e0954f16a04e8e50945e03becb71a5))
#### Features
* **watch:** show hint while watching ([8143d57b](https://github.com/rust-lang/rustlings/commit/8143d57b4e88c51341dd4a18a14c536042cc009c))
<a name="2.0.0"></a>
## 2.0.0 (2019-11-12)
#### Bug Fixes
* **default:** Clarify the installation procedure ([c371b853](https://github.com/rust-lang/rustlings/commit/c371b853afa08947ddeebec0edd074b171eeaae0))
* **info:** Fix trailing newlines for hints ([795b6e34](https://github.com/rust-lang/rustlings/commit/795b6e348094a898e9227a14f6232f7bb94c8d31))
* **run:** make `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
#### Breaking Changes
* Refactor hint system ([9bdb0a12](https://github.com/rust-lang/rustlings/commit/9bdb0a12e45a8e9f9f6a4bd4a9c172c5376c7f60))
* improve `watch` execution mode ([2cdd6129](https://github.com/rust-lang/rustlings/commit/2cdd61294f0d9a53775ee24ad76435bec8a21e60))
* Index exercises by name ([627cdc07](https://github.com/rust-lang/rustlings/commit/627cdc07d07dfe6a740e885e0ddf6900e7ec336b))
* **run:** makes `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
#### Features
* **cli:** check for rustc before doing anything ([36a033b8](https://github.com/rust-lang/rustlings/commit/36a033b87a6549c1e5639c908bf7381c84f4f425))
* **hint:** Add test for hint ([ce9fa6eb](https://github.com/rust-lang/rustlings/commit/ce9fa6ebbfdc3e7585d488d9409797285708316f))
<a name="1.5.1"></a>
### 1.5.1 (2019-11-11)
#### Bug Fixes
* **errors3:** Update hint ([dcfb427b](https://github.com/rust-lang/rustlings/commit/dcfb427b09585f0193f0a294443fdf99f11c64cb), closes [#185](https://github.com/rust-lang/rustlings/issues/185))
* **if1:** Remove `return` reference ([ad03d180](https://github.com/rust-lang/rustlings/commit/ad03d180c9311c0093e56a3531eec1a9a70cdb45))
* **strings:** Move Strings before Structs ([6dcecb38](https://github.com/rust-lang/rustlings/commit/6dcecb38a4435593beb87c8e12d6314143631482), closes [#204](https://github.com/rust-lang/rustlings/issues/204))
* **structs1:** Remove misleading comment ([f72e5a8f](https://github.com/rust-lang/rustlings/commit/f72e5a8f05568dde04eaeac10b9a69872f21cb37))
* **threads:** Move Threads behind SLT ([fbe91a67](https://github.com/rust-lang/rustlings/commit/fbe91a67a482bfe64cbcdd58d06ba830a0f39da3), closes [#205](https://github.com/rust-lang/rustlings/issues/205))
* **watch:** clear screen before each `verify()` ([3aff590](https://github.com/rust-lang/rustlings/commit/3aff59085586c24196a547c2693adbdcf4432648))
<a name="1.5.0"></a>
## 1.5.0 (2019-11-09)

View File

@@ -35,8 +35,11 @@ You want to make sure where in the file you add your exercise. If you're not sur
```diff
...
+ [[exercises]]
+ name = "yourTopicN"
+ path = "exercises/yourTopic/yourTopicN.rs"
+ mode = "compile"
+ hint = """
+ Some kind of useful hint for your exercise."""
...
```
@@ -125,4 +128,4 @@ BREAKING CHANGE: This has to be done because lorem ipsum dolor
Once you open a Pull Request, it may be reviewed or labeled (or both) until
the maintainers accept your change. Then, [bors](https://github.com/bors) will
run the test suite with your changes and if it's successful, automatically
merge it in!
merge it in!

189
Cargo.lock generated
View File

@@ -1,13 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.7.3"
@@ -21,7 +13,7 @@ name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -42,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -74,17 +66,6 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clicolors-control"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clicolors-control"
version = "1.0.0"
@@ -93,7 +74,7 @@ dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -106,23 +87,7 @@ dependencies = [
[[package]]
name = "console"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"clicolors-control 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "console"
version = "0.7.5"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -134,7 +99,22 @@ dependencies = [
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "console"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -168,6 +148,14 @@ dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "float-cmp"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fsevent"
version = "0.4.0"
@@ -204,20 +192,26 @@ name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "indicatif"
version = "0.9.0"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"console 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inotify"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -256,11 +250,6 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.3.0"
@@ -343,25 +332,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "normalize-line-endings"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "notify"
version = "4.0.12"
version = "4.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "number_prefix"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -391,7 +400,7 @@ dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -400,7 +409,10 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -448,7 +460,7 @@ dependencies = [
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -496,7 +508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -509,7 +521,7 @@ dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -550,18 +562,6 @@ dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.1.6"
@@ -574,14 +574,6 @@ dependencies = [
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.6"
@@ -600,13 +592,16 @@ dependencies = [
[[package]]
name = "rustlings"
version = "1.4.1"
version = "3.0.0"
dependencies = [
"assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"indicatif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -774,7 +769,7 @@ version = "2.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -785,7 +780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.7"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -807,7 +802,7 @@ name = "winapi-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -825,7 +820,6 @@ dependencies = [
]
[metadata]
"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e"
@@ -834,27 +828,27 @@ dependencies = [
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum clicolors-control 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f84dec9bc083ce2503908cd305af98bd363da6f54bf8d4bf0ac14ee749ad5d1"
"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd48adf136733979b49e15bc3b4c43cc0d3c85ece7bd08e6daa414c6fcb13e6"
"checksum console 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2bf3720d3f3fc30b721ef1ae54e13af3264af4af39dc476a8de56a6ee1e2184b"
"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628"
"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd"
"checksum escargot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597"
"checksum filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2f8c63033fcba1f51ef744505b3cad42510432b904c062afa67ad7ece008429d"
"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600"
"checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
"checksum fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum indicatif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a29b2fa6f00010c268bface64c18bb0310aaa70d46a195d5382d288c477fb016"
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
"checksum indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe"
"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
@@ -865,7 +859,10 @@ dependencies = [
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3572d71f13ea8ed41867accd971fd564aa75934cf7a1fae03ddb8c74a8a49943"
"checksum normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2e0a1a39eab95caf4f5556da9289b9e68f0aafac901b2ce80daaf020d3b733a8"
"checksum notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
@@ -887,9 +884,7 @@ dependencies = [
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
@@ -917,7 +912,7 @@ dependencies = [
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"

View File

@@ -1,15 +1,16 @@
[package]
name = "rustlings"
version = "1.5.0"
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
version = "4.0.0"
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
edition = "2018"
[dependencies]
clap = "2.32.0"
indicatif = "0.9.0"
console = "0.6.2"
notify = "4.0.0"
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]]
@@ -18,3 +19,5 @@ path = "src/main.rs"
[dev-dependencies]
assert_cmd = "0.11.0"
predicates = "1.0.1"
glob = "0.3.0"

105
README.md
View File

@@ -1,6 +1,9 @@
![crab pet](https://i.imgur.com/LbZJgmm.gif)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-48-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
# rustlings 🦀❤️
# rustlings 🦀❤️ [![Build status](https://badge.buildkite.com/7af93d81dc522c67a1ec8e33ff5705861b1cb36360b774807f.svg)](https://buildkite.com/mokou/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!
@@ -15,8 +18,6 @@ Alternatively, for a first-time Rust learner, there's several other resources:
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
_Note: If you have Xcode 10+ installed, you also need to install the package file found at `/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg`._
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
## MacOS/Linux
@@ -33,10 +34,16 @@ This will install Rustlings and give you access to the `rustlings` command. Run
## Windows
You can run:
In PowerShell, set `ExecutionPolicy` to `RemoteSigned`:
```ps
Invoke-WebRequest https://git.io/rustlings-win | Select-Object -ExpandProperty Content | Out-File $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1
Set-ExecutionPolicy RemoteSigned
```
Then, you can run:
```ps
Start-BitsTransfer -Source https://git.io/rustlings-win -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.
@@ -48,7 +55,7 @@ Basically: Clone the repository, checkout to the latest tag, run `cargo install`
```bash
git clone https://github.com/rust-lang/rustlings
cd rustlings
git checkout tags/1.5.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
git checkout tags/4.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
cargo install --force --path .
```
@@ -80,14 +87,19 @@ This will do the same as watch, but it'll quit after running.
In case you want to go by your own order, or want to only verify a single exercise, you can run:
```bash
rustlings run exercises/path/to/exercise.rs
rustlings run myExercise1
```
In case you get stuck, there is usually a hint at the bottom of each exercise.
In case you get stuck, you can run the following command to get a hint for your
exercise:
``` bash
rustlings hint myExercise1
```
## Testing yourself
After every couple of sections, there will be a test that'll test your knowledge on a bunch of sections at once. These tests are found in `exercises/testN.rs`.
After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once. These quizzes are found in `exercises/quizN.rs`.
## Completion
@@ -111,7 +123,78 @@ If you are interested in improving or adding new ones, please feel free to contr
See [CONTRIBUTING.md](./CONTRIBUTING.md).
## Credits
## Contributors ✨
`rustlings` was originally written by [Carol](https://github.com/carols10cents)!
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" width="100px;" alt=""/><br /><sub><b>Carol (Nichols &#124;&#124; Goulding)</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>QuietMisdreavus</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>Hynek Schlawack</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Katharina Fey</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>lukabavdaz</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Erik Vesteraas</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>delet0r</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Shaun Bennett</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Andrew Bagshaw</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Kyle Isom</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Colin Pitrat</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Zac Anger</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Matthias Geier</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Chris Pearce</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Yvan Sraka</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Denys Smirnov</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>eddyp</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Brian Kung</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Russell</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Dan Wilhelm</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Jesse</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Fredrik Jambrén</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>nkanderson</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Ajax M</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>vyaslav</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>George</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Thomas Holloway</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Jubilee</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>WofWca</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Roberto Vidal</b></sub></a><br /><a href="https://github.com/fmoko/rustlings/commits?author=jrvidal" title="Code">💻</a> <a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Jens</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Rahat Ahmed</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Abdou Seck</b></sub></a><br /><a href="https://github.com/fmoko/rustlings/commits?author=AbdouSeck" title="Code">💻</a> <a href="#content-AbdouSeck" title="Content">🖋</a> <a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Katie</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Socrates</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>Harrison Metzger</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Torben Jonas</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Paul Bissex</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Steven Mann</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Mario Reder</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>skim</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Sanjay K</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Rohan Jain</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Said Aspen</b></sub></a><br /><a href="https://github.com/fmoko/rustlings/commits?author=saidaspen" title="Code">💻</a> <a href="#content-saidaspen" title="Content">🖋</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- 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!

5
buildkite.yml Normal file
View File

@@ -0,0 +1,5 @@
steps:
- label: "Test with stable"
command: rustup run stable cargo test
- label: "Test with beta"
command: rustup run beta cargo test

View File

@@ -7,7 +7,8 @@ Let's make sure you're up to speed:
- You have `~/.cargo/bin` added to your PATH variable
- You have cloned this repository (https://github.com/rust-lang/rustlings)
- You have installed Rust language support for your editor
- You have locally installed the `rustlings` command by running:
- You have locally installed the `rustlings` command by running an
installation script or manually executing:
cargo install --force --path .
@@ -15,4 +16,4 @@ If you've done all of this (or even most of it), congrats! You're ready
to start working with Rust.
To get started, run `rustlings watch` in order to get the first exercise.
Make sure to have your editor open!
Make sure to have your editor open!

View File

@@ -0,0 +1,8 @@
### Clippy
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
If you used the installation script for Rustlings, Clippy should be already installed.
If not you can install it manually via `rustup component add clippy`.
For more information about Clippy lints, please see [their documentation page](https://rust-lang.github.io/rust-clippy/master/).

View File

@@ -0,0 +1,17 @@
// clippy1.rs
// The Clippy tool is a collection of lints to analyze your code
// so you can catch common mistakes and improve your Rust code.
//
// For these exercises the code will fail to compile when there are clippy warnings
// check clippy's suggestions from the output to solve the exercise.
// Execute `rustlings hint clippy1` for hints :)
// I AM NOT DONE
fn main() {
let x = 1.2331f64;
let y = 1.2332f64;
if y != x {
println!("Success!");
}
}

View File

@@ -0,0 +1,13 @@
// clippy2.rs
// Make me compile! Execute `rustlings hint clippy2` for hints :)
// I AM NOT DONE
fn main() {
let mut res = 42;
let option = Some(12);
for x in option {
res += x;
}
println!("{}", res);
}

View File

@@ -0,0 +1,20 @@
### Type conversions
Rust offers a multitude of ways to convert a value of a given type into another type.
The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this.
Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
The traits are the following:
- `From` and `Into` covered in [`from_into`](from_into.rs)
- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking.
These should be the main ways ***within the standard library*** to convert data into your desired types.
#### Book Sections
These are not directly covered in the book, but the standard library has great documentation for [conversions here](https://doc.rust-lang.org/std/convert/index.html). The `FromStr` trait is also covered [here](https://doc.rust-lang.org/std/str/trait.FromStr.html).

View File

@@ -0,0 +1,51 @@
// AsRef and AsMut allow for cheap reference-to-reference conversions.
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
// I AM NOT DONE
// Obtain the number of bytes (not characters) in the given argument
// Add the AsRef trait appropriately as a trait bound
fn byte_counter<T>(arg: T) -> usize {
arg.as_ref().as_bytes().len()
}
// Obtain the number of characters (not bytes) in the given argument
// Add the AsRef trait appropriately as a trait bound
fn char_counter<T>(arg: T) -> usize {
arg.as_ref().chars().count()
}
fn main() {
let s = "Café au lait";
println!("{}", char_counter(s));
println!("{}", byte_counter(s));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn different_counts() {
let s = "Café au lait";
assert_ne!(char_counter(s), byte_counter(s));
}
#[test]
fn same_counts() {
let s = "Cafe au lait";
assert_eq!(char_counter(s), byte_counter(s));
}
#[test]
fn different_counts_using_string() {
let s = String::from("Café au lait");
assert_ne!(char_counter(s.clone()), byte_counter(s));
}
#[test]
fn same_counts_using_string() {
let s = String::from("Cafe au lait");
assert_eq!(char_counter(s.clone()), byte_counter(s));
}
}

View File

@@ -0,0 +1,116 @@
// The From trait is used for value-to-value conversions.
// If From is implemented correctly for a type, the Into trait should work conversely.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
#[derive(Debug)]
struct Person {
name: String,
age: usize,
}
// We implement the Default trait to use it as a fallback
// when the provided string is not convertible into a Person object
impl Default for Person {
fn default() -> Person {
Person {
name: String::from("John"),
age: 30,
}
}
}
// I AM NOT DONE
// 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
impl From<&str> for Person {
fn from(s: &str) -> Person {
}
}
fn main() {
// Use the `from` function
let p1 = Person::from("Mark,20");
// Since From is implemented for Person, we should be able to use Into
let p2: Person = "Gerald,70".into();
println!("{:?}", p1);
println!("{:?}", p2);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
// Test that the default person is 30 year old John
let dp = Person::default();
assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30);
}
#[test]
fn test_bad_convert() {
// Test that John is returned when bad string is provided
let p = Person::from("");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_good_convert() {
// Test that "Mark,20" works
let p = Person::from("Mark,20");
assert_eq!(p.name, "Mark");
assert_eq!(p.age, 20);
}
#[test]
fn test_bad_age() {
// Test that "Mark.twenty" will return the default person due to an error in parsing age
let p = Person::from("Mark,twenty");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_comma_and_age() {
let p: Person = Person::from("Mark");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_age() {
let p: Person = Person::from("Mark,");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_name() {
let p: Person = Person::from(",1");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_name_and_age() {
let p: Person = Person::from(",");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
#[test]
fn test_missing_name_and_invalid_age() {
let p: Person = Person::from(",one");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
}
}

View File

@@ -0,0 +1,86 @@
// This does practically the same thing that TryFrom<&str> does.
// Additionally, upon implementing FromStr, you can use the `parse` method
// on strings to generate an object of the implementor type.
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
use std::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, then return an error
// 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 an error
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
// with something like `"4".parse::<usize>()`.
// If while parsing the age, something goes wrong, then return an error
// Otherwise, then return a Result of a Person object
impl FromStr for Person {
type Err = String;
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]
#[should_panic]
fn missing_age() {
"John,".parse::<Person>().unwrap();
}
#[test]
#[should_panic]
fn invalid_age() {
"John,twenty".parse::<Person>().unwrap();
}
#[test]
#[should_panic]
fn missing_comma_and_age() {
"John".parse::<Person>().unwrap();
}
#[test]
#[should_panic]
fn missing_name() {
",1".parse::<Person>().unwrap();
}
#[test]
#[should_panic]
fn missing_name_and_age() {
",".parse::<Person>().unwrap();
}
#[test]
#[should_panic]
fn missing_name_and_invalid_age() {
",one".parse::<Person>().unwrap();
}
}

View File

@@ -0,0 +1,130 @@
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
// Basically, this is the same as From. The main difference is that this should return a Result type
// instead of the target type itself.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
use std::convert::{TryInto, TryFrom};
#[derive(Debug)]
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 create implementation for a tuple of three integer,
// an array of three integer and slice of integer.
//
// Note, that implementation for tuple and array will be checked at compile-time,
// but slice implementation need check slice length!
// Also note, that chunk of correct rgb color must be integer in range 0..=255.
// Tuple implementation
impl TryFrom<(i16, i16, i16)> for Color {
type Error = String;
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
}
}
// Array implementation
impl TryFrom<[i16; 3]> for Color {
type Error = String;
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
}
}
// Slice implementation
impl TryFrom<&[i16]> for Color {
type Error = String;
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
}
}
fn main() {
// Use the `from` function
let c1 = Color::try_from((183, 65, 14));
println!("{:?}", c1);
// Since From is implemented for Color, we should be able to use Into
let c2: Result<Color, _> = [183, 65, 14].try_into();
println!("{:?}", c2);
let v = vec![183, 65, 14];
// With slice we should use `from` function
let c3 = Color::try_from(&v[..]);
println!("{:?}", c3);
// or take slice within round brackets and use Into
let c4: Result<Color, _> = (&v[..]).try_into();
println!("{:?}", c4);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn test_tuple_out_of_range_positive() {
let _ = Color::try_from((256, 1000, 10000)).unwrap();
}
#[test]
#[should_panic]
fn test_tuple_out_of_range_negative() {
let _ = Color::try_from((-1, -10, -256)).unwrap();
}
#[test]
fn test_tuple_correct() {
let c: Color = (183, 65, 14).try_into().unwrap();
assert_eq!(c.red, 183);
assert_eq!(c.green, 65);
assert_eq!(c.blue, 14);
}
#[test]
#[should_panic]
fn test_array_out_of_range_positive() {
let _: Color = [1000, 10000, 256].try_into().unwrap();
}
#[test]
#[should_panic]
fn test_array_out_of_range_negative() {
let _: Color = [-10, -256, -1].try_into().unwrap();
}
#[test]
fn test_array_correct() {
let c: Color = [183, 65, 14].try_into().unwrap();
assert_eq!(c.red, 183);
assert_eq!(c.green, 65);
assert_eq!(c.blue, 14);
}
#[test]
#[should_panic]
fn test_slice_out_of_range_positive() {
let arr = [10000, 256, 1000];
let _ = Color::try_from(&arr[..]).unwrap();
}
#[test]
#[should_panic]
fn test_slice_out_of_range_negative() {
let arr = [-256, -1, -10];
let _ = Color::try_from(&arr[..]).unwrap();
}
#[test]
fn test_slice_correct() {
let v = vec![183, 65, 14];
let c = Color::try_from(&v[..]).unwrap();
assert_eq!(c.red, 183);
assert_eq!(c.green, 65);
assert_eq!(c.blue, 14);
}
#[test]
#[should_panic]
fn test_slice_excess_length() {
let v = vec![0, 0, 0, 0];
let _ = Color::try_from(&v[..]).unwrap();
}
}

View File

@@ -0,0 +1,17 @@
// 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.
// I AM NOT DONE
// The goal is to make sure that the division does not fail to compile
fn average(values: &[f64]) -> f64 {
let total = values
.iter()
.fold(0.0, |a, b| a + b);
total / values.len()
}
fn main() {
let values = [3.5, 0.3, 13.0, 11.7];
println!("{}", average(&values));
}

View File

@@ -1,7 +1,10 @@
### Enums
Rust allows you to define a type called `enums` which allow you to enumerate possible values. In combination with enums, we have the concept of `pattern matching` in Rust, which makes it easy to run different code for different values of an enumeration. Enums, while available in many languages, Rust's enums are most similar to `algebraic data types` in functional languages, such as F#, OCaml, and Haskell.
Rust allows you to define types called "enums" which enumerate possible values.
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
#### Book Sections
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)

View File

@@ -1,5 +1,7 @@
// enums1.rs
// Make me compile! Scroll down for hints!
// Make me compile! Execute `rustlings hint enums1` for hints!
// I AM NOT DONE
#[derive(Debug)]
enum Message {
@@ -12,31 +14,3 @@ fn main() {
println!("{:?}", Message::Move);
println!("{:?}", Message::ChangeColor);
}
// Hint: The declaration of the enumeration type has not been defined yet.

View File

@@ -1,5 +1,7 @@
// enums2.rs
// Make me compile! Scroll down for hints
// Make me compile! Execute `rustlings hint enums2` for hints!
// I AM NOT DONE
#[derive(Debug)]
enum Message {
@@ -24,38 +26,3 @@ fn main() {
message.call();
}
}
// Hint: you can create enumerations that have different variants with different types
// such as no data, anonymous structs, a single string, tuples, ...etc

View File

@@ -1,6 +1,8 @@
// enums3.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
enum Message {
// TODO: implement the message variant types based on their usage below
}
@@ -51,7 +53,7 @@ mod tests {
};
state.process(Message::ChangeColor(255, 0, 255));
state.process(Message::Echo(String::from("hello world")));
state.process(Message::Move{ x: 10, y: 15 });
state.process(Message::Move(Point{ x: 10, y: 15 }));
state.process(Message::Quit);
assert_eq!(state.color, (255, 0, 255));

View File

@@ -4,7 +4,9 @@
// 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.
// Scroll down for hints!!!
// Execute `rustlings hint errors1` for hints!
// I AM NOT DONE
pub fn generate_nametag_text(name: String) -> Option<String> {
if name.len() > 0 {
@@ -38,36 +40,3 @@ mod tests {
);
}
}
// `Err` is one of the variants of `Result`, so what the 2nd test is saying
// is that `generate_nametag_text` should return a `Result` instead of an
// `Option`.
// To make this change, you'll need to:
// - update the return type in the function signature to be a Result<String, String> that
// could be the variants `Ok(String)` and `Err(String)`
// - change the body of the function to return `Ok(stuff)` where it currently
// returns `Some(stuff)`
// - change the body of the function to return `Err(error message)` where it
// currently returns `None`
// - change the first test to expect `Ok(stuff)` where it currently expects
// `Some(stuff)`.

View File

@@ -14,7 +14,9 @@
// and add.
// There are at least two ways to implement this that are both correct-- but
// one is a lot shorter! Scroll down for hints to both ways.
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
// I AM NOT DONE
use std::num::ParseIntError;
@@ -43,27 +45,3 @@ mod tests {
);
}
}
// One way to handle this is using a `match` statement on
// `item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
// `Err(something)`. This pattern is very common in Rust, though, so there's
// a `?` operator that does pretty much what you would make that match statement
// do for you! Take a look at this section of the Error Handling chapter:
// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
// and give it a try!

View File

@@ -1,8 +1,10 @@
// 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--
// we can't use the `?` operator in the `main()` function! Why not?
// What should we do instead? Scroll for hints!
// `total_cost` function from the previous exercise. It's not working though!
// Why not? What should we do to fix it?
// Execute `rustlings hint errors3` for hints!
// I AM NOT DONE
use std::num::ParseIntError;
@@ -27,36 +29,3 @@ pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
Ok(qty * cost_per_item + processing_fee)
}
// Since the `?` operator returns an `Err` early if the thing it's trying to
// do fails, you can only use the `?` operator in functions that have a
// `Result` as their return type.
// Hence the error that you get if you run this code is:
// ```
// error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
// ```
// So we have to use another way of handling a `Result` within `main`.
// Decide what we should do if `pretend_user_input` has a string value that does
// not parse to an integer, and implement that instead of using the `?`
// operator.

View File

@@ -2,8 +2,10 @@
// This is a bigger error exercise than the previous ones!
// You can do it! :)
//
// Edit the `read_and_validate` function so that it compiles and
// passes the tests... so many things could go wrong!
// Edit the `read_and_validate` function ONLY. Don't create any Errors
// that do not already exist.
//
// So many things could go wrong!
//
// - Reading from stdin could produce an io::Error
// - Parsing the input could produce a num::ParseIntError
@@ -13,7 +15,9 @@
// type goes where the question marks are, and how do we return
// that type from the body of read_and_validate?
//
// Scroll down for hints :)
// Execute `rustlings hint errorsn` for hints :)
// I AM NOT DONE
use std::error;
use std::fmt;
@@ -28,6 +32,10 @@ fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger,
answer
}
//
// Nothing below this needs to be modified
//
// This is a test helper function that turns a &str into a BufReader.
fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn error::Error>> {
let mut b = io::BufReader::new(s.as_bytes());
@@ -98,150 +106,12 @@ enum CreationError {
impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str((self as &dyn error::Error).description())
let description = match *self {
CreationError::Negative => "Number is negative",
CreationError::Zero => "Number is zero",
};
f.write_str(description)
}
}
impl error::Error for CreationError {
fn description(&self) -> &str {
match *self {
CreationError::Negative => "Negative",
CreationError::Zero => "Zero",
}
}
}
// First hint: To figure out what type should go where the ??? is, take a look
// at the test helper function `test_with_str`, since it returns whatever
// `read_and_validate` returns and`test_with_str` has its signature fully
// specified.
// Next hint: There are three places in `read_and_validate` that we call a
// function that returns a `Result` (that is, the functions might fail).
// Apply the `?` operator on those calls so that we return immediately from
// `read_and_validate` if those function calls fail.
// Another hint: under the hood, the `?` operator calls `From::from`
// on the error value to convert it to a boxed trait object, a Box<dyn error::Error>,
// which is polymorphic-- that means that lots of different kinds of errors
// can be returned from the same function because all errors act the same
// since they all implement the `error::Error` trait.
// Check out this section of the book:
// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
// Another another hint: Note that because the `?` operator returns
// the *unwrapped* value in the `Ok` case, if we want to return a `Result` from
// `read_and_validate` for *its* success case, we'll have to rewrap a value
// that we got from the return value of a `?`ed call in an `Ok`-- this will
// look like `Ok(something)`.
// Another another another hint: `Result`s must be "used", that is, you'll
// get a warning if you don't handle a `Result` that you get in your
// function. Read more about that in the `std::result` module docs:
// https://doc.rust-lang.org/std/result/#results-must-be-used
impl error::Error for CreationError {}

View File

@@ -1,57 +0,0 @@
// option1.rs
// This example panics because the second time it calls `pop`, the `vec`
// is empty, so `pop` returns `None`, and `unwrap` panics if it's called
// on `None`. Handle this in a more graceful way than calling `unwrap`!
// Scroll down for hints :)
pub fn pop_too_much() -> bool {
let mut list = vec![3];
let last = list.pop().unwrap();
println!("The last item in the list is {:?}", last);
let second_to_last = list.pop().unwrap();
println!(
"The second-to-last item in the list is {:?}",
second_to_last
);
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_not_panic() {
assert!(pop_too_much());
}
}
// Try using a `match` statement where the arms are `Some(thing)` and `None`.
// Or set a default value to print out if you get `None` by using the
// function `unwrap_or`.
// Or use an `if let` statement on the result of `pop()` to both destructure
// a `Some` value and only print out something if we have a value!

View File

@@ -1,5 +1,7 @@
// result1.rs
// Make this test pass! Scroll down for hints :)
// Make this test pass! Execute `rustlings hint result1` for hints :)
// I AM NOT DONE
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
@@ -25,22 +27,3 @@ fn test_creation() {
);
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
}
// `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
// It should be doing some checking, returning an `Err` result if those checks fail, and only
// returning an `Ok` result if those checks determine that everything is... okay :)

View File

@@ -1,44 +1,8 @@
// functions1.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint functions1` for hints :)
// I AM NOT DONE
fn main() {
call_me();
}
// This main function is calling a function that it expects to exist, but the
// function doesn't exist. It expects this function to have the name `call_me`.
// It expects this function to not take any arguments and not return a value.
// Sounds a lot like `main`, doesn't it?

View File

@@ -1,5 +1,7 @@
// functions2.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint functions2` for hints :)
// I AM NOT DONE
fn main() {
call_me(3);
@@ -10,33 +12,3 @@ fn call_me(num) {
println!("Ring! Call number {}", i + 1);
}
}
// Rust requires that all parts of a function's signature have type annotations,
// but `call_me` is missing the type annotation of `num`.

View File

@@ -1,5 +1,7 @@
// functions3.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint functions3` for hints :)
// I AM NOT DONE
fn main() {
call_me();
@@ -10,33 +12,3 @@ fn call_me(num: i32) {
println!("Ring! Call number {}", i + 1);
}
}
// This time, the function *declaration* is okay, but there's something wrong
// with the place where we're calling the function.

View File

@@ -1,8 +1,10 @@
// functions4.rs
// Make me compile! Scroll down for hints :)
// 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 (money unit) off, but if it's an odd number, it's 3 (money unit) less.
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
// I AM NOT DONE
fn main() {
let original_price = 51;
@@ -20,25 +22,3 @@ fn sale_price(price: i32) -> {
fn is_even(num: i32) -> bool {
num % 2 == 0
}
// The error message points to line 12 and says it expects a type after the
// `->`. This is where the function's return type should be-- take a look at
// the `is_even` function for an example!

View File

@@ -1,5 +1,7 @@
// functions5.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint functions5` for hints :)
// I AM NOT DONE
fn main() {
let answer = square(3);
@@ -9,39 +11,3 @@ fn main() {
fn square(num: i32) -> i32 {
num * num;
}
// This is a really common error that can be fixed by removing one character.
// It happens because Rust distinguishes between expressions and statements: expressions return
// a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language.
// We want to return a value of `i32` type from the `square` function, but it is returning a `()` type...
// They are not the same. There are two solutions:
// 1. Add a `return` ahead of `num * num;`
// 2. remove `;`, make it to be `num * num`

View File

@@ -0,0 +1,7 @@
### Generics
In this section you'll learn about saving yourself many lines of code with generics!
### Book Sections
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)

View File

@@ -0,0 +1,10 @@
// This shopping list program isn't compiling!
// Use your knowledge of generics to fix it.
// I AM NOT DONE
fn main() {
let mut shopping_list: Vec<?> = Vec::new();
shopping_list.push("milk");
}

View File

@@ -0,0 +1,28 @@
// This powerful wrapper provides the ability to store a positive integer value.
// Rewrite it using generics so that it supports wrapping ANY type.
// I AM NOT DONE
struct Wrapper {
value: u32
}
impl Wrapper {
pub fn new(value: u32) -> Self {
Wrapper { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn store_u32_in_wrapper() {
assert_eq!(Wrapper::new(42).value, 42);
}
#[test]
fn store_str_in_wrapper() {
assert_eq!(Wrapper::new("Foo").value, "Foo");
}
}

View File

@@ -0,0 +1,48 @@
// 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 to support alphabetical report cards, thereby making
// the second test pass.
// I AM NOT DONE
pub struct ReportCard {
pub grade: f32,
pub student_name: String,
pub student_age: u8,
}
impl ReportCard {
pub fn print(&self) -> String {
format!("{} ({}) - achieved a grade of {}",
&self.student_name, &self.student_age, &self.grade)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_numeric_report_card() {
let report_card = ReportCard {
grade: 2.1,
student_name: "Tom Wriggle".to_string(),
student_age: 12,
};
assert_eq!(report_card.print(), "Tom Wriggle (12) - achieved a grade of 2.1");
}
#[test]
fn generate_alphabetic_report_card() {
// TODO: Make sure to change the grade here after you finish the exercise.
let report_card = ReportCard {
grade: 2.1,
student_name: "Gary Plotter".to_string(),
student_age: 11,
};
assert_eq!(report_card.print(), "Gary Plotter (11) - achieved a grade of A+");
}
}

View File

@@ -1,12 +1,13 @@
// if1.rs
// I AM NOT DONE
pub fn bigger(a: i32, b: i32) -> i32 {
// Complete this function to return the bigger number!
// Do not use:
// - return
// - another function call
// - additional variables
// Scroll down for hints.
// Execute `rustlings hint if1` for hints
}
// Don't mind this for now :)
@@ -24,36 +25,3 @@ mod tests {
assert_eq!(42, bigger(32, 42));
}
}
// 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.

36
exercises/if/if2.rs Normal file
View File

@@ -0,0 +1,36 @@
// if2.rs
// Step 1: Make me compile!
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
// Execute the command `rustlings hint if2` if you want a hint :)
// I AM NOT DONE
pub fn fizz_if_foo(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else {
1
}
}
// No test changes needed!
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn foo_for_fizz() {
assert_eq!(fizz_if_foo("fizz"), "foo")
}
#[test]
fn bar_for_fuzz() {
assert_eq!(fizz_if_foo("fuzz"), "bar")
}
#[test]
fn default_to_baz() {
assert_eq!(fizz_if_foo("literally anything"), "baz")
}
}

View File

@@ -2,7 +2,7 @@
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
modules, instead we'll show you how to use and create them.
macros. Instead, we'll show you how to use and create them.
#### Book Sections

View File

@@ -1,5 +1,7 @@
// macros1.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint macros1` for hints :)
// I AM NOT DONE
macro_rules! my_macro {
() => {
@@ -10,55 +12,3 @@ macro_rules! my_macro {
fn main() {
my_macro();
}
// When you call a macro, you need to add something special compared to a
// regular function call. If you're stuck, take a look at what's inside
// `my_macro`.

View File

@@ -1,5 +1,7 @@
// macros2.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint macros2` for hints :)
// I AM NOT DONE
fn main() {
my_macro!();
@@ -10,64 +12,3 @@ macro_rules! my_macro {
println!("Check out my macro!");
};
}
// Macros don't quite play by the same rules as the rest of Rust, in terms of
// what's available where.
// Unlike other things in Rust, the order of "where you define a macro" versus
// "where you use it" actually matters.

View File

@@ -1,5 +1,8 @@
// macros3.rs
// Make me compile, without taking the macro out of the module! Scroll down for hints :)
// Make me compile, without taking the macro out of the module!
// Execute `rustlings hint macros3` for hints :)
// I AM NOT DONE
mod macros {
macro_rules! my_macro {
@@ -12,64 +15,3 @@ mod macros {
fn main() {
my_macro!();
}
// In order to use a macro outside of its module, you need to do something
// special to the module to lift the macro out into its parent.
// The same trick also works on "extern crate" statements for crates that have
// exported macros, if you've seen any of those around.

View File

@@ -1,5 +1,7 @@
// macros4.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint macros4` for hints :)
// I AM NOT DONE
macro_rules! my_macro {
() => {
@@ -14,64 +16,3 @@ fn main() {
my_macro!();
my_macro!(7777);
}
// 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.

View File

@@ -1,5 +1,7 @@
// modules1.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint modules1` for hints :)
// I AM NOT DONE
mod sausage_factory {
fn make_sausage() {
@@ -10,34 +12,3 @@ mod sausage_factory {
fn main() {
sausage_factory::make_sausage();
}
// Everything is private in Rust by default-- but there's a keyword we can use
// to make something public! The compiler error should point to the thing that
// needs to be public.

View File

@@ -1,5 +1,7 @@
// modules2.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint modules2` for hints :)
// I AM NOT DONE
mod delicious_snacks {
use self::fruits::PEAR as fruit;
@@ -23,25 +25,3 @@ fn main() {
delicious_snacks::veggie
);
}
// The delicious_snacks module is trying to present an external
// interface (the `fruit` and `veggie` constants) that is different than
// its internal structure (the `fruits` and `veggies` modules and
// associated constants). It's almost there except for one keyword missing for
// each constant.

View File

@@ -1,5 +1,7 @@
// move_semantics1.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint move_semantics1` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
@@ -22,21 +24,3 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec
}
// So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 11,
// right? The fix for this is going to be adding one keyword, and the addition is NOT on line 11
// where the error is.

View File

@@ -1,5 +1,8 @@
// move_semantics2.rs
// Make me compile without changing line 10! Scroll down for hints :)
// Make me compile without changing line 13!
// Execute `rustlings hint move_semantics2` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
@@ -23,31 +26,3 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec
}
// So `vec0` is being *moved* into the function `fill_vec` when we call it on
// line 7, which means it gets dropped at the end of `fill_vec`, which means we
// can't use `vec0` again on line 10 (or anywhere else in `main` after the
// `fill_vec` call for that matter). We could fix this in a few ways, try them
// all!
// 1. Make another, separate version of the data that's in `vec0` and pass that
// to `fill_vec` instead.
// 2. Make `fill_vec` borrow its argument instead of taking ownership of it,
// and then copy the data within the function in order to return an owned
// `Vec<i32>`
// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be
// mutable), modify it directly, then not return anything. Then you can get rid
// of `vec1` entirely -- note that this will change what gets printed by the
// first `println!`

View File

@@ -1,7 +1,9 @@
// move_semantics3.rs
// Make me compile without adding new lines-- just changing existing lines!
// (no lines with multiple semicolons necessary!)
// Scroll down for hints :)
// Execute `rustlings hint move_semantics3` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
@@ -22,24 +24,3 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec
}
// The difference between this one and the previous ones is that the first line
// of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can,
// instead of adding that line back, add `mut` in one place that will change
// an existing binding to be a mutable binding instead of an immutable one :)

View File

@@ -1,7 +1,10 @@
// move_semantics4.rs
// Refactor this code so that instead of having `vec0` and creating the vector
// in `fn main`, we instead create it within `fn fill_vec` and transfer the
// freshly created vector from fill_vec to its caller. Scroll for hints!
// freshly created vector from fill_vec to its caller.
// Execute `rustlings hint move_semantics4` for hints!
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
@@ -25,24 +28,3 @@ fn fill_vec() -> Vec<i32> {
vec
}
// Stop reading whenever you feel like you have enough direction :) Or try
// doing one step and then fixing the compiler errors that result!
// So the end goal is to:
// - get rid of the first line in main that creates the new vector
// - so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
// - we don't want to pass anything to `fill_vec`, so its signature should
// reflect that it does not take any arguments
// - since we're not creating a new vec in `main` anymore, we need to create
// a new vec in `fill_vec`, similarly to the way we did in `main`

View File

@@ -0,0 +1,9 @@
### Option
#### Book Sections
To learn about Option<T>, check out these links:
- [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)

View File

@@ -0,0 +1,23 @@
// option1.rs
// Make me compile! Execute `rustlings hint option1` for hints
// I AM NOT DONE
// you can modify anything EXCEPT for this function's sig
fn print_number(maybe_number: Option<u16>) {
println!("printing: {}", maybe_number.unwrap());
}
fn main() {
print_number(13);
print_number(99);
let mut numbers: [Option<u16>; 5];
for iter in 0..5 {
let number_to_add: u16 = {
((iter * 1235) + 2) / (4 * 16)
};
numbers[iter as usize] = number_to_add;
}
}

View File

@@ -0,0 +1,25 @@
// option2.rs
// Make me compile! Execute `rustlings hint option2` for hints
// I AM NOT DONE
fn main() {
let optional_value = Some(String::from("rustlings"));
// TODO: Make this an if let statement whose value is "Some" type
value = optional_value {
println!("the value of optional value is: {}", value);
} else {
println!("The optional value doesn't contain anything!");
}
let mut optional_values_vec: Vec<Option<i8>> = Vec::new();
for x in 1..10 {
optional_values_vec.push(Some(x));
}
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
// You can stack `Option<T>`'s into while let and if let
value = optional_values_vec.pop() {
println!("current value: {}", value);
}
}

View File

@@ -2,6 +2,8 @@
// Fill in the rest of the line that has code missing!
// No hints, there's no tricks, just get used to typing these :)
// I AM NOT DONE
fn main() {
// Booleans (`bool`)

View File

@@ -2,6 +2,8 @@
// Fill in the rest of the line that has code missing!
// No hints, there's no tricks, just get used to typing these :)
// I AM NOT DONE
fn main() {
// Characters (`char`)

View File

@@ -1,6 +1,8 @@
// primitive_types3.rs
// Create an array with at least 100 elements in it where the ??? is.
// Scroll down for hints!
// Execute `rustlings hint primitive_types3` for hints!
// I AM NOT DONE
fn main() {
let a = ???
@@ -11,37 +13,3 @@ fn main() {
println!("Meh, I eat arrays like that for breakfast.");
}
}
// There's a shorthand to initialize Arrays with a certain size that does not
// require you to type in 100 items (but you certainly can if you want!).
// For example, you can do:
// let array = ["Are we there yet?"; 10];
// Bonus: what are some other things you could have that would return true
// for `a.len() >= 100`?

View File

@@ -1,68 +1,14 @@
// primitive_types4.rs
// Get a slice out of Array a where the ??? is so that the `if` statement
// returns true. Scroll down for hints!!
// 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 main() {
fn slice_out_of_array() {
let a = [1, 2, 3, 4, 5];
let nice_slice = ???
assert_eq!([2, 3, 4], nice_slice)
}
// Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
// https://doc.rust-lang.org/book/ch04-03-slices.html
// and use the starting and ending indices of the items in the Array
// that you want to end up in the slice.
// If you're curious why the right hand of the `==` comparison does not
// have an ampersand for a reference since the left hand side is a
// reference, take a look at the Deref coercions section of the book:
// https://doc.rust-lang.org/book/ch15-02-deref.html

View File

@@ -1,6 +1,8 @@
// primitive_types5.rs
// Destructure the `cat` tuple so that the println will work.
// Scroll down for hints!
// Execute `rustlings hint primitive_types5` for hints!
// I AM NOT DONE
fn main() {
let cat = ("Furry McFurson", 3.5);
@@ -8,38 +10,3 @@ fn main() {
println!("{} is {} years old.", name, age);
}
// Take a look at the Data Types -> The Tuple Type section of the book:
// https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
// Particularly the part about destructuring (second to last example in the section).
// You'll need to make a pattern to bind `name` and `age` to the appropriate parts
// of the tuple. You can do it!!

View File

@@ -1,45 +1,11 @@
// primitive_types6.rs
// Use a tuple index to access the second element of `numbers`.
// You can put this right into the `println!` where the ??? is.
// Scroll down for hints!
// Execute `rustlings hint primitive_types6` for hints!
// I AM NOT DONE
fn main() {
let numbers = (1, 2, 3);
println!("The second number is {}", ???);
}
// While you could use a destructuring `let` for the tuple here, try
// indexing into it instead, as explained in the last example of the
// Data Types -> The Tuple Type section of the book:
// https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
// Now you have another tool in your toolbox!

View File

@@ -1,12 +1,14 @@
// test1.rs
// This is a test for the following sections:
// quiz1.rs
// This is a quiz for the following sections:
// - Variables
// - Functions
// Mary is buying apples. One apple usually costs 2 dollars, but if you buy
// 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 order amount. No hints this time!
// I AM NOT DONE
// Put your function here!
// fn ..... {

View File

@@ -1,12 +1,14 @@
// strings3.rs
// This is a test for the following sections:
// quiz2.rs
// This is a quiz for the following sections:
// - Strings
// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. Your
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!
// I AM NOT DONE
fn string_slice(arg: &str) {
println!("{}", arg);
}

View File

@@ -1,12 +1,14 @@
// test2.rs
// This is a test for the following sections:
// quiz3.rs
// This is a quiz for the following sections:
// - Tests
// This test isn't testing our function -- make it do that in such a way that
// This quiz isn't testing our function -- make it do that in such a way that
// the test passes. Then write a second test that tests that we get the result
// we expect to get when we call `times_two` with a negative number.
// No hints, you can do this :)
// I AM NOT DONE
pub fn times_two(num: i32) -> i32 {
num * 2
}

23
exercises/quiz4.rs Normal file
View File

@@ -0,0 +1,23 @@
// 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!");
}
}

View File

@@ -1,5 +1,7 @@
For the Box exercise check out the chapter [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html).
For the Arc exercise check out the chapter [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) of the Rust Book.
For the Iterator exercise check out the chapters [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) of the Rust Book and the [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/).
Do not adjust your monitors-- iterators 1 and 2 are indeed missing. Iterator 3 is a bit challenging so we're leaving space for some exercises to lead up to it!
Do not adjust your monitors-- iterators1.rs is indeed missing. Iterators is a challenging topic, so we're leaving space for a simpler exercise!

View File

@@ -1,9 +1,12 @@
// arc1.rs
// Make this code compile by filling in a value for `shared_numbers` where the
// TODO comment is and creating an initial binding for `child_numbers`
// TODO comment is and create an initial binding for `child_numbers`
// somewhere. Try not to create any copies of the `numbers` Vec!
// Scroll down for hints :)
// 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;
@@ -27,29 +30,3 @@ fn main() {
handle.join().unwrap();
}
}
// Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order
// to avoid creating a copy of `numbers`, you'll need to create `child_numbers`
// inside the loop but still in the main thread.
// `child_numbers` should be a clone of the Arc of the numbers instead of a
// thread-local copy of the numbers.

View File

@@ -0,0 +1,53 @@
// 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())
}
}

View File

@@ -1,9 +1,13 @@
// iterators2.rs
// In this module, you'll learn some of unique advantages that iterators can offer
// Step 1. Complete the `capitalize_first` function to pass the first two cases
// Step 2. Apply the `capitalize_first` function to a vector of strings, ensuring that it returns a vector of strings as well
// Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string
// As always, there are hints below!
// In this module, you'll learn some of unique advantages that iterators can offer.
// Step 1. Complete the `capitalize_first` function to pass the first two cases.
// Step 2. Apply the `capitalize_first` function to a vector of strings.
// Ensure that it returns a vector of strings as well.
// Step 3. Apply the `capitalize_first` function again to a list.
// Try to ensure it returns a single string.
// As always, there are hints if you execute `rustlings hint iterators2`!
// I AM NOT DONE
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
@@ -44,102 +48,3 @@ mod tests {
assert_eq!(capitalized_words, "Hello World");
}
}
// Step 1
// You need to call something on `first` before it can be collected
// Currently its type is `char`. Have a look at the methods that are available on that type:
// https://doc.rust-lang.org/std/primitive.char.html
// Step 2
// First you'll need to turn the Vec into an iterator
// Then you'll need to apply your function unto each item in the vector
// P.s. Don't forget to collect() at the end!
// Step 3.
// This is very similar to the previous test. The only real change is that you will need to
// alter the type that collect is coerced into. For a bonus you could try doing this with a
// turbofish

View File

@@ -4,10 +4,11 @@
// 1. Complete the divide function to get the first four tests to pass
// 2. Uncomment the last two tests and get them to pass by filling in
// values for `x` using `division_results`.
// Scroll down for a minor hint for part 2, and scroll down further for
// a major hint.
// Execute `rustlings hint iterators3` to get some hints!
// Have fun :-)
// I AM NOT DONE
#[derive(Debug, PartialEq, Eq)]
pub enum DivisionError {
NotDivisible(NotDivisibleError),
@@ -75,72 +76,3 @@ mod tests {
}
*/
}
// Minor hint: In each of the two cases in the match in main, you can create x with either
// a 'turbofish' or by hinting the type of x to the compiler. You may try both.
// Major hint: Have a look at the Iter trait and at the explanation of its collect function.
// Especially the part about Result is interesting.

View File

@@ -1,15 +1,17 @@
// iterators4.rs
// I AM NOT DONE
pub fn factorial(num: u64) -> u64 {
// Complete this function to return factorial of num
// Complete this function to return the factorial of num
// Do not use:
// - return
// For extra fun don't use:
// Try not to use:
// - imperative style loops (for, while)
// - additional variables
// For the most fun don't use:
// For an extra challenge, don't use:
// - recursion
// Scroll down for hints.
// Execute `rustlings hint iterators4` for hints.
}
#[cfg(test)]
@@ -30,32 +32,3 @@ mod tests {
assert_eq!(24, factorial(4));
}
}
// In an imperative language you might write a for loop to iterate through
// multiply the values into a mutable variable. Or you might write code more
// functionally with recursion and a match clause. But you can also use ranges
// and iterators to solve this in rust.

View File

@@ -1,5 +1,8 @@
// strings1.rs
// Make me compile without changing the function signature! Scroll down for hints :)
// Make me compile without changing the function signature!
// Execute `rustlings hint strings1` for hints ;)
// I AM NOT DONE
fn main() {
let answer = current_favorite_color();
@@ -9,38 +12,3 @@ fn main() {
fn current_favorite_color() -> String {
"blue"
}
// The `current_favorite_color` function is currently returning a string slice with the `'static`
// lifetime. We know this because the data of the string lives in our code itself -- it doesn't
// come from a file or user input or another program -- so it will live as long as our program
// lives. But it is still a string slice. There's one way to create a `String` by converting a
// string slice covered in the Strings chapter of the book, and another way that uses the `From`
// trait.

View File

@@ -1,5 +1,8 @@
// strings2.rs
// Make me compile without changing the function signature! Scroll down for hints :)
// Make me compile without changing the function signature!
// Execute `rustlings hint strings2` for hints :)
// I AM NOT DONE
fn main() {
let word = String::from("green"); // Try not changing this line :)
@@ -13,32 +16,3 @@ fn main() {
fn is_a_color_word(attempt: &str) -> bool {
attempt == "green" || attempt == "blue" || attempt == "red"
}
// Yes, it would be really easy to fix this by just changing the value bound to `word` to be a
// string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
// 6, though, that will coerce the `String` into a string slice.

View File

@@ -1,6 +1,8 @@
// structs1.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
struct ColorClassicStruct {
// TODO: Something goes here
}
@@ -26,7 +28,6 @@ mod tests {
#[test]
fn tuple_structs() {
// TODO: Instantiate a tuple struct!
// For more fun, use the field initialization shorthand.
// let green =
assert_eq!(green.0, "green");

View File

@@ -1,6 +1,7 @@
// structs2.rs
// Address all the TODOs to make the tests pass!
// No hints, just do it!
// I AM NOT DONE
#[derive(Debug)]
struct Order {

View File

@@ -0,0 +1,67 @@
// structs3.rs
// Structs contain more than simply some data, they 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_kg: i32) -> ??? {
// Something goes here... (beware of grams to kg conversion)
}
}
#[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 calculate_transport_fees() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Spain");
let cents_per_kg = ???;
let package = Package::new(sender_country, recipient_country, 1500);
assert_eq!(package.get_fees(cents_per_kg), 4500);
}
}

View File

@@ -1,12 +0,0 @@
// test4.rs
// This test covers the sections:
// - Modules
// - Macros
// Write a macro that passes the test! No hints this time, you can do it!
fn main() {
if my_macro!("world!") != "Hello world!" {
panic!("Oh no! Wrong output!");
}
}

View File

@@ -1,10 +1,12 @@
// 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 --test exercises/tests/tests1.rs
// rustlings run tests1
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Scroll down for hints :)
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)
// I AM NOT DONE
#[cfg(test)]
mod tests {
@@ -13,37 +15,3 @@ mod tests {
assert!();
}
}
// You don't even need to write any code to test -- you can just test values and run that, even
// though you wouldn't do that in real life :) `assert!` is a macro that needs an argument.
// Depending on the value of the argument, `assert!` will do nothing (in which case the test will
// pass) or `assert!` will panic (in which case the test will fail). So try giving different values
// to `assert!` and see which ones compile, which ones pass, and which ones fail :)

View File

@@ -1,6 +1,8 @@
// tests2.rs
// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Scroll down for hints :)
// pass! Make the test fail! Execute `rustlings hint tests2` for hints :)
// I AM NOT DONE
#[cfg(test)]
mod tests {
@@ -9,36 +11,3 @@ mod tests {
assert_eq!();
}
}
// Like the previous exercise, you don't need to write any code to get this test to compile and
// run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two
// values that are equal! Try giving it two arguments that are different! Try giving it two values
// that are of different types! Try switching which argument comes first and which comes second!

View File

@@ -1,7 +1,10 @@
// 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)`. Scroll down for hints!
// we expect to get when we call `is_even(5)`.
// Execute `rustlings hint tests3` for hints :)
// I AM NOT DONE
pub fn is_even(num: i32) -> bool {
num % 2 == 0
@@ -16,28 +19,3 @@ mod tests {
assert!();
}
}
// You can call a function right where you're passing arguments to `assert!` -- so you could do
// something like `assert!(having_fun())`. If you want to check that you indeed get false, you
// can negate the result of what you're doing using `!`, like `assert!(!having_fun())`.

View File

@@ -1,10 +1,12 @@
// threads1.rs
// Make this compile! Scroll down for hints :) The idea is the thread
// spawned on line 19 is completing jobs while the main thread is
// Make this compile! Execute `rustlings hint threads1` for hints :)
// The idea is the thread spawned on line 21 is completing jobs while the main thread is
// monitoring progress until 10 jobs are completed. If you see 6 lines
// of "waiting..." and the program ends without timing out the playground,
// of "waiting..." and the program ends without timing out when running,
// you've got it :)
// I AM NOT DONE
use std::sync::Arc;
use std::thread;
use std::time::Duration;
@@ -27,69 +29,3 @@ fn main() {
thread::sleep(Duration::from_millis(500));
}
}
// `Arc` is an Atomic Reference Counted pointer that allows safe, shared access
// to **immutable** data. But we want to *change* the number of `jobs_completed`
// so we'll need to also use another type that will only allow one thread to
// mutate the data at a time. Take a look at this section of the book:
// https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
// and keep scrolling if you'd like more hints :)
// Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like:
// `let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));`
// Similar to the code in the example in the book that happens after the text
// that says "We can use Arc<T> to fix this.". If not, give that a try! If you
// do and would like more hints, keep scrolling!!
// Make sure neither of your threads are holding onto the lock of the mutex
// while they are sleeping, since this will prevent the other thread from
// being allowed to get the lock. Locks are automatically released when
// they go out of scope.
// Ok, so, real talk, this was actually tricky for *me* to do too. And
// I could see a lot of different problems you might run into, so at this
// point I'm not sure which one you've hit :) Please see a few possible
// answers on https://github.com/carols10cents/rustlings/issues/3 --
// mine is a little more complicated because I decided I wanted to see
// the number of jobs currently done when I was checking the status.
// Please open an issue if you're still running into a problem that
// these hints are not helping you with, or if you've looked at the sample
// answers and don't understand why they work and yours doesn't.
// If you've learned from the sample solutions, I encourage you to come
// back to this exercise and try it again in a few days to reinforce
// what you've learned :)

View File

@@ -0,0 +1,20 @@
### Traits
A trait is a collection of methods.
Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`.
In this way, traits are somewhat similar to Java interfaces and C++ abstract classes.
Some additional common Rust traits include:
+ `Clone` (the `clone` method),
+ `Display` (which allows formatted display via `{}`), and
+ `Debug` (which allows formatted display via `{:?}`).
Because traits indicate shared behavior between data types, they are useful when writing generics.
#### Book Sections
- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)

View File

@@ -0,0 +1,44 @@
// traits1.rs
// Time to implement some traits!
//
// Your task is to implement the trait
// `AppendBar' for the type `String'.
//
// The trait AppendBar has only one function,
// which appends "Bar" to any object
// implementing this trait.
// I AM NOT DONE
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
//Add your code here
}
fn main() {
let s = String::from("Foo");
let s = s.append_bar();
println!("s: {}", s);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_FooBar() {
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
}
#[test]
fn is_BarBar() {
assert_eq!(
String::from("").append_bar().append_bar(),
String::from("BarBar")
);
}
}

View File

@@ -0,0 +1,35 @@
// traits2.rs
//
// Your task is to implement the trait
// `AppendBar' for a vector of strings.
//
// To implement this trait, consider for
// a moment what it means to 'append "Bar"'
// to a vector of strings.
//
// No boiler plate code this time,
// you can do this!
// I AM NOT DONE
trait AppendBar {
fn append_bar(self) -> Self;
}
//TODO: Add your code here
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
}
}

View File

@@ -1,42 +1,14 @@
// variables1.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)
// About this `I AM NOT DONE` thing:
// We sometimes encourage you to keep trying things on a given exercise,
// even after you already figured it out. If you got everything working and
// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
// I AM NOT DONE
fn main() {
x = 5;
println!("x has the value {}", x);
}
// Hint: The declaration on line 5 is missing a keyword that is needed in Rust
// to create a new variable binding.

View File

@@ -1,5 +1,7 @@
// variables2.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
// I AM NOT DONE
fn main() {
let x;
@@ -9,39 +11,3 @@ fn main() {
println!("Not ten!");
}
}
// The compiler message is saying that Rust cannot infer the type that the
// variable binding `x` has with what is given here.
// What happens if you annotate line 5 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?

View File

@@ -1,43 +1,11 @@
// variables3.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute the command `rustlings hint variables3` if you want a hint :)
// I AM NOT DONE
fn main() {
let x = 3;
println!("Number {}", x);
x = 5;
x = 5; // don't change this line
println!("Number {}", x);
}
// In Rust, variable bindings are immutable by default. But here we're trying
// to reassign a different value to x! There's a keyword we can use to make
// a variable binding mutable instead.

View File

@@ -1,45 +1,9 @@
// variables4.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute the command `rustlings hint variables4` if you want a hint :)
// I AM NOT DONE
fn main() {
let x: i32;
println!("Number {}", x);
}
// Oops! In this exercise, we have a variable binding that we've created on
// line 5, and we're trying to use it on line 6, but we haven't given it a
// value. We can't print out something that isn't there; try giving x a value!
// This is an error that can cause bugs that's very easy to make in any
// programming language -- thankfully the Rust compiler has caught this for us!

View File

@@ -0,0 +1,11 @@
// variables5.rs
// Make me compile! Execute the command `rustlings hint variables5` if you want a hint :)
// I AM NOT DONE
fn main() {
let number = "3"; // don't change this line
println!("Number {}", number);
number = 3;
println!("Number {}", number);
}

View File

@@ -0,0 +1,9 @@
// variables6.rs
// Make me compile! Execute the command `rustlings hint variables6` if you want a hint :)
// I AM NOT DONE
const NUMBER = 3;
fn main() {
println!("Number {}", NUMBER);
}

661
info.toml
View File

@@ -1,241 +1,824 @@
# VARIABLES
[[exercises]]
name = "variables1"
path = "exercises/variables/variables1.rs"
mode = "compile"
hint = """
Hint: The declaration on line 12 is missing a keyword that is needed in Rust
to create a new variable binding."""
[[exercises]]
name = "variables2"
path = "exercises/variables/variables2.rs"
mode = "compile"
hint = """
The compiler message is saying that Rust cannot infer the type that the
variable binding `x` has with what is given here.
What happens if you annotate line 7 with a type annotation?
What if you give x a value?
What if you do both?
What type should x be, anyway?
What if x is the same type as 10? What if it's a different type?"""
[[exercises]]
name = "variables3"
path = "exercises/variables/variables3.rs"
mode = "compile"
hint = """
In Rust, variable bindings are immutable by default. But here we're trying
to reassign a different value to x! There's a keyword we can use to make
a variable binding mutable instead."""
[[exercises]]
name = "variables4"
path = "exercises/variables/variables4.rs"
mode = "compile"
hint = """
Oops! In this exercise, we have a variable binding that we've created on
line 7, and we're trying to use it on line 8, but we haven't given it a
value. We can't print out something that isn't there; try giving x a value!
This is an error that can cause bugs that's very easy to make in any
programming language -- thankfully the Rust compiler has caught this for us!"""
[[exercises]]
name = "variables5"
path = "exercises/variables/variables5.rs"
mode = "compile"
hint = """
In variables3 we already learned how to make an immutable variable mutable
using a special keyword. Unfortunately this doesn't help us much in this exercise
because we want to assign a different typed value to an existing variable. Sometimes
you may also like to reuse existing variable names because you are just converting
values to different types like in this exercise.
Fortunately Rust has a powerful solution to this problem: 'Shadowing'!
You can read more about 'Shadowing' in the book's section 'Variables and Mutability':
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
Try to solve this exercise afterwards using this technique."""
[[exercises]]
name = "variables6"
path = "exercises/variables/variables6.rs"
mode = "compile"
hint = """
We know about variables and mutability, but there is another important type of
variable available; constants.
Constants are always immutable and they are declared with keyword 'const' rather
than keyword 'let'.
Constants types must also always be annotated.
Read more about constants under 'Differences Between Variables and Constants' in the book's section 'Variables and Mutability':
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
"""
# IF
[[exercises]]
name = "if1"
path = "exercises/if/if1.rs"
mode = "test"
hint = """
It's possible to do this in one line if you would like!
Some similar examples from other languages:
- In C(++) this would be: `a > b ? a : b`
- In Python this would be: `a if a > b else b`
Remember in Rust that:
- the `if` condition does not need to be surrounded by parentheses
- `if`/`else` conditionals are expressions
- Each condition is followed by a `{}` block."""
[[exercises]]
name = "if2"
path = "exercises/if/if2.rs"
mode = "test"
hint = """
For that first compiler error, it's important in Rust that each conditional
block return the same type! To get the tests passing, you will need a couple
conditions checking different input values."""
# FUNCTIONS
[[exercises]]
name = "functions1"
path = "exercises/functions/functions1.rs"
mode = "compile"
hint = """
This main function is calling a function that it expects to exist, but the
function doesn't exist. It expects this function to have the name `call_me`.
It expects this function to not take any arguments and not return a value.
Sounds a lot like `main`, doesn't it?"""
[[exercises]]
name = "functions2"
path = "exercises/functions/functions2.rs"
mode = "compile"
hint = """
Rust requires that all parts of a function's signature have type annotations,
but `call_me` is missing the type annotation of `num`."""
[[exercises]]
name = "functions3"
path = "exercises/functions/functions3.rs"
mode = "compile"
hint = """
This time, the function *declaration* is okay, but there's something wrong
with the place where we're calling the function."""
[[exercises]]
name = "functions4"
path = "exercises/functions/functions4.rs"
mode = "compile"
hint = """
The error message points to line 14 and says it expects a type after the
`->`. This is where the function's return type should be-- take a look at
the `is_even` function for an example!"""
[[exercises]]
name = "functions5"
path = "exercises/functions/functions5.rs"
mode = "compile"
hint = """
This is a really common error that can be fixed by removing one character.
It happens because Rust distinguishes between expressions and statements: expressions return
a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language.
We want to return a value of `i32` type from the `square` function, but it is returning a `()` type...
They are not the same. There are two solutions:
1. Add a `return` ahead of `num * num;`
2. remove `;`, make it to be `num * num`"""
# TEST 1
[[exercises]]
path = "exercises/test1.rs"
name = "quiz1"
path = "exercises/quiz1.rs"
mode = "test"
hint = "No hints this time ;)"
# PRIMITIVE TYPES
[[exercises]]
name = "primitive_types1"
path = "exercises/primitive_types/primitive_types1.rs"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "primitive_types2"
path = "exercises/primitive_types/primitive_types2.rs"
mode = "compile"
hint = "No hints this time ;)"
[[exercises]]
name = "primitive_types3"
path = "exercises/primitive_types/primitive_types3.rs"
mode = "compile"
hint = """
There's a shorthand to initialize Arrays with a certain size that does not
require you to type in 100 items (but you certainly can if you want!).
For example, you can do:
let array = ["Are we there yet?"; 10];
Bonus: what are some other things you could have that would return true
for `a.len() >= 100`?"""
[[exercises]]
name = "primitive_types4"
path = "exercises/primitive_types/primitive_types4.rs"
mode = "test"
hint = """
Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
https://doc.rust-lang.org/book/ch04-03-slices.html
and use the starting and ending indices of the items in the Array
that you want to end up in the slice.
If you're curious why the first argument of `assert_eq!` does not
have an ampersand for a reference since the second argument is a
reference, take a look at the Deref coercions section of the book:
https://doc.rust-lang.org/book/ch15-02-deref.html"""
[[exercises]]
name = "primitive_types5"
path = "exercises/primitive_types/primitive_types5.rs"
mode = "compile"
hint = """
Take a look at the Data Types -> The Tuple Type section of the book:
https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
Particularly the part about destructuring (second to last example in the section).
You'll need to make a pattern to bind `name` and `age` to the appropriate parts
of the tuple. You can do it!!"""
[[exercises]]
name = "primitive_types6"
path = "exercises/primitive_types/primitive_types6.rs"
mode = "compile"
hint = """
While you could use a destructuring `let` for the tuple here, try
indexing into it instead, as explained in the last example of the
Data Types -> The Tuple Type section of the book:
https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
Now you have another tool in your toolbox!"""
# STRUCTS
[[exercises]]
name = "structs1"
path = "exercises/structs/structs1.rs"
mode = "test"
hint = """
Rust has more than one type of struct. Both variants are used to package related data together.
On the one hand, there are normal, or classic, structs. These are named collections of related data stored in fields.
The other variant is tuple structs. Basically just named tuples.
In this exercise you need to implement one of each kind.
Read more about structs in The Book: https://doc.rust-lang.org/stable/book/ch05-00-structs.html"""
[[exercises]]
name = "structs2"
path = "exercises/structs/structs2.rs"
mode = "test"
# ENUMS
hint = """
Creating instances of structs is easy, all you need to do is assign some values to its fields.
There is 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]]
path = "exercises/enums/enums1.rs"
mode = "compile"
[[exercises]]
path = "exercises/enums/enums2.rs"
mode = "compile"
[[exercises]]
path = "exercises/enums/enums3.rs"
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?
# TESTS
For is_international: What makes a package international? Seems related to the places it goes through right?
[[exercises]]
path = "exercises/tests/tests1.rs"
mode = "test"
For calculate_transport_fees: Bigger is more expensive usually, we don't have size, but something may fit the bill here :)
[[exercises]]
path = "exercises/tests/tests2.rs"
mode = "test"
[[exercises]]
path = "exercises/tests/tests3.rs"
mode = "test"
# TEST 2
[[exercises]]
path = "exercises/test2.rs"
mode = "test"
Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
# STRINGS
[[exercises]]
name = "strings1"
path = "exercises/strings/strings1.rs"
mode = "compile"
hint = """
The `current_favorite_color` function is currently returning a string slice with the `'static`
lifetime. We know this because the data of the string lives in our code itself -- it doesn't
come from a file or user input or another program -- so it will live as long as our program
lives. But it is still a string slice. There's one way to create a `String` by converting a
string slice covered in the Strings chapter of the book, and another way that uses the `From`
trait."""
[[exercises]]
name = "strings2"
path = "exercises/strings/strings2.rs"
mode = "compile"
hint = """
Yes, it would be really easy to fix this by just changing the value bound to `word` to be a
string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
9, though, that will coerce the `String` into a string slice."""
# TEST 2
[[exercises]]
name = "quiz2"
path = "exercises/quiz2.rs"
mode = "compile"
hint = "No hints this time ;)"
# ENUMS
[[exercises]]
name = "enums1"
path = "exercises/enums/enums1.rs"
mode = "compile"
hint = """
Hint: The declaration of the enumeration type has not been defined yet."""
[[exercises]]
name = "enums2"
path = "exercises/enums/enums2.rs"
mode = "compile"
hint = """
Hint: you can create enumerations that have different variants with different types
such as no data, anonymous structs, a single string, tuples, ...etc"""
[[exercises]]
name = "enums3"
path = "exercises/enums/enums3.rs"
mode = "test"
hint = "No hints this time ;)"
# TESTS
[[exercises]]
name = "tests1"
path = "exercises/tests/tests1.rs"
mode = "test"
hint = """
You don't even need to write any code to test -- you can just test values and run that, even
though you wouldn't do that in real life :) `assert!` is a macro that needs an argument.
Depending on the value of the argument, `assert!` will do nothing (in which case the test will
pass) or `assert!` will panic (in which case the test will fail). So try giving different values
to `assert!` and see which ones compile, which ones pass, and which ones fail :)"""
[[exercises]]
name = "tests2"
path = "exercises/tests/tests2.rs"
mode = "test"
hint = """
Like the previous exercise, you don't need to write any code to get this test to compile and
run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two
values that are equal! Try giving it two arguments that are different! Try giving it two values
that are of different types! Try switching which argument comes first and which comes second!"""
[[exercises]]
name = "tests3"
path = "exercises/tests/tests3.rs"
mode = "test"
hint = """
You can call a function right where you're passing arguments to `assert!` -- so you could do
something like `assert!(having_fun())`. If you want to check that you indeed get false, you
can negate the result of what you're doing using `!`, like `assert!(!having_fun())`."""
# TEST 3
[[exercises]]
path = "exercises/test3.rs"
mode = "compile"
name = "quiz3"
path = "exercises/quiz3.rs"
mode = "test"
hint = "No hints this time ;)"
# MODULES
[[exercises]]
name = "modules1"
path = "exercises/modules/modules1.rs"
mode = "compile"
hint = """
Everything is private in Rust by default-- but there's a keyword we can use
to make something public! The compiler error should point to the thing that
needs to be public."""
[[exercises]]
name = "modules2"
path = "exercises/modules/modules2.rs"
mode = "compile"
hint = """
The delicious_snacks module is trying to present an external
interface (the `fruit` and `veggie` constants) that is different than
its internal structure (the `fruits` and `veggies` modules and
associated constants). It's almost there except for one keyword missing for
each constant."""
# MACROS
[[exercises]]
name = "macros1"
path = "exercises/macros/macros1.rs"
mode = "compile"
hint = """
When you call a macro, you need to add something special compared to a
regular function call. If you're stuck, take a look at what's inside
`my_macro`."""
[[exercises]]
name = "macros2"
path = "exercises/macros/macros2.rs"
mode = "compile"
hint = """
Macros don't quite play by the same rules as the rest of Rust, in terms of
what's available where.
Unlike other things in Rust, the order of "where you define a macro" versus
"where you use it" actually matters."""
[[exercises]]
name = "macros3"
path = "exercises/macros/macros3.rs"
mode = "compile"
hint = """
In order to use a macro outside of its module, you need to do something
special to the module to lift the macro out into its parent.
The same trick also works on "extern crate" statements for crates that have
exported macros, if you've seen any of those around."""
[[exercises]]
name = "macros4"
path = "exercises/macros/macros4.rs"
mode = "compile"
hint = """
You only need to add a single character to make this compile.
The way macros are written, it wants to see something between each
"macro arm", so it can separate them."""
# TEST 4
[[exercises]]
path = "exercises/test4.rs"
mode = "compile"
name = "quiz4"
path = "exercises/quiz4.rs"
mode = "test"
hint = "No hints this time ;)"
# MOVE SEMANTICS
[[exercises]]
name = "move_semantics1"
path = "exercises/move_semantics/move_semantics1.rs"
mode = "compile"
hint = """
So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 13,
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 13
where the error is."""
[[exercises]]
name = "move_semantics2"
path = "exercises/move_semantics/move_semantics2.rs"
mode = "compile"
hint = """
So `vec0` is being *moved* into the function `fill_vec` when we call it on
line 10, which means it gets dropped at the end of `fill_vec`, which means we
can't use `vec0` again on line 13 (or anywhere else in `main` after the
`fill_vec` call for that matter). We could fix this in a few ways, try them
all!
1. Make another, separate version of the data that's in `vec0` and pass that
to `fill_vec` instead.
2. Make `fill_vec` borrow its argument instead of taking ownership of it,
and then copy the data within the function in order to return an owned
`Vec<i32>`
3. Make `fill_vec` *mutably* borrow its argument (which will need to be
mutable), modify it directly, then not return anything. Then you can get rid
of `vec1` entirely -- note that this will change what gets printed by the
first `println!`"""
[[exercises]]
name = "move_semantics3"
path = "exercises/move_semantics/move_semantics3.rs"
mode = "compile"
hint = """
The difference between this one and the previous ones is that the first line
of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can,
instead of adding that line back, add `mut` in one place that will change
an existing binding to be a mutable binding instead of an immutable one :)"""
[[exercises]]
name = "move_semantics4"
path = "exercises/move_semantics/move_semantics4.rs"
mode = "compile"
hint = """
Stop reading whenever you feel like you have enough direction :) Or try
doing one step and then fixing the compiler errors that result!
So the end goal is to:
- get rid of the first line in main that creates the new vector
- so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
- we don't want to pass anything to `fill_vec`, so its signature should
reflect that it does not take any arguments
- since we're not creating a new vec in `main` anymore, we need to create
a new vec in `fill_vec`, similarly to the way we did in `main`"""
# ERROR HANDLING
[[exercises]]
name = "errors1"
path = "exercises/error_handling/errors1.rs"
mode = "test"
hint = """
`Err` is one of the variants of `Result`, so what the 2nd test is saying
is that `generate_nametag_text` should return a `Result` instead of an
`Option`.
To make this change, you'll need to:
- update the return type in the function signature to be a Result<String, String> that
could be the variants `Ok(String)` and `Err(String)`
- change the body of the function to return `Ok(stuff)` where it currently
returns `Some(stuff)`
- change the body of the function to return `Err(error message)` where it
currently returns `None`
- change the first test to expect `Ok(stuff)` where it currently expects
`Some(stuff)`."""
[[exercises]]
name = "errors2"
path = "exercises/error_handling/errors2.rs"
mode = "test"
hint = """
One way to handle this is using a `match` statement on
`item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
`Err(something)`. This pattern is very common in Rust, though, so there's
a `?` operator that does pretty much what you would make that match statement
do for you! Take a look at this section of the Error Handling chapter:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
and give it a try!"""
[[exercises]]
name = "errors3"
path = "exercises/error_handling/errors3.rs"
mode = "test"
hint = """
If other functions can return a `Result`, why shouldn't `main`?"""
[[exercises]]
name = "errorsn"
path = "exercises/error_handling/errorsn.rs"
mode = "test"
hint = """
First hint: To figure out what type should go where the ??? is, take a look
at the test helper function `test_with_str`, since it returns whatever
`read_and_validate` returns and `test_with_str` has its signature fully
specified.
Next hint: There are three places in `read_and_validate` that we call a
function that returns a `Result` (that is, the functions might fail).
Apply the `?` operator on those calls so that we return immediately from
`read_and_validate` if those function calls fail.
Another hint: under the hood, the `?` operator calls `From::from`
on the error value to convert it to a boxed trait object, a Box<dyn error::Error>,
which is polymorphic-- that means that lots of different kinds of errors
can be returned from the same function because all errors act the same
since they all implement the `error::Error` trait.
Check out this section of the book:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
Another another hint: Note that because the `?` operator returns
the *unwrapped* value in the `Ok` case, if we want to return a `Result` from
`read_and_validate` for *its* success case, we'll have to rewrap a value
that we got from the return value of a `?`ed call in an `Ok`-- this will
look like `Ok(something)`.
Another another another hint: `Result`s must be "used", that is, you'll
get a warning if you don't handle a `Result` that you get in your
function. Read more about that in the `std::result` module docs:
https://doc.rust-lang.org/std/result/#results-must-be-used"""
# OPTIONS / RESULTS
[[exercises]]
path = "exercises/error_handling/option1.rs"
mode = "test"
name = "option1"
path = "exercises/option/option1.rs"
mode = "compile"
hint = """
Hint 1: Check out some functions of Option:
is_some
is_none
unwrap
and:
pattern matching
Hint 2: There are no sensible defaults for the value of an Array; the values need to be filled before use.
"""
[[exercises]]
name = "option2"
path = "exercises/option/option2.rs"
mode = "compile"
hint = """
check out:
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html
Remember that Options can be stacked in if let and while let.
For example: Some(Some(variable)) = variable2
"""
[[exercises]]
name = "result1"
path = "exercises/error_handling/result1.rs"
mode = "test"
hint = """
`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
It should be doing some checking, returning an `Err` result if those checks fail, and only
returning an `Ok` result if those checks determine that everything is... okay :)"""
# THREADS
# CLIPPY
[[exercises]]
path = "exercises/threads/threads1.rs"
mode = "compile"
name = "clippy1"
path = "exercises/clippy/clippy1.rs"
mode = "clippy"
hint = """
Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble"""
[[exercises]]
name = "clippy2"
path = "exercises/clippy/clippy2.rs"
mode = "clippy"
hint = """
`for` loops over Option values are more clearly expressed as an `if let`"""
# STANDARD LIBRARY TYPES
[[exercises]]
name = "box1"
path = "exercises/standard_library_types/box1.rs"
mode = "test"
hint = """
Step 1
The compiler's message should help: since we cannot store the value of the actual type
when working with recursive types, we need to store a reference (pointer) to its value.
We should, therefore, place our `List` inside a `Box`. More details in the book here:
https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes
Step 2
Creating an empty list should be fairly straightforward (hint: peek at the assertions).
For a non-empty list keep in mind that we want to use our Cons "list builder".
Although the current list is one of integers (i32), feel free to change the definition
and try other types!
"""
[[exercises]]
name = "arc1"
path = "exercises/standard_library_types/arc1.rs"
mode = "compile"
hint = """
Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order
to avoid creating a copy of `numbers`, you'll need to create `child_numbers`
inside the loop but still in the main thread.
`child_numbers` should be a clone of the Arc of the numbers instead of a
thread-local copy of the numbers."""
[[exercises]]
name = "iterators2"
path = "exercises/standard_library_types/iterators2.rs"
mode = "test"
hint = """
Step 1
You need to call something on `first` before it can be collected
Currently its type is `char`. Have a look at the methods that are available on that type:
https://doc.rust-lang.org/std/primitive.char.html
Step 2
First you'll need to turn the Vec into an iterator
Then you'll need to apply your function unto each item in the vector
P.s. Don't forget to collect() at the end!
Step 3.
This is very similar to the previous test. The only real change is that you will need to
alter the type that collect is coerced into. For a bonus you could try doing this with a
turbofish"""
[[exercises]]
name = "iterators3"
path = "exercises/standard_library_types/iterators3.rs"
mode = "test"
hint = """
Minor hint: In each of the two cases in the match in main, you can create x with either
a 'turbofish' or by hinting the type of x to the compiler. You may try both.
Major hint: Have a look at the Iter trait and at the explanation of its collect function.
Especially the part about Result is interesting."""
[[exercises]]
name = "iterators4"
path = "exercises/standard_library_types/iterators4.rs"
mode = "test"
hint = """
In an imperative language, you might write a for loop that updates
a mutable variable. Or, you might write code utilizing recursion
and a match clause. In Rust you can take another functional
approach, computing the factorial elegantly with ranges and iterators."""
# TRAITS
[[exercises]]
name = "traits1"
path = "exercises/traits/traits1.rs"
mode = "test"
hint = """
A discussion about Traits in Rust can be found at:
https://doc.rust-lang.org/book/ch10-02-traits.html
"""
[[exercises]]
name = "traits2"
path = "exercises/traits/traits2.rs"
mode = "test"
hint = """
Notice how the trait takes ownership of 'self',and returns `Self'.
Try mutating the incoming string vector.
Vectors provide suitable methods for adding an element at the end. See
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
# Generics
[[exercises]]
name = "generics1"
path = "exercises/generics/generics1.rs"
mode = "compile"
hint = """
Vectors in rust make use of generics to create dynamically sized arrays of any type.
You need to tell the compiler what type we are pushing onto this vector."""
[[exercises]]
name = "generics2"
path = "exercises/generics/generics2.rs"
mode = "test"
hint = """
Currently we are wrapping only values of type 'u32'.
Maybe we could update the explicit references to this data type somehow?
If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions
"""
[[exercises]]
name = "generics3"
path = "exercises/generics/generics3.rs"
mode = "test"
hint = """
To find the best solution to this challenge you're going to need to think back to your
knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"
This is definitely harder than the last two exercises! You need to think about not only making the
ReportCard struct generic, but also the correct property - you will need to change the implementation
of the struct slightly too...you can do it!
"""
# THREADS
[[exercises]]
name = "threads1"
path = "exercises/threads/threads1.rs"
mode = "compile"
hint = """
`Arc` is an Atomic Reference Counted pointer that allows safe, shared access
to **immutable** data. But we want to *change* the number of `jobs_completed`
so we'll need to also use another type that will only allow one thread to
mutate the data at a time. Take a look at this section of the book:
https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
and keep reading if you'd like more hints :)
Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like:
`let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));`
Similar to the code in the example in the book that happens after the text
that says "We can use Arc<T> to fix this.". If not, give that a try! If you
do and would like more hints, keep reading!!
Make sure neither of your threads are holding onto the lock of the mutex
while they are sleeping, since this will prevent the other thread from
being allowed to get the lock. Locks are automatically released when
they go out of scope.
Ok, so, real talk, this was actually tricky for *me* to do too. And
I could see a lot of different problems you might run into, so at this
point I'm not sure which one you've hit :)
Please open an issue if you're still running into a problem that
these hints are not helping you with, or if you've looked at the sample
answers and don't understand why they work and yours doesn't.
If you've learned from the sample solutions, I encourage you to come
back to this exercise and try it again in a few days to reinforce
what you've learned :)"""
# TYPE CONVERSIONS
[[exercises]]
name = "using_as"
path = "exercises/conversions/using_as.rs"
mode = "compile"
hint = """
Use the `as` operator to cast one of the operands in the last line of the
`average` function into the expected return type."""
[[exercises]]
name = "from_into"
path = "exercises/conversions/from_into.rs"
mode = "test"
hint = """
Follow the steps provided right before the `From` implementation"""
[[exercises]]
name = "try_from_into"
path = "exercises/conversions/try_from_into.rs"
mode = "test"
hint = """
Follow the steps provided right before the `TryFrom` implementation.
You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html"""
[[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 a string if the string is not valid.
This is almost like the `try_from_into` exercise."""

View File

@@ -72,6 +72,7 @@ if (!($LASTEXITCODE -eq 0)) {
# but anyone running pwsh 5 will have to pass the argument.
$version = Invoke-WebRequest -UseBasicParsing https://api.github.com/repos/rust-lang/rustlings/releases/latest `
| ConvertFrom-Json | Select-Object -ExpandProperty tag_name
Write-Host "Checking out version $version..."
Set-Location $path
git checkout -q tags/$version
@@ -82,4 +83,12 @@ if (!(Get-Command rustlings -ErrorAction SilentlyContinue)) {
Write-Host "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
}
# Checking whether Clippy is installed.
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
$clippy = (rustup component list | Select-String "clippy" | Select-String "installed") | Out-String
if (!$clippy) {
Write-Host "Installing the 'cargo-clippy' executable..."
rustup component add clippy
}
Write-Host "All done! Run 'rustlings' to get started."

View File

@@ -7,7 +7,7 @@ if [ -x "$(command -v git)" ]
then
echo "SUCCESS: Git is installed"
else
echo "WARNING: Git does not seem to be installed."
echo "ERROR: Git does not seem to be installed."
echo "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
fi
@@ -16,7 +16,7 @@ if [ -x "$(command -v rustc)" ]
then
echo "SUCCESS: Rust is installed"
else
echo "WARNING: Rust does not seem to be installed."
echo "ERROR: Rust does not seem to be installed."
echo "Please download Rust using https://rustup.rs!"
exit 1
fi
@@ -25,11 +25,27 @@ if [ -x "$(command -v cargo)" ]
then
echo "SUCCESS: Cargo is installed"
else
echo "WARNING: Cargo does not seem to be installed."
echo "ERROR: Cargo does not seem to be installed."
echo "Please download Rust and Cargo using https://rustup.rs!"
exit 1
fi
# Look up python installations, starting with 3 with a fallback of 2
if [ -x "$(command -v python3)" ]
then
PY="$(command -v python3)"
elif [ -x "$(command -v python)" ]
then
PY="$(command -v python)"
elif [ -x "$(command -v python2)" ]
then
PY="$(command -v python2)"
else
echo "ERROR: No working python installation was found"
echo "Please install python and add it to the PATH variable"
exit 1
fi
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
function vercomp() {
@@ -75,7 +91,7 @@ MinRustVersion=1.31
vercomp $RustVersion $MinRustVersion
if [ $? -eq 2 ]
then
echo "WARNING: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "Please update Rust with 'rustup update'"
exit 1
else
@@ -86,17 +102,46 @@ Path=${1:-rustlings/}
echo "Cloning Rustlings at $Path..."
git clone -q https://github.com/rust-lang/rustlings $Path
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
echo "Checking out version $Version..."
cd $Path
git checkout -q tags/$Version
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | ${PY} -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin"
if [[ -z ${Version} ]]
then
echo "The latest tag version could not be fetched remotely."
echo "Using the local git repository..."
Version=$(ls -tr .git/refs/tags/ | tail -1)
if [[ -z ${Version} ]]
then
echo "No valid tag version found"
echo "Rustlings will be installed using the main branch"
Version="main"
else
Version="tags/${Version}"
fi
else
Version="tags/${Version}"
fi
echo "Checking out version $Version..."
git checkout -q ${Version}
echo "Installing the 'rustlings' executable..."
cargo install --force --path .
if ! [ -x "$(command -v rustlings)" ]
then
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
echo "WARNING: Please check that you have '$CargoBin' in your PATH environment variable!"
fi
# Checking whether Clippy is installed.
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
Clippy=$(rustup component list | grep "clippy" | grep "installed")
if [ -z "$Clippy" ]
then
echo "Installing the 'cargo-clippy' executable..."
rustup component add clippy
fi
echo "All done! Run 'rustlings' to get started."

View File

@@ -1,20 +1,32 @@
use regex::Regex;
use serde::Deserialize;
use std::fmt::{self, Display, Formatter};
use std::fs::remove_file;
use std::fs::{self, remove_file, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::{self, Command, Output};
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 to this process
#[inline]
fn temp_file() -> String {
format!("./temp_{}", process::id())
}
#[derive(Deserialize)]
// The mode of the exercise.
#[derive(Deserialize, Copy, Clone)]
#[serde(rename_all = "lowercase")]
pub enum Mode {
// Indicates that the exercise should be compiled as a binary
Compile,
// Indicates that the exercise should be compiled as a test harness
Test,
// Indicates that the exercise should be linted with clippy
Clippy,
}
#[derive(Deserialize)]
@@ -22,15 +34,74 @@ pub struct ExerciseList {
pub exercises: Vec<Exercise>,
}
// A representation of a rustlings exercise.
// This is deserialized from the accompanying info.toml file
#[derive(Deserialize)]
pub struct Exercise {
// Name of the exercise
pub name: String,
// The path to the file containing the exercise's source code
pub path: PathBuf,
// The mode of the exercise (Test, Compile, or Clippy)
pub mode: Mode,
// The hint text associated with the exercise
pub hint: String,
}
// An enum to track of the state of an Exercise.
// An Exercise can be either Done or Pending
#[derive(PartialEq, Debug)]
pub enum State {
// The state of the exercise once it's been completed
Done,
// The state of the exercise while it's not completed yet
Pending(Vec<ContextLine>),
}
// The context information of a pending exercise
#[derive(PartialEq, Debug)]
pub struct ContextLine {
// The source code that is still pending completion
pub line: String,
// The line number of the source code still pending completion
pub number: usize,
// Whether or not this is important
pub important: bool,
}
// The result of compiling an exercise
pub struct CompiledExercise<'a> {
exercise: &'a Exercise,
_handle: FileHandle,
}
impl<'a> CompiledExercise<'a> {
// Run the compiled exercise
pub fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
self.exercise.run()
}
}
// A representation of an already executed binary
#[derive(Debug)]
pub struct ExerciseOutput {
// The textual contents of the standard output of the binary
pub stdout: String,
// The textual contents of the standard error of the binary
pub stderr: String,
}
struct FileHandle;
impl Drop for FileHandle {
fn drop(&mut self) {
clean();
}
}
impl Exercise {
pub fn compile(&self) -> Output {
match self.mode {
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)
@@ -39,18 +110,121 @@ impl Exercise {
.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
);
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml)
.expect("Failed to write 📎 Clippy 📎 Cargo.toml file.");
// To support the ability to run the clipy exercises, build
// an executable, in addition to running clippy. With a
// compilation failure, this would silently fail. But we expect
// clippy to reflect the same failure while compiling later.
Command::new("rustc")
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output()
.expect("Failed to compile!");
// Due to an issue with Clippy, a cargo clean is required to catch all lints.
// See https://github.com/rust-lang/rust-clippy/issues/2604
// This is already fixed on Clippy's master branch. See this issue to track merging into Cargo:
// https://github.com/rust-lang/rust-clippy/issues/3837
Command::new("cargo")
.args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
.output()
.expect("Failed to run 'cargo clean'");
Command::new("cargo")
.args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
.args(&["--", "-D", "warnings"])
.output()
}
}
.expect("Failed to run 'compile' command.");
if cmd.status.success() {
Ok(CompiledExercise {
exercise: &self,
_handle: FileHandle,
})
} else {
clean();
Err(ExerciseOutput {
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
})
}
.expect("Failed to run 'compile' command.")
}
pub fn run(&self) -> Output {
Command::new(&temp_file())
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")
.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 clean(&self) {
let _ignored = remove_file(&temp_file());
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)
}
}
@@ -60,20 +234,92 @@ impl Display for Exercise {
}
}
#[inline]
fn clean() {
let _ignored = remove_file(&temp_file());
}
#[cfg(test)]
mod test {
use super::*;
use std::fs::File;
use std::path::Path;
#[test]
fn test_clean() {
File::create(&temp_file()).unwrap();
let exercise = Exercise {
path: PathBuf::from("example.rs"),
mode: Mode::Test,
name: String::from("example"),
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
mode: Mode::Compile,
hint: String::from(""),
};
exercise.clean();
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: "finished_exercise".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"));
}
}

View File

@@ -2,14 +2,22 @@ use crate::exercise::{Exercise, ExerciseList};
use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use console::Emoji;
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::fs;
use std::io;
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;
@@ -19,18 +27,36 @@ fn main() {
.version(crate_version!())
.author("Olivia Hugger, Carol Nichols")
.about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
.subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
.subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
.arg(
Arg::with_name("nocapture")
.long("nocapture")
.help("Show outputs from the test exercises")
)
.subcommand(
SubCommand::with_name("verify")
.alias("v")
.about("Verifies all exercises according to the recommended order")
)
.subcommand(
SubCommand::with_name("watch")
.alias("w")
.about("Reruns `verify` when files were edited")
)
.subcommand(
SubCommand::with_name("run")
.alias("r")
.about("Runs/Tests a single exercise")
.arg(Arg::with_name("file").required(true).index(1))
.arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
.arg(Arg::with_name("name").required(true).index(1)),
)
.subcommand(
SubCommand::with_name("hint")
.alias("h")
.about("Returns a hint for the current exercise")
.arg(Arg::with_name("name").required(true).index(1)),
)
.get_matches();
if None == matches.subcommand_name() {
if matches.subcommand_name().is_none() {
println!();
println!(r#" welcome to... "#);
println!(r#" _ _ _ "#);
@@ -51,39 +77,62 @@ fn main() {
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 = matches.is_present("nocapture");
if let Some(ref matches) = matches.subcommand_matches("run") {
let filename = matches.value_of("file").unwrap_or_else(|| {
println!("Please supply a file name!");
std::process::exit(1);
});
let name = matches.value_of("name").unwrap();
let matching_exercise = |e: &&Exercise| {
Path::new(filename)
.canonicalize()
.map(|p| p.ends_with(&e.path))
.unwrap_or(false)
};
let matching_exercise = |e: &&Exercise| name == e.name;
let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
println!("No exercise found for your file name!");
println!("No exercise found for your given name!");
std::process::exit(1)
});
run(&exercise).unwrap_or_else(|_| std::process::exit(1));
run(&exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
}
if let Some(ref matches) = matches.subcommand_matches("hint") {
let name = matches.value_of("name").unwrap();
let exercise = exercises
.iter()
.find(|e| name == e.name)
.unwrap_or_else(|| {
println!("No exercise found for your given name!");
std::process::exit(1)
});
println!("{}", exercise.hint);
}
if matches.subcommand_matches("verify").is_some() {
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1));
}
if matches.subcommand_matches("watch").is_some() {
/* Clears the terminal with an ANSI escape code.
Works in UNIX and newer Windows terminals. */
println!("\x1Bc");
watch(&exercises).unwrap();
if matches.subcommand_matches("watch").is_some() && watch(&exercises, verbose).is_ok() {
println!(
"{emoji} All exercises completed! {emoji}",
emoji = Emoji("🎉", "")
);
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");
}
if matches.subcommand_name().is_none() {
@@ -92,25 +141,63 @@ fn main() {
}
}
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>) {
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
println!("Type 'hint' to get help");
thread::spawn(move || loop {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => {
if input.trim().eq("hint") {
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
println!("{}", hint);
}
} else {
println!("unknown command: {}", input);
}
}
Err(error) => println!("error reading command: {}", error),
}
});
}
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)?;
let _ignored = verify(exercises.iter());
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() {
println!("----------**********----------\n");
let filepath = b.as_path().canonicalize().unwrap();
let exercise = exercises
let pending_exercises = exercises
.iter()
.skip_while(|e| !filepath.ends_with(&e.path));
let _ignored = verify(exercise);
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));
}
}
}
}
_ => {}
@@ -119,3 +206,13 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
}
}
}
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)
}

View File

@@ -1,52 +1,58 @@
use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use console::{style, Emoji};
use indicatif::ProgressBar;
pub fn run(exercise: &Exercise) -> Result<(), ()> {
// 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)?,
Mode::Test => test(exercise, verbose)?,
Mode::Compile => compile_and_run(exercise)?,
Mode::Clippy => compile_and_run(exercise)?,
}
Ok(())
}
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
// Invoke the rust compiler on the path of the given exercise
// and run the ensuing binary.
// This is strictly for non-test binaries, so output is displayed
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilecmd = exercise.compile();
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());
if compilecmd.status.success() {
let runcmd = exercise.run();
progress_bar.finish_and_clear();
let result = compilation.run();
progress_bar.finish_and_clear();
if runcmd.status.success() {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
let formatstr = format!("{} Successfully ran {}", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
exercise.clean();
match result {
Ok(output) => {
println!("{}", output.stdout);
success!("Successfully ran {}", exercise);
Ok(())
} else {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
}
Err(output) => {
println!("{}", output.stdout);
println!("{}", output.stderr);
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
println!("{}", style(formatstr).red());
exercise.clean();
warn!("Ran {} with errors", exercise);
Err(())
}
} else {
progress_bar.finish_and_clear();
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
exercise.clean();
Err(())
}
}

23
src/ui.rs Normal file
View File

@@ -0,0 +1,23 @@
macro_rules! warn {
($fmt:literal, $ex:expr) => {{
use console::{style, Emoji};
let formatstr = format!($fmt, $ex);
println!(
"{} {}",
style(Emoji("⚠️ ", "!")).red(),
style(formatstr).red()
);
}};
}
macro_rules! success {
($fmt:literal, $ex:expr) => {{
use console::{style, Emoji};
let formatstr = format!($fmt, $ex);
println!(
"{} {}",
style(Emoji("", "")).green(),
style(formatstr).green()
);
}};
}

View File

@@ -1,79 +1,185 @@
use crate::exercise::{Exercise, Mode};
use console::{style, Emoji};
use crate::exercise::{CompiledExercise, Exercise, Mode, State};
use console::style;
use indicatif::ProgressBar;
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), ()> {
// 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 {
match exercise.mode {
Mode::Test => test(&exercise)?,
Mode::Compile => compile_only(&exercise)?,
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(())
}
fn compile_only(exercise: &Exercise) -> Result<(), ()> {
enum RunMode {
Interactive,
NonInteractive,
}
// Compile and run the resulting test harness of the given Exercise
pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
compile_and_test(exercise, RunMode::NonInteractive, verbose)?;
Ok(())
}
// Invoke the rust compiler without running the resulting binary
fn compile_only(exercise: &Exercise) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compile_output = exercise.compile();
let _ = compile(&exercise, &progress_bar)?;
progress_bar.finish_and_clear();
if compile_output.status.success() {
let formatstr = format!("{} Successfully compiled {}!", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
exercise.clean();
Ok(())
} else {
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
exercise.clean();
Err(())
}
success!("Successfully compiled {}!", exercise);
Ok(prompt_for_completion(&exercise, None))
}
pub fn test(exercise: &Exercise) -> Result<(), ()> {
// Compile the given Exercise and run the resulting binary in an interactive mode
fn compile_and_run_interactively(exercise: &Exercise) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compilation = compile(&exercise, &progress_bar)?;
progress_bar.set_message(format!("Running {}...", exercise).as_str());
let result = compilation.run();
progress_bar.finish_and_clear();
let output = match result {
Ok(output) => output,
Err(output) => {
warn!("Ran {} with errors", exercise);
println!("{}", output.stdout);
return Err(());
}
};
success!("Successfully ran {}!", exercise);
Ok(prompt_for_completion(&exercise, Some(output.stdout)))
}
// Compile the given Exercise as a test harness and display
// the output if verbose is set to true
fn compile_and_test(
exercise: &Exercise, run_mode: RunMode, verbose: bool
) -> Result<bool, ()> {
let progress_bar = ProgressBar::new_spinner();
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
progress_bar.enable_steady_tick(100);
let compile_output = exercise.compile();
if compile_output.status.success() {
progress_bar.set_message(format!("Running {}...", exercise).as_str());
let compilation = compile(exercise, &progress_bar)?;
let result = compilation.run();
progress_bar.finish_and_clear();
let runcmd = exercise.run();
progress_bar.finish_and_clear();
if runcmd.status.success() {
let formatstr = format!("{} Successfully tested {}!", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
exercise.clean();
Ok(())
} else {
let formatstr = format!(
"{} Testing of {} failed! Please try again. Here's the output:",
Emoji("⚠️ ", "!"),
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!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
exercise.clean();
println!("{}", output.stdout);
Err(())
}
} else {
progress_bar.finish_and_clear();
let formatstr = format!(
"{} Compiling of {} failed! Please try again. Here's the output:",
Emoji("⚠️ ", "!"),
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
exercise.clean();
Err(())
}
}
// Compile the given Exercise and return an object with information
// about the state of the compilation
fn compile<'a, 'b>(
exercise: &'a Exercise,
progress_bar: &'b ProgressBar,
) -> Result<CompiledExercise<'a>, ()> {
let compilation_result = exercise.compile();
match compilation_result {
Ok(compilation) => Ok(compilation),
Err(output) => {
progress_bar.finish_and_clear();
warn!(
"Compiling of {} failed! Please try again. Here's the output:",
exercise
);
println!("{}", output.stderr);
Err(())
}
}
}
fn prompt_for_completion(exercise: &Exercise, prompt_output: Option<String>) -> bool {
let context = match exercise.state() {
State::Done => return true,
State::Pending(context) => context,
};
let success_msg = match exercise.mode {
Mode::Compile => "The code is compiling!",
Mode::Test => "The code is compiling, and the tests pass!",
Mode::Clippy => "The code is compiling, and 📎 Clippy 📎 is happy!",
};
println!();
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()
}

View File

@@ -1,7 +1,11 @@
[[exercises]]
name = "compFailure"
path = "compFailure.rs"
mode = "compile"
hint = ""
[[exercises]]
name = "testFailure"
path = "testFailure.rs"
mode = "test"
mode = "test"
hint = "Hello!"

View File

@@ -0,0 +1,5 @@
// fake_exercise
fn main() {
}

Some files were not shown because too many files have changed in this diff Show More