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

Compare commits

...

177 Commits
1.0.0 ... 2.0.0

Author SHA1 Message Date
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
marisa
c8babbad27 1.5.0 2019-11-09 10:52:20 +01:00
bors
c6dad28ddc Auto merge of #224 - nyxtom:feat-enums, r=fmoko
feat: Add enums exercises

Creates an exhaustive list of enum exercises. This goes through the basics of different ways to derive enums with mixed data type variants, as well as the use of the all important `match` operator.
2019-11-09 09:41:36 +00:00
bors
fea81419cd Auto merge of #227 - workingjubilee:watch-clears-terminal, r=fmoko
watch: clears terminal before entering loop

Fixes #146

If someone is sliding in and out of "watch" mode, it can make it hard
to tell which error messages are still relevant. This patch resolves
that by clearing the terminal entirely before entering watch's loop.

Note that the escape character is chosen for compatibility reasons, because different shells/terminals can change which commands they accept or have installed, betting on what other commands are in use to collect data seems risky, and just expecting them to implement ANSI escape code sequences is more reliable. This seems especially true since Windows is seeking more UNIX compatibility in its terminals going forward, even though it doesn't implement the POSIX standard per se.
2019-11-09 09:31:50 +00:00
Jubilee Young
83be517e77 watch: clears terminal before entering loop
If someone is sliding in and out of "watch" mode, it can make it hard
to tell which error messages are still relevant. This patch resolves
that by clearing the terminal entirely before entering watch's loop.
2019-11-09 00:57:36 -08:00
marisa
79a569422c fix: Rewrite test1 logic 2019-10-29 20:53:41 +01:00
bors
1e0b12e37e Auto merge of #225 - ssweeny:fix/test1-wording, r=fmoko
chore: Clarify comment in exercises/test1.rs

closes #194

The author of issue #194 suggests that the wording of the comment is at
least ambiguous about the desired results. I believe this change more
clearly describes the expectation of the exercise.
2019-10-29 13:37:30 +00:00
Thomas Holloway
dc15032112 feat: Add enums exercises 2019-10-28 22:49:49 -05:00
Scott Sweeny
2821227acf chore: Clarify comment in exercises/test1.rs
closes #194

The author of issue #194 suggests that the wording of the comment is at
least ambiguous about the desired results. I believe this change more
clearly describes the expectation of the exercise.
2019-10-28 23:08:46 -04:00
bors
2191ef7eee Auto merge of #219 - vyaslav:master, r=fmoko
Added exercise for struct update syntax

Added one exercise for struct update syntax `struct2.rs`
2019-10-28 22:56:54 +00:00
marisa
4c2cf6da75 fix(option1): Fix arguments passed to assert! macro (#222)
fix(option1): Fix arguments passed to assert! macro
2019-10-26 00:27:40 +02:00
marisa
0f3d6d871e chore: Bump version in Cargo.lock (#223)
chore: Bump version in Cargo.lock
2019-10-26 00:27:17 +02:00
Niklas Anderson
bd007d4617 chore: Bump version in Cargo.lock 2019-10-25 14:57:30 -07:00
Niklas Anderson
ead4f7af9e fix(option1): Fix arguments passed to assert! macro 2019-10-25 14:27:24 -07:00
marisa
4808b5b3ba Update README to show latest version, for those who copy/paste (#221)
Update README to show latest version, for those who copy/paste
2019-10-25 01:54:10 +02:00
Mark Provan
f3da6796b9 Update README to show latest version, for those who copy/paste 2019-10-24 13:56:14 +01:00
marisa
cece12e87e docs: Add automatic Windows support to Readme 2019-10-23 13:01:07 +02:00
marisa
68d1727cac chore(ci): Remove GitHub actions for now 2019-10-23 12:56:07 +02:00
bors
8a2e13b20a Auto merge of #220 - gdoenlen:master, r=fmoko
Add windows install script

Adds a powershell install script for windows users that are at least
running powershell 5. It is almost a direct port of install.sh.
This would be used to automatically download the script much like
curl | bash, but with:

`Invoke-WebRequest https://urltoscript.com | 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`
2019-10-23 10:49:36 +00:00
George Doenlen
ee311b8e5c remove execution policy check 2019-10-22 22:26:33 -04:00
George Doenlen
f0de6c4e92 Add basic windows install script.
Adds a powershell install script for windows users that are at least
running powershell 5. It is almost a direct port of install.sh.
This would be used to automatically download the script much like
curl | bash, but with:

`Invoke-WebRequest https://urltoscript.com | 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`
2019-10-22 21:56:50 -04:00
Viacheslav Avramenko
1c4c8764ed feat: Added exercise for struct update syntax 2019-10-21 14:50:59 +02:00
bors
e6161a6f58 Auto merge of #217 - timthelion:timthelion-readme-run, r=fmoko
Tense in README

Don't see why run should be past tense.  At least in my native General American dialect it shouldn't be.
2019-09-25 14:09:52 +00:00
Timothy Hobbs
8c0fe59c90 Tense in README
Don't see why run should be past tense.  At least in my native General American dialect it shouldn't be.
2019-09-07 16:17:45 +00:00
komaeda
17690b3add chore(ci): Add GitHub Actions CI file 2019-08-21 13:23:38 +02:00
bors
f9987c8bed Auto merge of #212 - sosnowski:fix/add-dyn-trait, r=komaeda
fix(errorsn.rs) Update the deprecated syntax by adding dyn to trait o…

fix(errorsn.rs) Update the deprecated syntax by adding dyn to trait objects.

closes #211

Related issue: https://github.com/rust-lang/rustlings/issues/211
2019-08-21 11:01:11 +00:00
Damian S
8109cbad97 fix(errorsn.rs) Update the deprecated syntax by adding dyn to trait objectscloses #211 2019-08-21 11:44:42 +01:00
bors
c5bb32253b Auto merge of #209 - Dylnuge:slice-assert, r=komaeda
fix(primitive_types4): Fail on a slice covering the wrong area

I noticed this issue and it seems like a similar one was raised/fixed in #160 this way. This is my first contribution to this repo (or any Rust project) so let me know if I messed up or need to fix anything!

---
This commit converts primitive_types4 to a test and asserts that the
slice given is equal to the expected slice.

The intent of the primitive_types4 exercise appears to be to ensure the
user understands inclusive and exclusive bounds as well as slice syntax.
`rustlings` commands using `compile` do not verify that a specific
println is reached and, in the case of `watch` and `verify` (but not
`run`), they do not output the `println`s at all.

This fix is semantically similar to #198. It does not take a stance on
the correct way to handle this for all exercises; see #127. There are
likely other exercises whose intent are masked by this issue.
2019-08-18 08:24:44 +00:00
Dylan Nugent
5b1e673cec fix(primitive_types4): Fail on a slice covering the wrong area
This commit converts primitive_types4 to a test and asserts that the
slice given is equal to the expected slice.

The intent of the primitive_types4 exercise appears to be to ensure the
user understands inclusive and exclusive bounds as well as slice syntax.
`rustlings` commands using `compile` do not verify that a specific
println is reached and, in the case of `watch` and `verify` (but not
`run`), they do not output the `println`s at all.

This fix is semantically similar to #198. It does not take a stance on
the correct way to handle this for all exercises; see #127. There are
likely other exercises whose intent are masked by this issue.
2019-08-17 17:16:19 -07:00
bors
2cd06826c0 Auto merge of #206 - ajaxm:ajaxm/rustup-update, r=komaeda
Suggest rustup update in readme

I'm pretty new to Rust. I tried installing rustlings for the first time and got this error:
```
$> cargo install --force --path .
error: `/Users/ajax/projects/rust/rustlings` is not a crate root; specify a crate to install from crates.io, or use --path or --git to specify an alternate source

Caused by:
  failed to parse manifest at `/Users/ajax/projects/rust/rustlings/Cargo.toml`

Caused by:
  editions are unstable

Caused by:
  feature `edition` is required

this Cargo does not support nightly features, but if you
switch to nightly channel you can add
`cargo-features = ["edition"]` to enable this feature
```

I'm not sure if the answer was to run `rustup update` but I noticed that I was running Rust 1.29.0, so updated to 1.36.0 and got it working. If there's a way to specify a minimum required version, pls let me know.

Lastly, the whitespace changes were automatic from my editor. What's the convention here for making such updates? Thanks!
2019-08-13 10:04:36 +00:00
marisa
4f0c5a8d49 1.4.1 2019-08-13 11:59:17 +02:00
bors
3011251da7 Auto merge of #208 - EnricoMiccoli:patch-1, r=komaeda
chore: Correct typo in hint text
2019-08-12 15:24:17 +00:00
Enrico Miccoli
76b4cb5c00 chore: Correct typo 2019-08-12 11:45:40 +02:00
bors
f83af3c25d Auto merge of #207 - nkanderson:fix_iterators2, r=komaeda
Fix iterators2

A couple of small changes to the `iterators2` exercise. @Jesse-Cameron, it looks like you contributed this exercise, so I wanted to check and see if these changes are in line with your intentions. Happy to adjust if they're not :)
2019-08-11 15:44:40 +00:00
Niklas Anderson
e3931718fb chore(iterators2): Add exercise instructions 2019-08-09 07:38:21 -07:00
Niklas Anderson
4cde86643e fix(iterators2): Remove syntax resulting in misleading error message
closes #199
2019-08-09 07:37:27 -07:00
Ajax Manohar
9ee3207280 docs: Suggest rustup update in readme 2019-08-03 10:49:37 -07:00
bors
e696a07190 Auto merge of #201 - zdzc:patch-1, r=komaeda
docs: Fix wrong title

fix #200
2019-07-27 19:07:22 +00:00
Andre Pratama
e0db987441 docs: Fix wrong title
fix #200
2019-07-27 22:14:48 +07:00
bors
1890b0019d Auto merge of #198 - nkanderson:160_options1-add-test, r=komaeda
fix(option1): Add test for prematurely passing exercise

Fixes the bug referenced in #160, but does not address the larger feature work referenced by the issue.
2019-07-27 10:32:47 +00:00
Niklas Anderson
a750e4a1a3 fix(option1): Add test for prematurely passing exercise
Fixes the bug referenced in #160, but does not address the larger feature work referenced by the issue.
2019-07-26 16:58:12 -07:00
bors
1c789dda08 Auto merge of #192 - petemcfarlane:patch-2, r=komaeda
fix(test1): Swap assertion parameter order

`Expected` should come before `actual`, other wise it leads to confusing compiler messages, e.g.
```
note: expected type `()`
         found type `{integer}`
```
There may be other tests that need updating, but this is as far as I am through the Rustlings course right now :)
2019-07-13 16:27:14 +00:00
Pete McFarlane
4086d463a9 fix(test1): Swap assertion parameter order
`Expected` should come before `actual`, other wise it leads to confusing compiler messages, e.g.
```
note: expected type `()`
         found type `{integer}`
```
2019-07-13 13:31:57 +01:00
marisa
b8368de6d5 1.4.0 2019-07-13 12:50:22 +02:00
bors
7dc90094d2 Auto merge of #191 - MrFroop:master, r=komaeda
Fix(watch): Check if changed exercise file exists before calling verify.

Prevent a panic if the file triggering the watch event is gone.
2019-07-12 08:16:35 +00:00
Fredrik Jambrén
ba85ca32c4 Check if changed exercise file exists before calling verify. 2019-07-11 23:54:18 +02:00
etisdew
70946b85e5 fix(readme): http to https
changing readme image (line 1) to https fixes markdown preview and improves fidelity
2019-07-08 16:58:14 +02:00
bors
1570c328c6 Auto merge of #186 - Jesse-Cameron:iterator-exercise2, r=komaeda
feat(iterators2): adds iterators2 exercise including config

Hi there!

I really enjoyed doing the rustlings exercises so I thought that I would try to add an exercise!

This one just covers a couple of basic iterator operations. Getting people used to the `map` and `collect` functions.

However, it does feel kinda similar to the next exercise. So I may also revisit some of the tests in iterators3 if we think that is necessary.
2019-07-04 11:35:40 +00:00
Jesse
9288fccf07 feat(iterators2): adds iterators2 exercise including config 2019-07-03 21:06:24 +10:00
bors
5e1d7c3076 Auto merge of #184 - Jesse-Cameron:master, r=komaeda
fix(test1): renamed function name to snake case

addressing a minor function naming convention, see: [RFC #430](https://doc.rust-lang.org/1.0.0/style/style/naming/README.html)

closes #180
2019-06-28 15:27:40 +00:00
Jesse
89d5186c0d fix(test1): renamed function name to snake case
closes #180
2019-06-29 01:00:10 +10:00
bors
aaad60d07e Auto merge of #172 - miller-time:fix-book-links, r=komaeda
chore: Fix a couple broken book links

While I was fixing these, I figured maybe it's good to just use a consistent URL for book links: https://doc.rust-lang.org/book/

Is there a plan for what to do with this old 1.4.0 example that doesn't exist in the current version of the book? Perhaps at least include a disclaimer when recommending that folks check it out?

34e31232df/exercises/threads/README.md (L1)
2019-06-23 10:31:50 +00:00
bors
5f16469807 Auto merge of #171 - miller-time:rustfmt-exercises, r=komaeda
chore: Clean up some formatting in exercises

I noticed some formatting that isn't consistent with the `rustfmt` style and tried my best to run it on the files in the exercises directory (which does fail for files that can't compile!), which just caught some minor whitespace things here and there.

Note: also can't just apply `rustfmt` blindly because of the blank lines that lead to the hint comments
2019-06-23 10:25:48 +00:00
bors
752bc27e2b Auto merge of #179 - briankung:fix_irrefutable_let_pattern_structs1, r=komaeda
Fixes the irrefutable let pattern warning in `structs1.rs`

PR https://github.com/rust-lang/rustlings/pull/163 accidentally introduced an error using some versions of the Rust compiler where the compiler would (rightly!) complain about an irrefutable let pattern. I have no idea why this did not occur in all versions of the compiler, but here is a way around it.
2019-06-20 15:02:20 +00:00
Brian Kung
cc6a14104d Fixes the irrefutable let pattern warning 2019-06-20 09:46:49 -05:00
Russell Cousineau
eb13c2b6af chore: Clean up some formatting in exercises 2019-06-11 07:14:43 -07:00
Russell Cousineau
63c133e4a3 chore: Fix a couple broken book links 2019-06-11 07:13:05 -07:00
bors
b8d59d699b Auto merge of #169 - miller-time:fix-install-script, r=komaeda
fix(installation): Fix rustlings installation check

fixes #147

I did some quick testing with the `-x` check:

```sh
if [ -x "$(notrustlings)" ]
then
    echo "notrustlings does not exist"
else
    echo "notrustlings appears to exist!"
    notrustlings
fi
```

which produced:

```
./test.sh: line 12: notrustlings: command not found
notrustlings appears to exist!
./test.sh: line 17: notrustlings: command not found
```

(consistent with comments in issue)

Using `if ! [ -x "$(command -v <command>)" ]` appears to be the standard way to perform this type of check.
2019-06-11 13:53:07 +00:00
bors
5586613eec Auto merge of #170 - miller-time:rename-iterator-exercise, r=komaeda
fix(iterators): Rename iterator3.rs

fixes #155
2019-06-11 12:53:58 +00:00
bors
ad8e6dc63b Auto merge of #176 - danwilhelm:dan-minor-text, r=komaeda
chore: Minor text updates

- Make the default rustlings executable text consistent with the README and install script by adding `--force`.

- Remove a missed highlighting character from Issue #133.
2019-06-11 09:38:18 +00:00
Dan Wilhelm
f72e0ca979 chore: Remove missed highlighting char from Issue #133 2019-06-10 20:24:18 -07:00
Dan Wilhelm
03cfe67500 chore: Make install instructions consistent 2019-06-10 20:20:22 -07:00
Russell Cousineau
7a252c4755 fix(installation): Fix rustlings installation check 2019-06-09 07:40:54 -07:00
liv
2089901739 docs: Move content from Readme to Contributing 2019-06-09 14:46:38 +02:00
liv
635e506c16 docs: Recommend rustlings watch as default 2019-06-09 14:44:16 +02:00
liv
75d8c7e3cc docs: Add CONTRIBUTING.md 2019-06-09 14:39:00 +02:00
Rohan Prinja
080d6cdd11 chore: Fix link to Arc<T> in the book 2019-06-09 13:45:53 +02:00
Russell Cousineau
433d2115bc fix(iterators): Rename iterator3.rs 2019-06-07 14:42:44 -07:00
liv
34e31232df feat(changelog): Use clog for changelogs 2019-06-05 13:14:51 +02:00
liv
7fca1d28af 1.3.0 2019-06-05 12:37:02 +02:00
bors
9c3d765403 Auto merge of #167 - rust-lang:fix/remove-highlighting, r=komaeda
Remove highlighting and syntect

Closes #166 and #122
2019-06-05 10:23:37 +00:00
liv
bb652ceb91 Commit Cargo.lock file 2019-06-05 12:22:41 +02:00
liv
62696f5819 Remove highlighting and syntect 2019-06-05 12:18:50 +02:00
bors
41170ce341 Auto merge of #164 - HanKruiger:master, r=komaeda
Fix broken link
2019-05-26 14:07:16 +00:00
bors
e2092a4ddd Auto merge of #165 - gushroom:fix-outdated-links, r=komaeda
fixed outdated links

The links had the 2018 book in them and they were outdated.
2019-05-26 13:58:24 +00:00
gushroom
fd1441d122 fixed outdated links 2019-05-26 14:57:56 +02:00
HanKruiger
e1422c6443 Fix broken link 2019-05-26 14:45:04 +02:00
bors
1f07fd4150 Auto merge of #163 - briankung:add_structs, r=komaeda
Adds a simple exercise for structures

Thanks for rustlings! Here's a small contribution in return.
2019-05-25 13:40:15 +00:00
Brian Kung
9b92aa08ae Adds a simple exercise for structures 2019-05-25 06:39:58 -05:00
bors
8bf8cbbd61 Auto merge of #162 - c-rustacean:rustfmt-and-ws-fixes, r=komaeda
errorsn.rs: Separate also the hints from each other to avoid accidental viewing
2019-05-23 11:01:15 +00:00
Eddy Petrisor
f507844102 errorsn.rs: Separate also the hints from each other to avoid accidental viewing
Signed-off-by: Eddy Petrisor <eddy.petrisor@gmail.com>
2019-05-23 12:21:42 +03:00
bors
fffbb60ed9 Auto merge of #161 - c-rustacean:rustfmt-and-ws-fixes, r=komaeda
Rustfmt and ws fixes
2019-05-22 12:29:20 +00:00
Eddy Petrisor
9aec4abc4d rustfmt the exercises
Signed-off-by: Eddy Petrisor <eddy.petrisor@gmail.com>
2019-05-22 14:50:40 +03:00
Eddy Petrisor
a53b3f199f iterator3.rs: whitespace fixes
Signed-off-by: Eddy Petrisor <eddy.petrisor@gmail.com>
2019-05-22 14:50:40 +03:00
Eddy Petrisor
d6d696b66a errorsn.rs: Separate hints from code, so hints are not accidentally seen
Signed-off-by: Eddy Petrisor <eddy.petrisor@gmail.com>
2019-05-22 14:50:39 +03:00
Eddy Petrisor
ca6bf966dd Cargo fmt the rustlings application code
Signed-off-by: Eddy Petrisor <eddy.petrisor@gmail.com>
2019-05-22 14:50:23 +03:00
liv
5a9f8860ca Add not passing integration test (#154)
Add not passing integration test
2019-05-22 10:53:46 +02:00
liv
5423bc66a9 Update errors1.rs - Add Result type signature as it is difficult for new comers to understand Generics and Error all at once. (#157)
Update errors1.rs - Add Result type signature as it is difficult for new comers to understand Generics and Error all at once.
2019-05-22 10:53:18 +02:00
Julien Bisconti
187d2ad226 Update errors1.rs
Add Result type signature as it is difficult for new comers to understand Generics and Error all at once
2019-05-12 14:54:37 +02:00
Denys Smirnov
7cf0d5d15e Add not passing integration test 2019-05-09 20:17:38 +03:00
liv
1f2ee8cb62 1.2.2 2019-05-07 12:32:50 +02:00
liv
35c3d0b3fc Revert --nocapture flag
This closes #149 and #152
2019-05-07 12:31:02 +02:00
liv
0279294972 1.2.1 2019-04-22 19:12:30 +08:00
liv
7eddee6f7a add a slightly more helpful error message 2019-04-22 18:43:39 +08:00
liv
f2c48cfac5 fix the --nocapture functionality 2019-04-22 18:42:32 +08:00
liv
6ae0a00211 1.2.0 2019-04-22 13:09:28 +08:00
liv
bfcf38c8bc damn it 2019-04-22 07:05:46 +02:00
liv
9e328da641 use -- --nocapture when testing 2019-04-22 05:49:23 +02:00
bors
e336d04c79 Auto merge of #144 - yvan-sraka:patch-0, r=komaeda
Add errors to exercises that compile without user changes

Hi !

I played a bit with rustlings, and I felt that some exercises were incorrect because they passed the tests without me needing to edit the files!

This gave me the feeling that the exercise was skiped! Especially when I use `rustlings watch`, it is easy to miss an exercise because the compilation error that is displayed is the one of the next exercise ...

It is easy to identify "broken" exercises with:

```bash
% find exercises -name "*.rs" | xargs -n 1 rustlings run
...
 Successfully ran exercises/move_semantics/move_semantics4.rs
 Successfully tested exercises/test2.rs
```

My suggestion is to make sure that these files trigger a compilation error by adding a simple syntax error (e.g. with `???` in the code that must change) so that our Rustacean can then play with it!
2019-04-22 01:50:48 +00:00
Yvan Sraka
a71bc62c29 Add errors to exercises that compile without user changes 2019-04-22 00:09:30 +02:00
liv
4b0b7093e5 1.1.1 2019-04-14 18:29:32 +02:00
bors
8387de64d3 Auto merge of #143 - cjpearce:fix-exercise-path-matching, r=komaeda
Canonicalize paths to fix path matching

This PR should fix #126. The main solution to the issue was using `canonicalize()` on the paths we create for the exercises from `info.toml` and any user-specified paths, so that path `ends_with` matching will work correctly.

As adding calls to the canonicalize function everywhere requires unwrapping, I also decided to extract a struct representing an exercise and use serde to deserialize the paths from the `info.toml` file up front. I also tried to move the path handling out into the `exercise.rs` file and down into `main.rs` so that it doesn't create as much clutter. There was already a lot of unwrapping and path handling in the other files and I felt like it was getting a bit too repetitive.

If the approach is going too far (too many changes etc.) I'm happy to try to produce a smaller PR that fixes the bug without any refactoring.
2019-04-13 16:32:02 +00:00
Chris Pearce
77de6e5d6a Clean up test includes for File and Path 2019-04-12 23:14:15 +01:00
Chris Pearce
8c867a001a Remove unwrap on canonicalize result 2019-04-12 22:24:13 +01:00
Chris Pearce
d01a71f7de Extract exercise struct to encapsulate path logic 2019-04-12 08:58:25 +01:00
bors
04d1d4c00e Auto merge of #142 - diodfr:patch-1, r=komaeda
Fix links by deleting book version
2019-04-08 20:05:34 +00:00
Diod FR
d7e58ee1af Fix links by deleting book version 2019-04-08 22:02:04 +02:00
bors
ffb165ce26 Auto merge of #140 - cjpearce:fix/test-race-condition, r=komaeda
Fix intermittent test failure caused by race condition

First public pull request 😬

There's an intermittent integration test failure when you use multiple test threads (at least for me on a mac). I narrowed it down to two tests each spawning a process using `Command` which then try to compile the same file at the same time. If the timing doesn't work out, they both try to compile, and then one process runs `clean` before the other can run the executable - causing a panic.

![Screenshot 2019-04-07 at 19 54 55](https://user-images.githubusercontent.com/3453268/55688324-20520980-596f-11e9-8474-5215d61a4387.png)

You can prevent it from happening by running with a single thread (`cargo test -- --test-threads=1`), because the `Command` blocks. That's not a particularly good solution though because it's not something you can configure in `Cargo.toml`.

I considered making the affected tests just run serially, but it occurred to me that this could also happen if someone accidentally runs rustlings in watch mode in two terminals without realising it. I wound't consider this that unlikely given it's a tool for learning.

I fixed it by ensuring that the executables made from separate processes don't conflict by appending a process id to the output executable name. I also extracted the commands into a single file next to `clean` so that we don't have to repeat the generated file name everywhere and risk missing something.
2019-04-07 22:37:34 +00:00
Chris Pearce
65cb09eb2e Update ci test command to allow multithreaded tests 2019-04-07 21:23:02 +01:00
bors
78552ebd7a Auto merge of #141 - cjpearce:fix/run-panics-on-compile-fail, r=komaeda
Stop run from panicking when compile fails

Currently if you use the `rustlings run` command and your program fails to compile, rustlings will panic while trying to exit.

First I've added a couple of integration tests to cover this case, which also meant moving a few tests so that the new fixtures didn't cause `verify_all_success` to fail.

Then I noticed that the existing integration tests that test for failure pass even when rustlings panics, preventing the new tests from failing. I've updated the integration tests to distinguish between when rustlings has failed in the way that we want (exit code 1) rather than a panic (exit code 101).

Finally I fixed the actual panic, which was just caused by unwrapping when rustlings should probably be exiting cleanly.
2019-04-07 20:11:22 +00:00
Chris Pearce
0c7bd12372 Fix test failing due to panic 2019-04-07 20:13:04 +01:00
Chris Pearce
3d11d7685b Modify integration tests to fail on panic 2019-04-07 20:13:04 +01:00
Chris Pearce
592ae6b4d2 Add process id to temp file name 2019-04-07 17:28:51 +01:00
Chris Pearce
4fa79ee02f Extract command builders into util 2019-04-07 17:26:01 +01:00
bors
fbd0ccbd5b Auto merge of #134 - rust-lang:fix/windows-paths, r=komaeda
fix watch command path execution

@hades32 @guttume could you test whether this works on windows by checking out the branch locally and running `cargo run watch`?
2019-04-03 09:37:37 +00:00
komaeda
8c008a0e7d Merge pull request #137 from mgeier/patch-1
Fix order of true/false in tests for executables
2019-03-28 12:11:35 +01:00
Matthias Geier
11fe19d08a Fix order of true/false in tests for executables
1b3469f236 has fixed the tests themselves, but now the original error shows itself.
2019-03-28 11:53:29 +01:00
liv
1b3469f236 make installation command checks more thorough 2019-03-28 10:51:54 +01:00
liv
022921168d fix watch command path execution 2019-03-27 10:58:56 +01:00
komaeda
c6765eb3eb Merge pull request #133 from zacanger/bug/permissions
Fix permissions on exercise files
2019-03-24 15:44:34 +01:00
zacanger
c5a374fbf2 Fix permissions on source files 2019-03-23 14:19:42 -06:00
lyn
f3ee70489f 1.1.0 2019-03-20 21:27:27 +01:00
lyn
6a27ba735c cargo fmt 2019-03-20 21:25:45 +01:00
komaeda
91dce31265 Merge pull request #131 from ColinPitrat/master
Verify that rust version is recent enough to install rustlings.
2019-03-20 21:22:04 +01:00
lyn
040ca18a64 add travis config 2019-03-20 21:08:08 +01:00
lyn
f43cb124f6 add tests 2019-03-20 21:05:45 +01:00
komaeda
11875aed6e adjust author name 2019-03-20 14:51:28 +01:00
Colin Pitrat
f07703eb7a Fix comment position 2019-03-20 11:21:15 +00:00
Colin Pitrat
fd4eda8bda Verify that rust version is recent enough to install rustlings.
I would have liked to write some tests for the vercomp function I
introduce, but there doesn't seem to be any CI setup yet?
2019-03-20 11:18:39 +00:00
komaeda
bf8d927ab2 Merge pull request #123 from kisom/master
Be nicer when rustlings isn't run from the right directory.
2019-03-17 22:28:03 +01:00
Kyle Isom
9fc4a83987 Be nicer when rustlings isn't run from the right directory.
Before, rustlings would panic if it wasn't in the right directory. It
took me a minute to figure out why, and this wasn't my first intro to
Rust. It would probably help new users if they saw a helpful message
instead of a stack trace.
2019-03-17 11:43:47 -07:00
komaeda
63280ed9e4 Merge pull request #119 from LesnyRumcajs/patch-1
Add standard library types to exercises suite
2019-03-17 13:27:48 +01:00
komaeda
25f9d61410 Merge pull request #124 from kisom/update-link
errors2.rs: update link to Rust book.
2019-03-17 13:19:57 +01:00
Kyle Isom
c1f4257a91 errors2.rs: update link to Rust book. 2019-03-16 19:22:06 -07:00
komaeda
8f9d7ce3d8 Merge pull request #120 from abagshaw/master
Start verification at most recently modified file
2019-03-16 12:54:09 +01:00
Andrew Bagshaw
3b5dfac44e Remove unnessecary whitespace 2019-03-15 16:01:45 -07:00
Andrew Bagshaw
a6a8b61b12 Change to \n 2019-03-15 12:47:06 -07:00
Andrew Bagshaw
6cd42bb821 Add clear break between verify executions 2019-03-13 14:08:28 -07:00
Andrew Bagshaw
4d7ce6e571 deduplicate 2019-03-13 13:53:24 -07:00
Andrew Bagshaw
3f114cc069 Start verification at most recently modified file 2019-03-13 13:50:54 -07:00
LesnyRumcajs
58ccd72aff Add standard library types to exercises suite 2019-03-13 15:29:02 +01:00
lyn
abf175111d clippy-ify 2019-03-11 15:09:20 +01:00
lyn
9144c816bf remove obsolete paragraph on --test flag 2019-03-06 22:01:45 +01:00
lyn
999601d828 1.0.1 2019-03-06 21:58:10 +01:00
lyn
10d4d61d19 rework contribution guide for the new toml file 2019-03-06 21:55:48 +01:00
lyn
70e59cca3c standardize exercise running via an external toml file 2019-03-06 21:47:33 +01:00
komaeda
7d6e2812fb Merge pull request #117 from shaunbennett/master
Watch for file creation events in watch mode
2019-03-06 20:28:29 +01:00
lyn
05e8f02d0a edit readme to use the install script 2019-03-06 20:25:27 +01:00
lyn
9a14d72f08 add a basic install script 2019-03-06 20:16:31 +01:00
Shaun Bennett
04d0f78a2c Fix file watching for vim swap files 2019-03-06 18:38:55 +00:00
96 changed files with 3309 additions and 1726 deletions

4
.clog.toml Normal file
View File

@@ -0,0 +1,4 @@
[clog]
repository = "https://github.com/rust-lang/rustlings"
changelog = "CHANGELOG.md"

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

1
.gitignore vendored
View File

@@ -1,5 +1,4 @@
*.swp
target/
**/*.rs.bk
Cargo.lock
.DS_Store

11
.travis.yml Normal file
View File

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

160
CHANGELOG.md Normal file
View File

@@ -0,0 +1,160 @@
<a name="2.0.0"></a>
## 2.0.0 (2019-11-12)
#### Bug Fixes
* **default:** Clarify the installation procedure ([c371b853](https://github.com/rust-lang/rustlings/commit/c371b853afa08947ddeebec0edd074b171eeaae0))
* **info:** Fix trailing newlines for hints ([795b6e34](https://github.com/rust-lang/rustlings/commit/795b6e348094a898e9227a14f6232f7bb94c8d31))
* **run:** make `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
#### Breaking Changes
* Refactor hint system ([9bdb0a12](https://github.com/rust-lang/rustlings/commit/9bdb0a12e45a8e9f9f6a4bd4a9c172c5376c7f60))
* improve `watch` execution mode ([2cdd6129](https://github.com/rust-lang/rustlings/commit/2cdd61294f0d9a53775ee24ad76435bec8a21e60))
* Index exercises by name ([627cdc07](https://github.com/rust-lang/rustlings/commit/627cdc07d07dfe6a740e885e0ddf6900e7ec336b))
* **run:** makes `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
#### Features
* **cli:** check for rustc before doing anything ([36a033b8](https://github.com/rust-lang/rustlings/commit/36a033b87a6549c1e5639c908bf7381c84f4f425))
* **hint:** Add test for hint ([ce9fa6eb](https://github.com/rust-lang/rustlings/commit/ce9fa6ebbfdc3e7585d488d9409797285708316f))
<a name="1.5.1"></a>
### 1.5.1 (2019-11-11)
#### Bug Fixes
* **errors3:** Update hint ([dcfb427b](https://github.com/rust-lang/rustlings/commit/dcfb427b09585f0193f0a294443fdf99f11c64cb), closes [#185](https://github.com/rust-lang/rustlings/issues/185))
* **if1:** Remove `return` reference ([ad03d180](https://github.com/rust-lang/rustlings/commit/ad03d180c9311c0093e56a3531eec1a9a70cdb45))
* **strings:** Move Strings before Structs ([6dcecb38](https://github.com/rust-lang/rustlings/commit/6dcecb38a4435593beb87c8e12d6314143631482), closes [#204](https://github.com/rust-lang/rustlings/issues/204))
* **structs1:** Remove misleading comment ([f72e5a8f](https://github.com/rust-lang/rustlings/commit/f72e5a8f05568dde04eaeac10b9a69872f21cb37))
* **threads:** Move Threads behind SLT ([fbe91a67](https://github.com/rust-lang/rustlings/commit/fbe91a67a482bfe64cbcdd58d06ba830a0f39da3), closes [#205](https://github.com/rust-lang/rustlings/issues/205))
* **watch:** clear screen before each `verify()` ([3aff590](https://github.com/rust-lang/rustlings/commit/3aff59085586c24196a547c2693adbdcf4432648))
<a name="1.5.0"></a>
## 1.5.0 (2019-11-09)
#### Bug Fixes
* **test1:** Rewrite logic ([79a56942](https://github.com/rust-lang/rustlings/commit/79a569422c8309cfc9e4aed25bf4ab3b3859996b))
* **installation:** Fix rustlings installation check ([7a252c47](https://github.com/rust-lang/rustlings/commit/7a252c475551486efb52f949b8af55803b700bc6))
* **iterators:** Rename iterator3.rs ([433d2115](https://github.com/rust-lang/rustlings/commit/433d2115bc1c04b6d34a335a18c9a8f3e2672bc6))
* **iterators2:** Remove syntax resulting in misleading error message ([4cde8664](https://github.com/rust-lang/rustlings/commit/4cde86643e12db162a66e62f23b78962986046ac))
* **option1:**
* Fix arguments passed to assert! macro (#222) ([4c2cf6da](https://github.com/rust-lang/rustlings/commit/4c2cf6da755efe02725e05ecc3a303304c10a6da))
* Fix arguments passed to assert! macro ([ead4f7af](https://github.com/rust-lang/rustlings/commit/ead4f7af9e10e53418efdde5c359159347282afd))
* Add test for prematurely passing exercise ([a750e4a1](https://github.com/rust-lang/rustlings/commit/a750e4a1a3006227292bb17d57d78ce84da6bfc6))
* **primitive_types4:** Fail on a slice covering the wrong area ([5b1e673c](https://github.com/rust-lang/rustlings/commit/5b1e673cec1658afc4ebbbc800213847804facf5))
* **readme:** http to https ([70946b85](https://github.com/rust-lang/rustlings/commit/70946b85e536e80e70ed9505cb650ca0a3a1fbb5))
* **test1:**
* Swap assertion parameter order ([4086d463](https://github.com/rust-lang/rustlings/commit/4086d463a981e81d97781851d17db2ced290f446))
* renamed function name to snake case closes #180 ([89d5186c](https://github.com/rust-lang/rustlings/commit/89d5186c0dae8135ecabf90ee8bb35949bc2d29b))
#### Features
* Add enums exercises ([dc150321](https://github.com/rust-lang/rustlings/commit/dc15032112fc485226a573a18139e5ce928b1755))
* Added exercise for struct update syntax ([1c4c8764](https://github.com/rust-lang/rustlings/commit/1c4c8764ed118740cd4cee73272ddc6cceb9d959))
* **iterators2:** adds iterators2 exercise including config ([9288fccf](https://github.com/rust-lang/rustlings/commit/9288fccf07a2c5043b76d0fd6491e4cf72d76031))
<a name="1.4.1"></a>
### 1.4.1 (2019-08-13)
#### Bug Fixes
* **iterators2:** Remove syntax resulting in misleading error message ([4cde8664](https://github.com/rust-lang/rustlings/commit/4cde86643e12db162a66e62f23b78962986046ac))
* **option1:** Add test for prematurely passing exercise ([a750e4a1](https://github.com/rust-lang/rustlings/commit/a750e4a1a3006227292bb17d57d78ce84da6bfc6))
* **test1:** Swap assertion parameter order ([4086d463](https://github.com/rust-lang/rustlings/commit/4086d463a981e81d97781851d17db2ced290f446))
<a name="1.4.0"></a>
## 1.4.0 (2019-07-13)
#### Bug Fixes
* **installation:** Fix rustlings installation check ([7a252c47](https://github.com/rust-lang/rustlings/commit/7a252c475551486efb52f949b8af55803b700bc6))
* **iterators:** Rename iterator3.rs ([433d2115](https://github.com/rust-lang/rustlings/commit/433d2115bc1c04b6d34a335a18c9a8f3e2672bc6))
* **readme:** http to https ([70946b85](https://github.com/rust-lang/rustlings/commit/70946b85e536e80e70ed9505cb650ca0a3a1fbb5))
* **test1:** renamed function name to snake case ([89d5186c](https://github.com/rust-lang/rustlings/commit/89d5186c0dae8135ecabf90ee8bb35949bc2d29b))
* **cli:** Check if changed exercise file exists before calling verify ([ba85ca3](https://github.com/rust-lang/rustlings/commit/ba85ca32c4cfc61de46851ab89f9c58a28f33c88))
* **structs1:** Fix the irrefutable let pattern warning ([cc6a141](https://github.com/rust-lang/rustlings/commit/cc6a14104d7c034eadc98297eaaa972d09c50b1f))
#### Features
* **changelog:** Use clog for changelogs ([34e31232](https://github.com/rust-lang/rustlings/commit/34e31232dfddde284a341c9609b33cd27d9d5724))
* **iterators2:** adds iterators2 exercise including config ([9288fccf](https://github.com/rust-lang/rustlings/commit/9288fccf07a2c5043b76d0fd6491e4cf72d76031))
<a name="1.3.0"></a>
### 1.3.0 (2019-06-05)
#### Features
- Adds a simple exercise for structures (#163, @briankung)
#### Bug Fixes
- Add Result type signature as it is difficult for new comers to understand Generics and Error all at once. (#157, @veggiemonk)
- Rustfmt and whitespace fixes (#161, @eddyp)
- errorsn.rs: Separate also the hints from each other to avoid accidental viewing (#162, @eddyp)
- fixed outdated links (#165, @gushroom)
- Fix broken link (#164, @HanKruiger)
- Remove highlighting and syntect (#167, @komaeda)
<a name="1.2.2"></a>
### 1.2.2 (2019-05-07)
#### Bug Fixes
- Reverted `--nocapture` flag since it was causing tests to pass unconditionally
<a name="1.2.1"></a>
### 1.2.1 (2019-04-22)
#### Bug Fixes
- Fix the `--nocapture` feature (@komaeda)
- Provide a nicer error message for when you're in the wrong directory
<a name="1.2.0"></a>
### 1.2.0 (2019-04-22)
#### Features
- Add errors to exercises that compile without user changes (@yvan-sraka)
- Use --nocapture when testing, enabling `println!` when running (@komaeda)
<a name="1.1.1"></a>
### 1.1.1 (2019-04-14)
#### Bug fixes
- Fix permissions on exercise files (@zacanger, #133)
- Make installation checks more thorough (@komaeda, 1b3469f236bc6979c27f6e1a04e4138a88e55de3)
- Fix order of true/false in tests for executables (@mgeier, #137)
- Stop run from panicking when compile fails (@cjpearce, #141)
- Fix intermittent test failure caused by race condition (@cjpearce, #140)
- Fix links by deleting book version (@diodfr, #142)
- Canonicalize paths to fix path matching (@cjpearce, #143)
<a name="1.1.0"></a>
### 1.1.0 (2019-03-20)
- errors2.rs: update link to Rust book (#124)
- Start verification at most recently modified file (#120)
- Watch for file creation events in watch mode (#117)
- Add standard library types to exercises suite (#119)
- Give a warning when Rustlings isn't run from the right directory (#123)
- Verify that rust version is recent enough to install Rustlings (#131)
<a name="1.0.1"></a>
### 1.0.1 (2019-03-06)
- Adds a way to install Rustlings in one command (`curl -L https://git.io/rustlings | bash`)
- Makes `rustlings watch` react to create file events (@shaunbennett, #117)
- Reworks the exercise management to use an external TOML file instead of just listing them in the code
<a name="1.0.0"></a>
### 1.0.0 (2019-03-06)
Initial release.

131
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,131 @@
## Contributing to Rustlings
First off, thanks for taking the time to contribute!! ❤️
### Quick Reference
I want to...
_add an exercise! ➡️ [read this](#addex) and then [open a Pull Request](#prs)_
_update an outdated exercise! ➡️ [open a Pull Request](#prs)_
_report a bug! ➡️ [open an Issue](#issues)_
_fix a bug! ➡️ [open a Pull Request](#prs)_
_implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull Request](#issues)_
<a name="#src"></a>
### Working on the source code
`rustlings` is basically a glorified `rustc` wrapper. Therefore the source code
isn't really that complicated since the bulk of the work is done by `rustc`.
`src/main.rs` contains a simple `clap` CLI that loads from `src/verify.rs` and `src/run.rs`.
<a name="addex"></a>
### Adding an exercise
First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
Next you want to make sure it runs when using `rustlings`. All exercises are stored in `info.toml`, under the `exercises` array. They're ordered by the order they're ran when using `rustlings verify`.
You want to make sure where in the file you add your exercise. If you're not sure, add it at the bottom and ask in your pull request. To add an exercise, edit the file like this:
```diff
...
+ [[exercises]]
+ name = "yourTopicN"
+ path = "exercises/yourTopic/yourTopicN.rs"
+ mode = "compile"
+ hint = """
+ Some kind of useful hint for your exercise."""
...
```
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`.
That's all! Feel free to put up a pull request.
<a name="issues"></a>
### Issues
You can open an issue [here](https://github.com/rust-lang/rustlings/issues/new).
If you're reporting a bug, please include the output of the following commands:
- `rustc --version`
- `rustlings --version`
- `ls -la`
- Your OS name and version
<a name="prs"></a>
### Pull Requests
Opening a pull request is as easy as forking the repository and committing your
changes. There's a couple of things to watch out for:
#### Write correct commit messages
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
specification, because it makes it easier to generate changelogs automatically.
This means that you have to format your commit messages in a specific way. Say
you're working on adding a new exercise called `foobar1.rs`. You could write
the following commit message:
```
feat: Add foobar1.rs exercise
```
If you're just fixing a bug, please use the `fix` type:
```
fix(verify): Make sure verify doesn't self-destruct
```
The scope within the brackets is optional, but should be any of these:
- `installation` (for the installation script)
- `cli` (for general CLI changes)
- `verify` (for the verification source file)
- `watch` (for the watch functionality source)
- `run` (for the run functionality source)
- `EXERCISENAME` (if you're changing a specific exercise, or set of exercises,
substitute them here)
When the commit also happens to close an existing issue, link it in the message
body:
```
fix: Update foobar
closes #101029908
```
If you're doing simple changes, like updating a book link, use `chore`:
```
chore: Update exercise1.rs book link
```
If you're updating documentation, use `docs`:
```
docs: Add more information to Readme
```
If, and only if, you're absolutely sure you want to make a breaking change
(please discuss this beforehand!), add an exclamation mark to the type and
explain the breaking change in the message body:
```
fix!: Completely change verification
BREAKING CHANGE: This has to be done because lorem ipsum dolor
```
#### Pull Request Workflow
Once you open a Pull Request, it may be reviewed or labeled (or both) until
the maintainers accept your change. Then, [bors](https://github.com/bors) will
run the test suite with your changes and if it's successful, automatically
merge it in!

961
Cargo.lock generated Normal file
View File

@@ -0,0 +1,961 @@
# 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"
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 = "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)",
]
[[package]]
name = "assert_cmd"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"escargot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
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)",
]
[[package]]
name = "autocfg"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"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"
source = "registry+https://github.com/rust-lang/crates.io-index"
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)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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"
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 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)",
"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 = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encode_unicode"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "escargot"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "filetime"
version = "0.2.5"
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)",
"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"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fsevent-sys"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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"
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)",
"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)",
]
[[package]]
name = "inotify"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inotify-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "iovec"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"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"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazycell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lock_api"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.6"
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)",
]
[[package]]
name = "memchr"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mio"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio-extras"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.2.1"
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)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.33"
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)",
]
[[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"
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)",
"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)",
]
[[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 = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parking_lot"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.5.0"
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)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
]
[[package]]
name = "predicates"
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]]
name = "predicates-core"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "predicates-tree"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
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)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.3 (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.6.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-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"
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 = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustlings"
version = "2.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)",
"glob 0.3.0 (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)",
"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)",
]
[[package]]
name = "ryu"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scopeguard"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termios"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "treeline"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
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-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.7"
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)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
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)",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[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"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
"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 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 glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
"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 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"
"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
"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 normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2e0a1a39eab95caf4f5556da9289b9e68f0aafac901b2ce80daaf020d3b733a8"
"checksum notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3572d71f13ea8ed41867accd971fd564aa75934cf7a1fae03ddb8c74a8a49943"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"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"
"checksum predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "53e09015b0d3f5a0ec2d4428f7559bb7b3fff341b4e159fedd1d57fac8b939ff"
"checksum predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
"checksum predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"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"
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
"checksum treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"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-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"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"

View File

@@ -1,12 +1,23 @@
[package]
name = "rustlings"
version = "1.0.0"
authors = ["Lynn <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
version = "2.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"
syntect = "3.0.2"
notify = "4.0.0"
toml = "0.4.10"
regex = "1.1.6"
serde = {version = "1.0.10", features = ["derive"]}
[[bin]]
name = "rustlings"
path = "src/main.rs"
[dev-dependencies]
assert_cmd = "0.11.0"
predicates = "1.0.1"
glob = "0.3.0"

105
README.md
View File

@@ -1,4 +1,4 @@
![crab pet](http://i.imgur.com/LbZJgmm.gif)
![crab pet](https://i.imgur.com/LbZJgmm.gif)
# rustlings 🦀❤️
@@ -13,60 +13,83 @@ Alternatively, for a first-time Rust learner, there's several other resources:
## Getting Started
To use `rustlings` you need to have [Rust](https://www.rust-lang.org/) installed on your computer. To install Rust, go to [rustup.rs](https://rustup.rs/).
Once Rust is installed, clone the `rustlings` repository and enter the resulting directory:
```bash
git clone https://github.com/rust-lang/rustlings.git
cd rustlings
```
_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`._
Once in the directory you can install `rustlings` on your machine and run the introduction:
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
## MacOS/Linux
Just run:
```bash
cargo install --path .
rustlings
curl -L https://git.io/rustlings | bash
# Or if you want it to be installed to a different path:
curl -L https://git.io/rustlings | bash -s mypath/
```
If you choose to not install the `rustlings` command, just replace `rustlings` with `cargo run` in the rest of this text.
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
## Windows
You can run:
```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
```
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
## Manually
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/2.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
cargo install --force --path .
```
If there are installation errors, ensure that your toolchain is up to date. For the latest, run:
```bash
rustup update
```
Then, same as above, run `rustlings` to get started.
## Doing exercises
The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/<topic>`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start.
The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/<topic>`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start.
The task is simple. Most exercises contain an error that keep it from compiling, and it's up to you to fix it! Some exercises are also ran as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute:
```bash
rustlings verify
```
This will try to verify the completion of every exercise in a predetermined order (what we think is best for newcomers). If you don't want to rerun `verify` every time you change a file, you can run:
The task is simple. Most exercises contain an error that keep it from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute:
```bash
rustlings watch
```
This will do the same as verify, but won't quit after running and instead automatically rerun as soon as you change a file in the `exercises/` directory.
This will try to verify the completion of every exercise in a predetermined order (what we think is best for newcomers). It will also rerun automatically every time you change a file in the `exercises/` directory. If you want to only run it once, you can use:
```bash
rustlings verify
```
This will do the same as watch, but it'll quit after running.
In case you want to go by your own order, or want to only verify a single exercise, you can run:
```bash
rustlings run exercises/path/to/exercise.rs
rustlings run myExercise1
```
Or if it's a `#[test]`:
In case you get stuck, you can run the following command to get a hint for your
exercise:
```bash
rustlings run --test exercises/path/to/exercise_with_test.rs
``` bash
rustlings hint myExercise1
```
In case you get stuck, there is usually a hint at the bottom of each exercise.
## 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`.
@@ -91,29 +114,7 @@ If you are interested in improving or adding new ones, please feel free to contr
## Contributing
### Adding an exercise
First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
Then, you'll want to make sure it gets verified when you run `rustlings verify`. Open `src/verify.rs` and
put your exercise somewhere in there:
```diff
...
compile_only("exercises/functions5.rs")?;
+ compile_only("exercises/yourTopic/yourTopicN.rs")?;
compile_only("exercises/test1.rs")?;
...
```
That's all!
### Working on the source code
`rustlings` is basically a glorified `rustc` wrapper. Therefore the source code
isn't really that complicated since the bulk of the work is done by `rustc`.
`src/main.rs` contains a simple `clap` CLI that loads from `src/verify.rs` and `src/run.rs`.
See [CONTRIBUTING.md](./CONTRIBUTING.md).
## Credits

View File

@@ -1,20 +1,19 @@
Thanks for installing `rustlings`!
Thanks for installing Rustlings!
## Is this your first time?
Is this your first time?
Let's make sure you're up to speed:
- You have Rust installed, preferably via `rustup`
- 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:
```sh
cargo install --path .
```
cargo install --force --path .
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 verify` in order to get the first exercise.
To get started, run `rustlings watch` in order to get the first exercise.
Make sure to have your editor open!

View File

@@ -0,0 +1,7 @@
### 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.
#### Book Sections
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)

16
exercises/enums/enums1.rs Normal file
View File

@@ -0,0 +1,16 @@
// enums1.rs
// Make me compile! Execute `rustlings hint enums1` for hints!
// I AM NOT DONE
#[derive(Debug)]
enum Message {
// TODO: define a few types of messages as used below
}
fn main() {
println!("{:?}", Message::Quit);
println!("{:?}", Message::Echo);
println!("{:?}", Message::Move);
println!("{:?}", Message::ChangeColor);
}

28
exercises/enums/enums2.rs Normal file
View File

@@ -0,0 +1,28 @@
// enums2.rs
// Make me compile! Execute `rustlings hint enums2` for hints!
// I AM NOT DONE
#[derive(Debug)]
enum Message {
// TODO: define the different variants used below
}
impl Message {
fn call(&self) {
println!("{:?}", &self);
}
}
fn main() {
let messages = [
Message::Move{ x: 10, y: 30 },
Message::Echo(String::from("hello world")),
Message::ChangeColor(200, 255, 255),
Message::Quit
];
for message in &messages {
message.call();
}
}

65
exercises/enums/enums3.rs Normal file
View File

@@ -0,0 +1,65 @@
// enums3.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
enum Message {
// TODO: implement the message variant types based on their usage below
}
struct Point {
x: u8,
y: u8
}
struct State {
color: (u8, u8, u8),
position: Point,
quit: bool
}
impl State {
fn change_color(&mut self, color: (u8, u8, u8)) {
self.color = color;
}
fn quit(&mut self) {
self.quit = true;
}
fn echo(&self, s: String) {
println!("{}", s);
}
fn move_position(&mut self, p: Point) {
self.position = p;
}
fn process(&mut self, message: Message) {
// TODO: create a match expression to process the different message variants
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_message_call() {
let mut state = State{
quit: false,
position: Point{ x: 0, y: 0 },
color: (0, 0, 0)
};
state.process(Message::ChangeColor(255, 0, 255));
state.process(Message::Echo(String::from("hello world")));
state.process(Message::Move{ x: 10, y: 15 });
state.process(Message::Quit);
assert_eq!(state.color, (255, 0, 255));
assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15);
assert_eq!(state.quit, true);
}
}

View File

@@ -1,5 +1,5 @@
For this exercise check out the sections:
- [Error Handling](https://doc.rust-lang.org/book/2018-edition/ch09-02-recoverable-errors-with-result.html)
- [Generics](https://doc.rust-lang.org/book/2018-edition/ch10-01-syntax.html)
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
of the Rust Book.
of the Rust Book.

37
exercises/error_handling/errors1.rs Executable file → Normal file
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 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)`.

33
exercises/error_handling/errors2.rs Executable file → Normal file
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;
@@ -32,10 +34,7 @@ mod tests {
#[test]
fn item_quantity_is_a_valid_number() {
assert_eq!(
total_cost("34"),
Ok(171)
);
assert_eq!(total_cost("34"), Ok(171));
}
#[test]
@@ -46,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/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
// and give it a try!

41
exercises/error_handling/errors3.rs Executable file → Normal file
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.

48
exercises/error_handling/errorsn.rs Executable file → Normal file
View File

@@ -13,14 +13,16 @@
// 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;
use std::io;
// PositiveNonzeroInteger is a struct defined below the tests.
fn read_and_validate(b: &mut io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
let mut line = String::new();
b.read_line(&mut line);
let num: i64 = line.trim().parse();
@@ -29,7 +31,7 @@ fn read_and_validate(b: &mut io::BufRead) -> Result<PositiveNonzeroInteger, ???>
}
// This is a test helper function that turns a &str into a BufReader.
fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<error::Error>> {
fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn error::Error>> {
let mut b = io::BufReader::new(s.as_bytes());
read_and_validate(&mut b)
}
@@ -65,7 +67,7 @@ fn test_ioerror() {
assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string());
}
#[derive(PartialEq,Debug)]
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
impl PositiveNonzeroInteger {
@@ -83,11 +85,14 @@ impl PositiveNonzeroInteger {
#[test]
fn test_positive_nonzero_integer_creation() {
assert!(PositiveNonzeroInteger::new(10).is_ok());
assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10));
assert_eq!(
Err(CreationError::Negative),
PositiveNonzeroInteger::new(-10)
);
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
}
#[derive(PartialEq,Debug)]
#[derive(PartialEq, Debug)]
enum CreationError {
Negative,
Zero,
@@ -95,7 +100,7 @@ enum CreationError {
impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str((self as &error::Error).description())
f.write_str((self as &dyn error::Error).description())
}
}
@@ -107,32 +112,3 @@ impl error::Error for CreationError {
}
}
}
// 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<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/stable/book/second-edition/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

48
exercises/error_handling/option1.rs Executable file → Normal file
View File

@@ -2,44 +2,30 @@
// 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 :)
// Execute `rustlings hint option1` for hints :)
fn main() {
// I AM NOT DONE
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);
println!(
"The second-to-last item in the list is {:?}",
second_to_last
);
true
}
#[cfg(test)]
mod tests {
use super::*;
// 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!
#[test]
fn should_not_panic() {
assert!(pop_too_much());
}
}

32
exercises/error_handling/result1.rs Executable file → Normal file
View File

@@ -1,10 +1,12 @@
// result1.rs
// Make this test pass! Scroll down for hints :)
// Make this test pass! Execute `rustlings hint result1` for hints :)
#[derive(PartialEq,Debug)]
// I AM NOT DONE
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
#[derive(PartialEq,Debug)]
#[derive(PartialEq, Debug)]
enum CreationError {
Negative,
Zero,
@@ -19,25 +21,9 @@ impl PositiveNonzeroInteger {
#[test]
fn test_creation() {
assert!(PositiveNonzeroInteger::new(10).is_ok());
assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10));
assert_eq!(
Err(CreationError::Negative),
PositiveNonzeroInteger::new(-10)
);
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

@@ -4,4 +4,4 @@ Here, you'll learn how to write functions and how Rust's compiler can trace thin
#### Book Sections
- [How Functions Work](https://doc.rust-lang.org/stable/book/ch03-03-how-functions-work.html)
- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)

42
exercises/functions/functions1.rs Executable file → Normal file
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?

34
exercises/functions/functions2.rs Executable file → Normal file
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`.

34
exercises/functions/functions3.rs Executable file → Normal file
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.

26
exercises/functions/functions4.rs Executable file → Normal file
View File

@@ -1,9 +1,11 @@
// 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.
// I AM NOT DONE
fn main() {
let original_price = 51;
println!("Your sale price is {}", sale_price(original_price));
@@ -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!

40
exercises/functions/functions5.rs Executable file → Normal file
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

@@ -4,4 +4,4 @@
#### Book Sections
- [Control Flow - if expressions](https://doc.rust-lang.org/stable/book/ch03-05-control-flow.html#if-expressions)
- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions)

40
exercises/if/if1.rs Executable file → Normal file
View File

@@ -1,12 +1,13 @@
// if1.rs
pub fn bigger(a: i32, b:i32) -> i32 {
// 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.

View File

@@ -6,5 +6,5 @@ modules, instead we'll show you how to use and create them.
#### Book Sections
- [Macros](https://doc.rust-lang.org/stable/book/ch19-06-macros.html)
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)

56
exercises/macros/macros1.rs Executable file → Normal file
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`.

65
exercises/macros/macros2.rs Executable file → Normal file
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.

66
exercises/macros/macros3.rs Executable file → Normal file
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.

65
exercises/macros/macros4.rs Executable file → Normal file
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

@@ -4,4 +4,4 @@ In this section we'll give you an introduction to Rust's module system.
#### Book Sections
- [The Module System](https://doc.rust-lang.org/stable/book/ch07-02-modules-and-use-to-control-scope-and-privacy.html)
- [The Module System](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html)

35
exercises/modules/modules1.rs Executable file → Normal file
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.

36
exercises/modules/modules2.rs Executable file → Normal file
View File

@@ -1,7 +1,9 @@
// modules2.rs
// Make me compile! Scroll down for hints :)
// Make me compile! Execute `rustlings hint modules2` for hints :)
mod delicious_snacks {
// I AM NOT DONE
mod delicious_snacks {
use self::fruits::PEAR as fruit;
use self::veggies::CUCUMBER as veggie;
@@ -17,29 +19,9 @@ mod delicious_snacks {
}
fn main() {
println!("favorite snacks: {} and {}",
delicious_snacks::fruit,
delicious_snacks::veggie);
println!(
"favorite snacks: {} and {}",
delicious_snacks::fruit,
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

@@ -6,5 +6,5 @@ These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust
For this section, the book links are especially important.
- [Ownership](https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html)
- [Reference and borrowing](https://doc.rust-lang.org/stable/book/ch04-02-references-and-borrowing.html)
- [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
- [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)

23
exercises/move_semantics/move_semantics1.rs Executable file → Normal file
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();
@@ -11,7 +13,6 @@ fn main() {
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
@@ -23,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.

34
exercises/move_semantics/move_semantics2.rs Executable file → Normal file
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 10!
// Execute `rustlings hint move_semantics2` for hints :)
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
@@ -12,7 +15,6 @@ fn main() {
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
@@ -24,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!`

26
exercises/move_semantics/move_semantics3.rs Executable file → Normal file
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();
@@ -13,7 +15,6 @@ fn main() {
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
@@ -23,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 :)

30
exercises/move_semantics/move_semantics4.rs Executable file → Normal file
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();
@@ -13,10 +16,10 @@ fn main() {
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
// `fill_vec()` no longer take `vec: Vec<i32>` as argument
fn fill_vec() -> Vec<i32> {
let mut vec = vec;
vec.push(22);
@@ -25,24 +28,3 @@ fn fill_vec(vec: Vec<i32>) -> 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

@@ -6,3 +6,4 @@ compiler. In this section, we'll go through the most important ones.
#### Book Sections
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html)
- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html)

2
exercises/primitive_types/primitive_types1.rs Executable file → Normal file
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`)

2
exercises/primitive_types/primitive_types2.rs Executable file → Normal file
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`)

38
exercises/primitive_types/primitive_types3.rs Executable file → Normal file
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`?

45
exercises/primitive_types/primitive_types4.rs Executable file → Normal file
View File

@@ -1,49 +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!!
// returns true. Execute `rustlings hint primitive_types4` for hints!!
// I AM NOT DONE
#[test]
fn main() {
let a = [1, 2, 3, 4, 5];
let nice_slice = ???
if nice_slice == [2, 3, 4] {
println!("Nice slice!");
} else {
println!("Not quite what I was expecting... I see: {:?}", 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

39
exercises/primitive_types/primitive_types5.rs Executable file → Normal file
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/stable/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!!

40
exercises/primitive_types/primitive_types6.rs Executable file → Normal file
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/stable/book/ch03-02-data-types.html#the-tuple-type
// Now you have another tool in your toolbox!

View File

@@ -1,5 +1,5 @@
For the Arc exercise check out the chapter [Shared-State Concurrency](https://doc.rust-lang.org/book/2018-edition/ch16-03-shared-state.html) of the Rust Book.
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/2018-edition/ch13-02-iterators.html) of the Rust Book and the [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.htmlj).
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!

33
exercises/standard_library_types/arc1.rs Executable file → Normal file
View File

@@ -2,7 +2,9 @@
// 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`
// somewhere. Try not to create any copies of the `numbers` Vec!
// Scroll down for hints :)
// Execute `rustlings help arc1` for hints :)
// I AM NOT DONE
use std::sync::Arc;
use std::thread;
@@ -13,8 +15,7 @@ fn main() {
let mut joinhandles = Vec::new();
for offset in 0..8 {
joinhandles.push(
thread::spawn(move || {
joinhandles.push(thread::spawn(move || {
let mut i = offset;
let mut sum = 0;
while i < child_numbers.len() {
@@ -28,29 +29,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,48 @@
// 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 if you execute `rustlings hint iterators2`!
// I AM NOT DONE
pub fn capitalize_first(input: &str) -> String {
let mut c = input.chars();
match c.next() {
None => String::new(),
Some(first) => first.collect::<String>() + c.as_str(),
}
}
#[cfg(test)]
mod tests {
use super::*;
// Step 1.
// Tests that verify your `capitalize_first` function implementation
#[test]
fn test_success() {
assert_eq!(capitalize_first("hello"), "Hello");
}
#[test]
fn test_empty() {
assert_eq!(capitalize_first(""), "");
}
// Step 2.
#[test]
fn test_iterate_string_vec() {
let words = vec!["hello", "world"];
let capitalized_words: Vec<String> = // TODO
assert_eq!(capitalized_words, ["Hello", "World"]);
}
#[test]
fn test_iterate_into_string() {
let words = vec!["hello", " ", "world"];
let capitalized_words = // TODO
assert_eq!(capitalized_words, "Hello World");
}
}

View File

@@ -1,13 +1,14 @@
// iterator3.rs
// iterators3.rs
// This is a bigger exercise than most of the others! You can do it!
// Here is your mission, should you choose to accept it:
// 1. Complete the divide function to get the first four tests to pass
// 2. 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),
@@ -23,8 +24,7 @@ pub struct NotDivisibleError {
// This function should calculate `a` divided by `b` if `a` is
// evenly divisible by b.
// Otherwise, it should return a suitable error.
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
}
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {}
#[cfg(test)]
mod tests {
@@ -40,7 +40,7 @@ mod tests {
fn test_not_divisible() {
assert_eq!(
divide(81, 6),
Err(DivisionError::NotDivisible(NotDivisibleError{
Err(DivisionError::NotDivisible(NotDivisibleError {
dividend: 81,
divisor: 6
}))
@@ -76,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.

33
exercises/standard_library_types/iterators4.rs Executable file → Normal file
View File

@@ -1,5 +1,7 @@
// iterators4.rs
// I AM NOT DONE
pub fn factorial(num: u64) -> u64 {
// Complete this function to return factorial of num
// Do not use:
@@ -9,7 +11,7 @@ pub fn factorial(num: u64) -> u64 {
// - additional variables
// For the most fun 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

@@ -6,4 +6,4 @@ to identify and create them, as well as use them.
#### Book Sections
- [Strings](https://doc.rust-lang.org/stable/book/ch08-02-strings.html)
- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)

40
exercises/strings/strings1.rs Executable file → Normal file
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.

34
exercises/strings/strings2.rs Executable file → Normal file
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

@@ -0,0 +1,7 @@
### Structs
Rust has three struct types: a classic c struct, a tuple struct, and a unit struct.
#### Book Sections
- [Structures](https://doc.rust-lang.org/rust-by-example/custom_types/structs.html)

View File

@@ -0,0 +1,45 @@
// structs1.rs
// Address all the TODOs to make the tests pass!
// I AM NOT DONE
struct ColorClassicStruct {
// TODO: Something goes here
}
struct ColorTupleStruct(/* TODO: Something goes here */);
#[derive(Debug)]
struct UnitStruct;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classic_c_structs() {
// TODO: Instantiate a classic c struct!
// let green =
assert_eq!(green.name, "green");
assert_eq!(green.hex, "#00FF00");
}
#[test]
fn tuple_structs() {
// TODO: Instantiate a tuple struct!
// let green =
assert_eq!(green.0, "green");
assert_eq!(green.1, "#00FF00");
}
#[test]
fn unit_structs() {
// TODO: Instantiate a unit struct!
// let unit_struct =
let message = format!("{:?}s are fun!", unit_struct);
assert_eq!(message, "UnitStructs are fun!");
}
}

View File

@@ -0,0 +1,47 @@
// structs2.rs
// Address all the TODOs to make the tests pass!
// No hints, just do it!
// I AM NOT DONE
#[derive(Debug)]
struct Order {
name: String,
year: u32,
made_by_phone: bool,
made_by_mobile: bool,
made_by_email: bool,
item_number: u32,
count: u32,
}
fn create_order_template() -> Order {
Order {
name: String::from("Bob"),
year: 2019,
made_by_phone: false,
made_by_mobile: false,
made_by_email: true,
item_number: 123,
count: 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn your_order() {
let order_template = create_order_template();
// TODO: Create your own order using the update syntax and template above!
// let your_order =
assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year);
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
assert_eq!(your_order.made_by_email, order_template.made_by_email);
assert_eq!(your_order.item_number, order_template.item_number);
assert_eq!(your_order.count, 1);
}
}

View File

@@ -7,15 +7,17 @@
// 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 ..... {
// Don't modify this function!
#[test]
fn verify_test() {
let price1 = calculateprice(55);
let price2 = calculateprice(40);
let price1 = calculate_apple_price(35);
let price2 = calculate_apple_price(65);
assert_eq!(price1, 55);
assert_eq!(price2, 80);
assert_eq!(70, price1);
assert_eq!(65, price2);
}

38
exercises/test2.rs Executable file → Normal file
View File

@@ -1,22 +1,30 @@
// test2.rs
// This is a test for the following sections:
// - Tests
// - Strings
// 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 that we get the result
// we expect to get when we call `times_two` with a negative number.
// No hints, you can do this :)
// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. 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!
pub fn times_two(num: i32) -> i32 {
num * 2
// I AM NOT DONE
fn string_slice(arg: &str) {
println!("{}", arg);
}
fn string(arg: String) {
println!("{}", arg);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_twice_of_positive_numbers() {
assert_eq!(4, 4);
}
fn main() {
("blue");
("red".to_string());
(String::from("hi"));
("rust is fun!".to_owned());
("nice weather".into());
(format!("Interpolation {}", "Station"));
(&String::from("abc")[0..1]);
(" hello there ".trim());
("Happy Monday!".to_string().replace("Mon", "Tues"));
("mY sHiFt KeY iS sTiCkY".to_lowercase());
}

43
exercises/test3.rs Executable file → Normal file
View File

@@ -1,24 +1,29 @@
// strings3.rs
// test3.rs
// This is a test for the following sections:
// - Strings
// - Tests
// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. 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!
// 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 that we get the result
// we expect to get when we call `times_two` with a negative number.
// No hints, you can do this :)
fn string_slice(arg: &str) { println!("{}", arg); }
fn string(arg: String) { println!("{}", arg); }
// I AM NOT DONE
fn main() {
("blue");
("red".to_string());
(String::from("hi"));
("rust is fun!".to_owned());
("nice weather".into());
(format!("Interpolation {}", "Station"));
(&String::from("abc")[0..1]);
(" hello there ".trim());
("Happy Monday!".to_string().replace("Mon", "Tues"));
("mY sHiFt KeY iS sTiCkY".to_lowercase());
pub fn times_two(num: i32) -> i32 {
num * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn returns_twice_of_positive_numbers() {
assert_eq!(times_two(4), ???);
}
#[test]
fn returns_twice_of_negative_numbers() {
// TODO write an assert for `times_two(-4)`
}
}

View File

@@ -5,6 +5,8 @@
// Write a macro that passes the test! No hints this time, you can do it!
// I AM NOT DONE
fn main() {
if my_macro!("world!") != "Hello world!" {
panic!("Oh no! Wrong output!");

View File

@@ -4,4 +4,4 @@ Going out of order from the book to cover tests -- many of the following exercis
#### Book Sections
- [Writing Tests](https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html)
- [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html)

38
exercises/tests/tests1.rs Executable file → Normal file
View File

@@ -4,7 +4,9 @@
// rustlings run --test exercises/tests/tests1.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 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 :)

37
exercises/tests/tests2.rs Executable file → Normal file
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!

30
exercises/tests/tests3.rs Executable file → Normal file
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 +1 @@
For this exercise check out the [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the chapter [Concurrency](https://doc.rust-lang.org/book/2018-edition/ch16-01-threads.html) of the Rust Book.
For this exercise check out the [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the chapter [Concurrency](https://doc.rust-lang.org/book/ch16-01-threads.html) of the Rust Book.

74
exercises/threads/threads1.rs Executable file → Normal file
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 19 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/stable/book/second-edition/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

@@ -4,4 +4,4 @@ Here you'll learn about simple variables.
#### Book Sections
- [Variables and Mutability](https://doc.rust-lang.org/stable/book/ch03-01-variables-and-mutability.html)
- [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html)

44
exercises/variables/variables1.rs Executable file → Normal file
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, you 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.

40
exercises/variables/variables2.rs Executable file → Normal file
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?

38
exercises/variables/variables3.rs Executable file → Normal file
View File

@@ -1,5 +1,7 @@
// 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;
@@ -7,37 +9,3 @@ fn main() {
x = 5;
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.

42
exercises/variables/variables4.rs Executable file → Normal file
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!

612
info.toml Normal file
View File

@@ -0,0 +1,612 @@
# VARIABLES
[[exercises]]
name = "variables1"
path = "exercises/variables/variables1.rs"
mode = "compile"
hint = """
Hint: The declaration on line 5 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 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?"""
[[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 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!"""
# 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."""
# 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 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!"""
[[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]]
name = "test1"
path = "exercises/test1.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 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"""
[[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 = "No hints this time ;)"
[[exercises]]
name = "structs2"
path = "exercises/structs/structs2.rs"
mode = "test"
hint = "No hints this time ;)"
# 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
6, though, that will coerce the `String` into a string slice."""
# TEST 2
[[exercises]]
name = "test2"
path = "exercises/test2.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]]
name = "test3"
path = "exercises/test3.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]]
name = "test4"
path = "exercises/test4.rs"
mode = "compile"
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 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."""
[[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 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!`"""
[[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]]
name = "option1"
path = "exercises/error_handling/option1.rs"
mode = "test"
hint = """
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!"""
[[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 :)"""
# STANDARD LIBRARY 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 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."""
# 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 :)"""

85
install.ps1 Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env pwsh
#Requires -Version 5
param($path = "$pwd/rustlings")
Write-Host "Let's get you set up with Rustlings!"
Write-Host "Checking requirements..."
if (Get-Command git -ErrorAction SilentlyContinue) {
Write-Host "SUCCESS: Git is installed"
} else {
Write-Host "WARNING: Git does not seem to be installed."
Write-Host "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
}
if (Get-Command rustc -ErrorAction SilentlyContinue) {
Write-Host "SUCCESS: Rust is installed"
} else {
Write-Host "WARNING: Rust does not seem to be installed."
Write-Host "Please download Rust using https://rustup.rs!"
exit 1
}
if (Get-Command cargo -ErrorAction SilentlyContinue) {
Write-Host "SUCCESS: Cargo is installed"
} else {
Write-Host "WARNING: Cargo does not seem to be installed."
Write-Host "Please download Rust and Cargo using https://rustup.rs!"
exit 1
}
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
function vercomp($v1, $v2) {
if ($v1 -eq $v2) {
return 0
}
$v1 = $v1.Replace(".", "0")
$v2 = $v2.Replace(".", "0")
if ($v1.Length -gt $v2.Length) {
$v2 = $v2.PadRight($v1.Length, "0")
} else {
$v1 = $v1.PadRight($v2.Length, "0")
}
if ($v1 -gt $v2) {
return 1
} else {
return 2
}
}
$rustVersion = $(rustc --version).Split(" ")[1]
$minRustVersion = "1.31"
if ((vercomp $rustVersion $minRustVersion) -eq 2) {
Write-Host "WARNING: Rust version is too old: $rustVersion - needs at least $minRustVersion"
Write-Host "Please update Rust with 'rustup update'"
exit 1
} else {
Write-Host "SUCCESS: Rust is up to date"
}
Write-Host "Cloning Rustlings at $path"
git clone -q https://github.com/rust-lang/rustlings $path
if (!($LASTEXITCODE -eq 0)) {
exit 1
}
# UseBasicParsing is deprecated, pwsh 6 or above will automatically use it,
# but anyone running pwsh 5 will have to pass the argument.
$version = Invoke-WebRequest -UseBasicParsing https://api.github.com/repos/rust-lang/rustlings/releases/latest `
| ConvertFrom-Json | Select-Object -ExpandProperty tag_name
Write-Host "Checking out version $version..."
Set-Location $path
git checkout -q tags/$version
Write-Host "Installing the 'rustlings' executable..."
cargo install --force --path .
if (!(Get-Command rustlings -ErrorAction SilentlyContinue)) {
Write-Host "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
}
Write-Host "All done! Run 'rustlings' to get started."

102
install.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env bash
echo "Let's get you set up with Rustlings!"
echo "Checking requirements..."
if [ -x "$(command -v git)" ]
then
echo "SUCCESS: Git is installed"
else
echo "WARNING: Git does not seem to be installed."
echo "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
fi
if [ -x "$(command -v rustc)" ]
then
echo "SUCCESS: Rust is installed"
else
echo "WARNING: Rust does not seem to be installed."
echo "Please download Rust using https://rustup.rs!"
exit 1
fi
if [ -x "$(command -v cargo)" ]
then
echo "SUCCESS: Cargo is installed"
else
echo "WARNING: Cargo does not seem to be installed."
echo "Please download Rust and Cargo using https://rustup.rs!"
exit 1
fi
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
function vercomp() {
if [[ $1 == $2 ]]
then
return 0
fi
v1=( ${1//./ } )
v2=( ${2//./ } )
len1=${#v1[@]}
len2=${#v2[@]}
max_len=$len1
if [[ $max_len -lt $len2 ]]
then
max_len=$len2
fi
for i in `seq 0 $max_len`
do
# Fill empty fields with zeros in v1
if [ -z "${v1[$i]}" ]
then
v1[$i]=0
fi
# And in v2
if [ -z "${v2[$i]}" ]
then
v2[$i]=0
fi
if [ ${v1[$i]} -gt ${v2[$i]} ]
then
return 1
fi
if [ ${v1[$i]} -lt ${v2[$i]} ]
then
return 2
fi
done
return 0
}
RustVersion=$(rustc --version | cut -d " " -f 2)
MinRustVersion=1.31
vercomp $RustVersion $MinRustVersion
if [ $? -eq 2 ]
then
echo "WARNING: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "Please update Rust with 'rustup update'"
exit 1
else
echo "SUCCESS: Rust is up to date"
fi
Path=${1:-rustlings/}
echo "Cloning Rustlings at $Path..."
git clone -q https://github.com/rust-lang/rustlings $Path
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
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!"
fi
echo "All done! Run 'rustlings' to get started."

194
src/exercise.rs Normal file
View File

@@ -0,0 +1,194 @@
use regex::Regex;
use serde::Deserialize;
use std::fmt::{self, Display, Formatter};
use std::fs::{remove_file, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::{self, Command, Output};
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;
fn temp_file() -> String {
format!("./temp_{}", process::id())
}
#[derive(Deserialize, Copy, Clone)]
#[serde(rename_all = "lowercase")]
pub enum Mode {
Compile,
Test,
}
#[derive(Deserialize)]
pub struct ExerciseList {
pub exercises: Vec<Exercise>,
}
#[derive(Deserialize)]
pub struct Exercise {
pub name: String,
pub path: PathBuf,
pub mode: Mode,
pub hint: String,
}
#[derive(PartialEq, Debug)]
pub enum State {
Done,
Pending(Vec<ContextLine>),
}
#[derive(PartialEq, Debug)]
pub struct ContextLine {
pub line: String,
pub number: usize,
pub important: bool,
}
impl Exercise {
pub fn compile(&self) -> Output {
match self.mode {
Mode::Compile => Command::new("rustc")
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output(),
Mode::Test => Command::new("rustc")
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
.args(RUSTC_COLOR_ARGS)
.output(),
}
.expect("Failed to run 'compile' command.")
}
pub fn run(&self) -> Output {
Command::new(&temp_file())
.output()
.expect("Failed to run 'run' command")
}
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)
}
}
impl Display for Exercise {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.path.to_str().unwrap())
}
}
#[cfg(test)]
mod test {
use super::*;
use std::path::Path;
#[test]
fn test_clean() {
File::create(&temp_file()).unwrap();
let exercise = Exercise {
name: String::from("example"),
path: PathBuf::from("example.rs"),
mode: Mode::Test,
hint: String::from(""),
};
exercise.clean();
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);
}
}

View File

@@ -1,18 +1,18 @@
use crate::exercise::{Exercise, ExerciseList};
use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::io::BufRead;
use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::process::{Command, Stdio};
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;
mod exercise;
mod run;
mod util;
mod verify;
fn main() {
@@ -26,16 +26,18 @@ fn main() {
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();
let ss = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
if None == matches.subcommand_name() {
println!("");
println!();
println!(r#" welcome to... "#);
println!(r#" _ _ _ "#);
println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
@@ -43,50 +45,96 @@ fn main() {
println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
println!(r#" |___/ "#);
println!("");
println!();
}
if let Some(matches) = matches.subcommand_matches("run") {
run(matches.clone());
if !Path::new("info.toml").exists() {
println!(
"{} must be run from the rustlings directory",
std::env::current_exe().unwrap().to_str().unwrap()
);
println!("Try `cd rustlings/`!");
std::process::exit(1);
}
if let Some(_) = matches.subcommand_matches("verify") {
match verify() {
Ok(_) => {}
Err(_) => 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);
}
if let Some(_) = matches.subcommand_matches("watch") {
watch().unwrap();
let toml_str = &fs::read_to_string("info.toml").unwrap();
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
if let Some(ref matches) = matches.subcommand_matches("run") {
let name = matches.value_of("name").unwrap();
let matching_exercise = |e: &&Exercise| name == e.name;
let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
println!("No exercise found for your given name!");
std::process::exit(1)
});
run(&exercise).unwrap_or_else(|_| std::process::exit(1));
}
if let None = matches.subcommand_name() {
let mut highlighter =
HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
for maybe_line in highlighter.reader.lines() {
let line = maybe_line.unwrap();
let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
}
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);
}
println!("\x1b[0m");
if matches.subcommand_matches("verify").is_some() {
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
}
if matches.subcommand_matches("watch").is_some() {
watch(&exercises).unwrap();
}
if matches.subcommand_name().is_none() {
let text = fs::read_to_string("default_out.txt").unwrap();
println!("{}", text);
}
}
fn watch() -> notify::Result<()> {
fn watch(exercises: &[Exercise]) -> 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("./exercises", RecursiveMode::Recursive)?;
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
let _ignored = verify();
clear_screen();
let _ignored = verify(exercises.iter());
loop {
match rx.recv() {
Ok(event) => match event {
DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
let _ignored = verify();
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
if b.extension() == Some(OsStr::new("rs")) && b.exists() {
let filepath = b.as_path().canonicalize().unwrap();
let pending_exercises = exercises
.iter()
.skip_while(|e| !filepath.ends_with(&e.path));
clear_screen();
let _ignored = verify(pending_exercises);
}
}
_ => {}
},
@@ -94,3 +142,13 @@ fn watch() -> 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,55 +1,52 @@
use crate::util::clean;
use crate::exercise::{Exercise, Mode};
use crate::verify::test;
use console::{style, Emoji};
use indicatif::ProgressBar;
use std::process::Command;
pub fn run(matches: clap::ArgMatches) {
if let Some(filename) = matches.value_of("file") {
if matches.is_present("test") {
match test(filename) {
Ok(_) => (),
Err(_) => (),
}
std::process::exit(0);
}
let bar = ProgressBar::new_spinner();
bar.set_message(format!("Compiling {}...", filename).as_str());
bar.enable_steady_tick(100);
let compilecmd = Command::new("rustc")
.args(&[filename, "-o", "temp", "--color", "always"])
.output()
.expect("fail");
bar.set_message(format!("Running {}...", filename).as_str());
if compilecmd.status.success() {
let runcmd = Command::new("./temp").output().expect("fail");
bar.finish_and_clear();
pub fn run(exercise: &Exercise) -> Result<(), ()> {
match exercise.mode {
Mode::Test => test(exercise)?,
Mode::Compile => compile_and_run(exercise)?,
}
Ok(())
}
if runcmd.status.success() {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
let formatstr = format!("{} Successfully ran {}", Emoji("", ""), filename);
println!("{}", style(formatstr).green());
clean();
} else {
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
pub 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 formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), filename);
println!("{}", style(formatstr).red());
clean();
}
let compilecmd = exercise.compile();
progress_bar.set_message(format!("Running {}...", exercise).as_str());
if compilecmd.status.success() {
let runcmd = exercise.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();
Ok(())
} else {
bar.finish_and_clear();
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
filename
);
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
clean();
exercise.clean();
Err(())
}
} else {
panic!("Please supply a filename!");
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(())
}
}

View File

@@ -1,5 +0,0 @@
use std::fs::remove_file;
pub fn clean() {
let _ignored = remove_file("temp");
}

View File

@@ -1,124 +1,129 @@
use crate::util::clean;
use crate::exercise::{Exercise, Mode, State};
use console::{style, Emoji};
use indicatif::ProgressBar;
use std::process::Command;
pub fn verify() -> Result<(), ()> {
compile_only("exercises/variables/variables1.rs")?;
compile_only("exercises/variables/variables2.rs")?;
compile_only("exercises/variables/variables3.rs")?;
compile_only("exercises/variables/variables4.rs")?;
test("exercises/if/if1.rs")?;
compile_only("exercises/functions/functions1.rs")?;
compile_only("exercises/functions/functions2.rs")?;
compile_only("exercises/functions/functions3.rs")?;
compile_only("exercises/functions/functions4.rs")?;
compile_only("exercises/functions/functions5.rs")?;
test("exercises/test1.rs")?;
compile_only("exercises/primitive_types/primitive_types1.rs")?;
compile_only("exercises/primitive_types/primitive_types2.rs")?;
compile_only("exercises/primitive_types/primitive_types3.rs")?;
compile_only("exercises/primitive_types/primitive_types4.rs")?;
compile_only("exercises/primitive_types/primitive_types5.rs")?;
compile_only("exercises/primitive_types/primitive_types6.rs")?;
test("exercises/tests/tests1.rs")?;
test("exercises/tests/tests2.rs")?;
test("exercises/tests/tests3.rs")?;
test("exercises/test2.rs")?;
compile_only("exercises/strings/strings1.rs")?;
compile_only("exercises/strings/strings2.rs")?;
compile_only("exercises/test3.rs")?;
compile_only("exercises/modules/modules1.rs")?;
compile_only("exercises/modules/modules2.rs")?;
compile_only("exercises/macros/macros1.rs")?;
compile_only("exercises/macros/macros2.rs")?;
compile_only("exercises/macros/macros3.rs")?;
compile_only("exercises/macros/macros4.rs")?;
compile_only("exercises/test4.rs")?;
compile_only("exercises/move_semantics/move_semantics1.rs")?;
compile_only("exercises/move_semantics/move_semantics2.rs")?;
compile_only("exercises/move_semantics/move_semantics3.rs")?;
compile_only("exercises/move_semantics/move_semantics4.rs")?;
test("exercises/error_handling/errors1.rs")?;
test("exercises/error_handling/errors2.rs")?;
test("exercises/error_handling/errors3.rs")?;
test("exercises/error_handling/errorsn.rs")?;
compile_only("exercises/error_handling/option1.rs")?;
test("exercises/error_handling/result1.rs")?;
compile_only("exercises/threads/threads1.rs")?;
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), ()> {
for exercise in start_at {
let is_done = match exercise.mode {
Mode::Test => compile_and_test_interactively(&exercise)?,
Mode::Compile => compile_only(&exercise)?,
};
if !is_done {
return Err(());
}
}
Ok(())
}
fn compile_only(filename: &str) -> Result<(), ()> {
let bar = ProgressBar::new_spinner();
bar.set_message(format!("Compiling {}...", filename).as_str());
bar.enable_steady_tick(100);
let compilecmd = Command::new("rustc")
.args(&[filename, "-o", "temp", "--color", "always"])
.output()
.expect("fail");
bar.finish_and_clear();
if compilecmd.status.success() {
let formatstr = format!(
"{} Successfully compiled {}!",
Emoji("", ""),
filename
);
pub fn test(exercise: &Exercise) -> Result<(), ()> {
compile_and_test(exercise, true)?;
Ok(())
}
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();
progress_bar.finish_and_clear();
if compile_output.status.success() {
let formatstr = format!("{} Successfully compiled {}!", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
clean();
Ok(())
exercise.clean();
Ok(prompt_for_completion(&exercise))
} else {
let formatstr = format!(
"{} Compilation of {} failed! Compiler error message:\n",
Emoji("⚠️ ", "!"),
filename
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
clean();
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
exercise.clean();
Err(())
}
}
pub fn test(filename: &str) -> Result<(), ()> {
let bar = ProgressBar::new_spinner();
bar.set_message(format!("Testing {}...", filename).as_str());
bar.enable_steady_tick(100);
let testcmd = Command::new("rustc")
.args(&["--test", filename, "-o", "temp", "--color", "always"])
.output()
.expect("fail");
if testcmd.status.success() {
bar.set_message(format!("Running {}...", filename).as_str());
let runcmd = Command::new("./temp").output().expect("fail");
bar.finish_and_clear();
fn compile_and_test_interactively(exercise: &Exercise) -> Result<bool, ()> {
compile_and_test(exercise, false)
}
fn compile_and_test(exercise: &Exercise, skip_prompt: 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 runcmd = exercise.run();
progress_bar.finish_and_clear();
if runcmd.status.success() {
let formatstr = format!("{} Successfully tested {}!", Emoji("", ""), filename);
let formatstr = format!("{} Successfully tested {}!", Emoji("", ""), exercise);
println!("{}", style(formatstr).green());
clean();
Ok(())
exercise.clean();
Ok(skip_prompt || prompt_for_completion(exercise))
} else {
let formatstr = format!(
"{} Testing of {} failed! Please try again. Here's the output:",
Emoji("⚠️ ", "!"),
filename
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
clean();
exercise.clean();
Err(())
}
} else {
bar.finish_and_clear();
progress_bar.finish_and_clear();
let formatstr = format!(
"{} Compiling of {} failed! Please try again. Here's the output:",
Emoji("⚠️ ", "!"),
filename
exercise
);
println!("{}", style(formatstr).red());
println!("{}", String::from_utf8_lossy(&testcmd.stderr));
clean();
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
exercise.clean();
Err(())
}
}
fn prompt_for_completion(exercise: &Exercise) -> 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!",
};
println!("");
println!("🎉 🎉 {} 🎉 🎉", success_msg);
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 {
format!("{}", context_line.line)
};
println!(
"{:>2} {} {}",
style(context_line.number).blue().bold(),
style("|").blue(),
formatted_line
);
}
false
}

View File

@@ -0,0 +1,3 @@
fn main() {
let
}

View File

@@ -0,0 +1,2 @@
fn main() {
}

View File

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

View File

@@ -0,0 +1,4 @@
#[test]
fn passing() {
asset!(true);
}

View File

@@ -0,0 +1,4 @@
#[test]
fn not_passing() {
assert!(false);
}

View File

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

View File

@@ -0,0 +1,11 @@
[[exercises]]
name = "pending_exercise"
path = "pending_exercise.rs"
mode = "compile"
hint = """"""
[[exercises]]
name = "pending_test_exercise"
path = "pending_test_exercise.rs"
mode = "test"
hint = """"""

View File

@@ -0,0 +1,7 @@
// fake_exercise
// I AM NOT DONE
fn main() {
}

View File

@@ -0,0 +1,4 @@
// I AM NOT DONE
#[test]
fn it_works() {}

View File

@@ -0,0 +1,2 @@
fn main() {
}

View File

@@ -0,0 +1,11 @@
[[exercises]]
name = "compSuccess"
path = "compSuccess.rs"
mode = "compile"
hint = """"""
[[exercises]]
name = "testSuccess"
path = "testSuccess.rs"
mode = "test"
hint = """"""

View File

@@ -0,0 +1,4 @@
#[test]
fn passing() {
assert!(true);
}

161
tests/integration_tests.rs Normal file
View File

@@ -0,0 +1,161 @@
use assert_cmd::prelude::*;
use glob::glob;
use predicates::boolean::PredicateBooleanExt;
use std::fs::File;
use std::io::Read;
use std::process::Command;
#[test]
fn runs_without_arguments() {
let mut cmd = Command::cargo_bin("rustlings").unwrap();
cmd.assert().success();
}
#[test]
fn fails_when_in_wrong_dir() {
Command::cargo_bin("rustlings")
.unwrap()
.current_dir("tests/")
.assert()
.code(1);
}
#[test]
fn verify_all_success() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("v")
.current_dir("tests/fixture/success")
.assert()
.success();
}
#[test]
fn verify_all_failure() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("v")
.current_dir("tests/fixture/failure")
.assert()
.code(1);
}
#[test]
fn run_single_compile_success() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "compSuccess"])
.current_dir("tests/fixture/success/")
.assert()
.success();
}
#[test]
fn run_single_compile_failure() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "compFailure"])
.current_dir("tests/fixture/failure/")
.assert()
.code(1);
}
#[test]
fn run_single_test_success() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "testSuccess"])
.current_dir("tests/fixture/success/")
.assert()
.success();
}
#[test]
fn run_single_test_failure() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "testFailure"])
.current_dir("tests/fixture/failure/")
.assert()
.code(1);
}
#[test]
fn run_single_test_not_passed() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "testNotPassed.rs"])
.current_dir("tests/fixture/failure/")
.assert()
.code(1);
}
#[test]
fn run_single_test_no_filename() {
Command::cargo_bin("rustlings")
.unwrap()
.arg("r")
.current_dir("tests/fixture/")
.assert()
.code(1);
}
#[test]
fn run_single_test_no_exercise() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "compNoExercise.rs"])
.current_dir("tests/fixture/failure")
.assert()
.code(1);
}
#[test]
fn get_hint_for_single_test() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["h", "testFailure"])
.current_dir("tests/fixture/failure")
.assert()
.code(0)
.stdout("Hello!\n");
}
#[test]
fn all_exercises_require_confirmation() {
for exercise in glob("exercises/**/*.rs").unwrap() {
let path = exercise.unwrap();
let source = {
let mut file = File::open(&path).unwrap();
let mut s = String::new();
file.read_to_string(&mut s).unwrap();
s
};
source.matches("// I AM NOT DONE").next().expect(&format!(
"There should be an `I AM NOT DONE` annotation in {:?}",
path
));
}
}
#[test]
fn run_compile_exercise_does_not_prompt() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "pending_exercise"])
.current_dir("tests/fixture/state")
.assert()
.code(0)
.stdout(predicates::str::contains("I AM NOT DONE").not());
}
#[test]
fn run_test_exercise_does_not_prompt() {
Command::cargo_bin("rustlings")
.unwrap()
.args(&["r", "pending_test_exercise"])
.current_dir("tests/fixture/state")
.assert()
.code(0)
.stdout(predicates::str::contains("I AM NOT DONE").not());
}